wave-agent-sdk 0.4.0 → 0.6.1

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 (190) hide show
  1. package/dist/agent.d.ts +42 -11
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +114 -115
  4. package/dist/constants/prompts.d.ts +18 -14
  5. package/dist/constants/prompts.d.ts.map +1 -1
  6. package/dist/constants/prompts.js +130 -54
  7. package/dist/constants/tools.d.ts +6 -3
  8. package/dist/constants/tools.d.ts.map +1 -1
  9. package/dist/constants/tools.js +6 -3
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -0
  13. package/dist/managers/MemoryRuleManager.js +1 -1
  14. package/dist/managers/aiManager.d.ts +5 -3
  15. package/dist/managers/aiManager.d.ts.map +1 -1
  16. package/dist/managers/aiManager.js +57 -20
  17. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  18. package/dist/managers/backgroundBashManager.js +1 -0
  19. package/dist/managers/backgroundTaskManager.d.ts +35 -0
  20. package/dist/managers/backgroundTaskManager.d.ts.map +1 -0
  21. package/dist/managers/backgroundTaskManager.js +255 -0
  22. package/dist/managers/foregroundTaskManager.d.ts +9 -0
  23. package/dist/managers/foregroundTaskManager.d.ts.map +1 -0
  24. package/dist/managers/foregroundTaskManager.js +21 -0
  25. package/dist/managers/liveConfigManager.d.ts +1 -1
  26. package/dist/managers/lspManager.d.ts.map +1 -1
  27. package/dist/managers/lspManager.js +3 -1
  28. package/dist/managers/mcpManager.d.ts.map +1 -1
  29. package/dist/managers/messageManager.d.ts +26 -12
  30. package/dist/managers/messageManager.d.ts.map +1 -1
  31. package/dist/managers/messageManager.js +138 -64
  32. package/dist/managers/permissionManager.d.ts.map +1 -1
  33. package/dist/managers/permissionManager.js +26 -22
  34. package/dist/managers/planManager.d.ts +1 -1
  35. package/dist/managers/planManager.d.ts.map +1 -1
  36. package/dist/managers/planManager.js +2 -2
  37. package/dist/managers/pluginManager.d.ts.map +1 -1
  38. package/dist/managers/pluginManager.js +3 -2
  39. package/dist/managers/slashCommandManager.d.ts +6 -0
  40. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  41. package/dist/managers/slashCommandManager.js +8 -2
  42. package/dist/managers/subagentManager.d.ts +15 -2
  43. package/dist/managers/subagentManager.d.ts.map +1 -1
  44. package/dist/managers/subagentManager.js +153 -39
  45. package/dist/managers/toolManager.d.ts +18 -1
  46. package/dist/managers/toolManager.d.ts.map +1 -1
  47. package/dist/managers/toolManager.js +29 -5
  48. package/dist/services/GitService.d.ts.map +1 -1
  49. package/dist/services/GitService.js +6 -2
  50. package/dist/services/MarketplaceService.d.ts +2 -2
  51. package/dist/services/MarketplaceService.d.ts.map +1 -1
  52. package/dist/services/MarketplaceService.js +18 -11
  53. package/dist/services/MemoryRuleService.d.ts +1 -1
  54. package/dist/services/MemoryRuleService.d.ts.map +1 -1
  55. package/dist/services/MemoryRuleService.js +13 -2
  56. package/dist/services/aiService.d.ts +0 -1
  57. package/dist/services/aiService.d.ts.map +1 -1
  58. package/dist/services/aiService.js +4 -140
  59. package/dist/services/memory.d.ts +0 -3
  60. package/dist/services/memory.d.ts.map +1 -1
  61. package/dist/services/memory.js +1 -60
  62. package/dist/services/session.d.ts +15 -1
  63. package/dist/services/session.d.ts.map +1 -1
  64. package/dist/services/session.js +57 -1
  65. package/dist/services/taskManager.d.ts +21 -0
  66. package/dist/services/taskManager.d.ts.map +1 -0
  67. package/dist/services/taskManager.js +158 -0
  68. package/dist/tools/askUserQuestion.d.ts.map +1 -1
  69. package/dist/tools/askUserQuestion.js +39 -25
  70. package/dist/tools/bashTool.d.ts +0 -8
  71. package/dist/tools/bashTool.d.ts.map +1 -1
  72. package/dist/tools/bashTool.js +48 -172
  73. package/dist/tools/editTool.d.ts.map +1 -1
  74. package/dist/tools/editTool.js +8 -6
  75. package/dist/tools/exitPlanMode.d.ts.map +1 -1
  76. package/dist/tools/exitPlanMode.js +25 -1
  77. package/dist/tools/globTool.d.ts.map +1 -1
  78. package/dist/tools/globTool.js +8 -2
  79. package/dist/tools/grepTool.d.ts.map +1 -1
  80. package/dist/tools/grepTool.js +17 -6
  81. package/dist/tools/lsTool.d.ts.map +1 -1
  82. package/dist/tools/lsTool.js +3 -1
  83. package/dist/tools/multiEditTool.d.ts.map +1 -1
  84. package/dist/tools/multiEditTool.js +7 -6
  85. package/dist/tools/readTool.d.ts.map +1 -1
  86. package/dist/tools/readTool.js +16 -1
  87. package/dist/tools/taskManagementTools.d.ts +6 -0
  88. package/dist/tools/taskManagementTools.d.ts.map +1 -0
  89. package/dist/tools/taskManagementTools.js +453 -0
  90. package/dist/tools/taskOutputTool.d.ts +3 -0
  91. package/dist/tools/taskOutputTool.d.ts.map +1 -0
  92. package/dist/tools/taskOutputTool.js +173 -0
  93. package/dist/tools/taskStopTool.d.ts +3 -0
  94. package/dist/tools/taskStopTool.d.ts.map +1 -0
  95. package/dist/tools/taskStopTool.js +71 -0
  96. package/dist/tools/taskTool.d.ts.map +1 -1
  97. package/dist/tools/taskTool.js +110 -63
  98. package/dist/tools/types.d.ts +12 -0
  99. package/dist/tools/types.d.ts.map +1 -1
  100. package/dist/tools/writeTool.d.ts.map +1 -1
  101. package/dist/tools/writeTool.js +9 -1
  102. package/dist/types/index.d.ts +1 -0
  103. package/dist/types/index.d.ts.map +1 -1
  104. package/dist/types/index.js +1 -0
  105. package/dist/types/marketplace.d.ts +1 -0
  106. package/dist/types/marketplace.d.ts.map +1 -1
  107. package/dist/types/messaging.d.ts +3 -8
  108. package/dist/types/messaging.d.ts.map +1 -1
  109. package/dist/types/processes.d.ts +29 -4
  110. package/dist/types/processes.d.ts.map +1 -1
  111. package/dist/types/tasks.d.ts +13 -0
  112. package/dist/types/tasks.d.ts.map +1 -0
  113. package/dist/types/tasks.js +1 -0
  114. package/dist/types/tools.d.ts +4 -1
  115. package/dist/types/tools.d.ts.map +1 -1
  116. package/dist/utils/builtinSubagents.d.ts.map +1 -1
  117. package/dist/utils/builtinSubagents.js +38 -1
  118. package/dist/utils/cacheControlUtils.d.ts.map +1 -1
  119. package/dist/utils/cacheControlUtils.js +18 -12
  120. package/dist/utils/constants.d.ts +0 -4
  121. package/dist/utils/constants.d.ts.map +1 -1
  122. package/dist/utils/constants.js +0 -4
  123. package/dist/utils/convertMessagesForAPI.js +2 -2
  124. package/dist/utils/editUtils.d.ts +2 -11
  125. package/dist/utils/editUtils.d.ts.map +1 -1
  126. package/dist/utils/editUtils.js +52 -79
  127. package/dist/utils/messageOperations.d.ts +5 -36
  128. package/dist/utils/messageOperations.d.ts.map +1 -1
  129. package/dist/utils/messageOperations.js +9 -98
  130. package/dist/utils/nameGenerator.d.ts +1 -1
  131. package/dist/utils/nameGenerator.d.ts.map +1 -1
  132. package/dist/utils/nameGenerator.js +19 -3
  133. package/package.json +5 -5
  134. package/src/agent.ts +157 -134
  135. package/src/constants/prompts.ts +156 -65
  136. package/src/constants/tools.ts +6 -3
  137. package/src/index.ts +1 -0
  138. package/src/managers/MemoryRuleManager.ts +1 -1
  139. package/src/managers/aiManager.ts +77 -35
  140. package/src/managers/backgroundBashManager.ts +1 -0
  141. package/src/managers/backgroundTaskManager.ts +305 -0
  142. package/src/managers/foregroundTaskManager.ts +27 -0
  143. package/src/managers/lspManager.ts +3 -1
  144. package/src/managers/mcpManager.ts +6 -3
  145. package/src/managers/messageManager.ts +185 -75
  146. package/src/managers/permissionManager.ts +33 -28
  147. package/src/managers/planManager.ts +2 -2
  148. package/src/managers/pluginManager.ts +4 -3
  149. package/src/managers/slashCommandManager.ts +15 -2
  150. package/src/managers/subagentManager.ts +194 -35
  151. package/src/managers/toolManager.ts +48 -6
  152. package/src/services/GitService.ts +6 -2
  153. package/src/services/MarketplaceService.ts +30 -12
  154. package/src/services/MemoryRuleService.ts +18 -6
  155. package/src/services/aiService.ts +3 -145
  156. package/src/services/memory.ts +1 -73
  157. package/src/services/session.ts +73 -0
  158. package/src/services/taskManager.ts +188 -0
  159. package/src/tools/askUserQuestion.ts +51 -29
  160. package/src/tools/bashTool.ts +63 -196
  161. package/src/tools/editTool.ts +9 -18
  162. package/src/tools/exitPlanMode.ts +26 -2
  163. package/src/tools/globTool.ts +10 -2
  164. package/src/tools/grepTool.ts +17 -6
  165. package/src/tools/lsTool.ts +3 -1
  166. package/src/tools/multiEditTool.ts +7 -18
  167. package/src/tools/readTool.ts +17 -1
  168. package/src/tools/taskManagementTools.ts +498 -0
  169. package/src/tools/taskOutputTool.ts +196 -0
  170. package/src/tools/taskStopTool.ts +78 -0
  171. package/src/tools/taskTool.ts +136 -74
  172. package/src/tools/types.ts +13 -0
  173. package/src/tools/writeTool.ts +9 -2
  174. package/src/types/index.ts +1 -0
  175. package/src/types/marketplace.ts +1 -0
  176. package/src/types/messaging.ts +2 -9
  177. package/src/types/processes.ts +39 -4
  178. package/src/types/tasks.ts +13 -0
  179. package/src/types/tools.ts +4 -1
  180. package/src/utils/builtinSubagents.ts +47 -1
  181. package/src/utils/cacheControlUtils.ts +26 -18
  182. package/src/utils/constants.ts +0 -5
  183. package/src/utils/convertMessagesForAPI.ts +2 -2
  184. package/src/utils/editUtils.ts +65 -103
  185. package/src/utils/messageOperations.ts +12 -136
  186. package/src/utils/nameGenerator.ts +20 -3
  187. package/dist/tools/todoWriteTool.d.ts +0 -6
  188. package/dist/tools/todoWriteTool.d.ts.map +0 -1
  189. package/dist/tools/todoWriteTool.js +0 -220
  190. package/src/tools/todoWriteTool.ts +0 -257
@@ -0,0 +1,196 @@
1
+ import { TASK_OUTPUT_TOOL_NAME } from "../constants/tools.js";
2
+ import { ToolContext, ToolPlugin, ToolResult } from "./types.js";
3
+ import { stripAnsiColors } from "../utils/stringUtils.js";
4
+
5
+ const MAX_OUTPUT_LENGTH = 30000;
6
+
7
+ export const taskOutputTool: ToolPlugin = {
8
+ name: TASK_OUTPUT_TOOL_NAME,
9
+ config: {
10
+ type: "function",
11
+ function: {
12
+ name: TASK_OUTPUT_TOOL_NAME,
13
+ description: "Retrieves output from a running or completed task",
14
+ parameters: {
15
+ type: "object",
16
+ properties: {
17
+ task_id: {
18
+ type: "string",
19
+ description: "The task ID to get output from",
20
+ },
21
+ block: {
22
+ type: "boolean",
23
+ default: true,
24
+ description: "Whether to wait for completion",
25
+ },
26
+ timeout: {
27
+ type: "number",
28
+ minimum: 0,
29
+ maximum: 600000,
30
+ default: 30000,
31
+ description: "Max wait time in ms",
32
+ },
33
+ },
34
+ required: ["task_id"],
35
+ },
36
+ },
37
+ },
38
+ prompt:
39
+ () => `- Retrieves output from a running or completed task (background shell, agent, or remote session)
40
+ - Takes a task_id parameter identifying the task
41
+ - Returns the task output along with status information
42
+ - Use block=true (default) to wait for task completion
43
+ - Use block=false for non-blocking check of current status
44
+ - Task IDs can be found using the /tasks command
45
+ - Works with all task types: background shells, async agents, and remote sessions`,
46
+ execute: async (
47
+ args: Record<string, unknown>,
48
+ context: ToolContext,
49
+ ): Promise<ToolResult> => {
50
+ const taskId = args.task_id as string;
51
+ const filter = args.filter as string | undefined;
52
+ const block = (args.block as boolean | undefined) ?? true;
53
+ const timeout = (args.timeout as number | undefined) ?? 30000;
54
+
55
+ if (!taskId || typeof taskId !== "string") {
56
+ return {
57
+ success: false,
58
+ content: "",
59
+ error: "task_id parameter is required and must be a string",
60
+ };
61
+ }
62
+
63
+ const backgroundTaskManager = context?.backgroundTaskManager;
64
+ if (!backgroundTaskManager) {
65
+ return {
66
+ success: false,
67
+ content: "",
68
+ error: "Background task manager not available",
69
+ };
70
+ }
71
+
72
+ const getResult = () => {
73
+ const output = backgroundTaskManager.getOutput(taskId, filter);
74
+ if (!output) return null;
75
+
76
+ let content = "";
77
+ if (output.stdout) {
78
+ content += stripAnsiColors(output.stdout);
79
+ }
80
+ if (output.stderr) {
81
+ content += (content ? "\n" : "") + stripAnsiColors(output.stderr);
82
+ }
83
+
84
+ const finalContent = content || "No output available";
85
+ const processedContent =
86
+ finalContent.length > MAX_OUTPUT_LENGTH
87
+ ? finalContent.substring(0, MAX_OUTPUT_LENGTH) +
88
+ "\n\n... (output truncated)"
89
+ : finalContent;
90
+
91
+ return {
92
+ success: true,
93
+ content: processedContent,
94
+ shortResult: `${taskId}: ${output.status}`,
95
+ };
96
+ };
97
+
98
+ if (block) {
99
+ // Polling for completion
100
+ return new Promise((resolve) => {
101
+ let timeoutHandle: NodeJS.Timeout | null = null;
102
+ let isAborted = false;
103
+ const startTime = Date.now();
104
+
105
+ const cleanup = () => {
106
+ if (timeoutHandle) {
107
+ clearTimeout(timeoutHandle);
108
+ timeoutHandle = null;
109
+ }
110
+ };
111
+
112
+ const onAbort = () => {
113
+ isAborted = true;
114
+ cleanup();
115
+ resolve({
116
+ success: false,
117
+ content: "",
118
+ error: "Task output retrieval was aborted",
119
+ });
120
+ };
121
+
122
+ if (context.abortSignal) {
123
+ if (context.abortSignal.aborted) {
124
+ onAbort();
125
+ return;
126
+ }
127
+ context.abortSignal.addEventListener("abort", onAbort, {
128
+ once: true,
129
+ });
130
+ }
131
+
132
+ const check = () => {
133
+ if (isAborted) return;
134
+
135
+ if (Date.now() - startTime > timeout) {
136
+ if (context.abortSignal) {
137
+ context.abortSignal.removeEventListener("abort", onAbort);
138
+ }
139
+ resolve({
140
+ success: true,
141
+ content: "Retrieval timed out",
142
+ shortResult: `${taskId}: timeout`,
143
+ });
144
+ return;
145
+ }
146
+
147
+ const task = backgroundTaskManager.getTask(taskId);
148
+ if (!task) {
149
+ if (context.abortSignal) {
150
+ context.abortSignal.removeEventListener("abort", onAbort);
151
+ }
152
+ resolve({
153
+ success: false,
154
+ content: "",
155
+ error: `Task with ID ${taskId} not found`,
156
+ });
157
+ return;
158
+ }
159
+
160
+ if (task.status !== "running") {
161
+ if (context.abortSignal) {
162
+ context.abortSignal.removeEventListener("abort", onAbort);
163
+ }
164
+ const result = getResult();
165
+ resolve(
166
+ result || {
167
+ success: false,
168
+ content: "",
169
+ error: "Task not found",
170
+ },
171
+ );
172
+ } else {
173
+ timeoutHandle = setTimeout(check, 500);
174
+ }
175
+ };
176
+ check();
177
+ });
178
+ }
179
+
180
+ const result = getResult();
181
+ if (!result) {
182
+ return {
183
+ success: false,
184
+ content: "",
185
+ error: `Task with ID ${taskId} not found`,
186
+ };
187
+ }
188
+
189
+ return result;
190
+ },
191
+ formatCompactParams: (params: Record<string, unknown>) => {
192
+ const taskId = params.task_id as string;
193
+ const block = params.block as boolean;
194
+ return `${taskId}${block ? " (blocking)" : ""}`;
195
+ },
196
+ };
@@ -0,0 +1,78 @@
1
+ import { TASK_STOP_TOOL_NAME } from "../constants/tools.js";
2
+ import { ToolContext, ToolPlugin, ToolResult } from "./types.js";
3
+
4
+ export const taskStopTool: ToolPlugin = {
5
+ name: TASK_STOP_TOOL_NAME,
6
+ config: {
7
+ type: "function",
8
+ function: {
9
+ name: TASK_STOP_TOOL_NAME,
10
+ description: "Stop a running background task by ID",
11
+ parameters: {
12
+ type: "object",
13
+ properties: {
14
+ task_id: {
15
+ type: "string",
16
+ description: "The ID of the background task to stop",
17
+ },
18
+ },
19
+ required: ["task_id"],
20
+ },
21
+ },
22
+ },
23
+ prompt: () => `
24
+ - Stops a running background task by its ID
25
+ - Takes a task_id parameter identifying the task to stop
26
+ - Returns a success or failure status
27
+ - Use this tool when you need to terminate a long-running task
28
+ `,
29
+ execute: async (
30
+ args: Record<string, unknown>,
31
+ context: ToolContext,
32
+ ): Promise<ToolResult> => {
33
+ const taskId = args.task_id as string;
34
+
35
+ if (!taskId || typeof taskId !== "string") {
36
+ return {
37
+ success: false,
38
+ content: "",
39
+ error: "task_id parameter is required and must be a string",
40
+ };
41
+ }
42
+
43
+ const backgroundTaskManager = context?.backgroundTaskManager;
44
+ if (!backgroundTaskManager) {
45
+ return {
46
+ success: false,
47
+ content: "",
48
+ error: "Background task manager not available",
49
+ };
50
+ }
51
+
52
+ const stopped = backgroundTaskManager.stopTask(taskId);
53
+ if (stopped) {
54
+ return {
55
+ success: true,
56
+ content: `Task ${taskId} has been stopped`,
57
+ shortResult: `Stopped ${taskId}`,
58
+ };
59
+ } else {
60
+ const task = backgroundTaskManager.getTask(taskId);
61
+ if (!task) {
62
+ return {
63
+ success: false,
64
+ content: "",
65
+ error: `Task with ID ${taskId} not found`,
66
+ };
67
+ }
68
+ return {
69
+ success: false,
70
+ content: "",
71
+ error: `Failed to stop task ${taskId} (status: ${task.status})`,
72
+ };
73
+ }
74
+ },
75
+ formatCompactParams: (params: Record<string, unknown>) => {
76
+ return params.task_id as string;
77
+ },
78
+ };
@@ -46,6 +46,11 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
46
46
  type: "string",
47
47
  description: `The type or name of subagent to use. Available options: ${availableSubagents.map((c) => c.name).join(", ") || "none"}`,
48
48
  },
49
+ run_in_background: {
50
+ type: "boolean",
51
+ description:
52
+ "Set to true to run this command in the background. Use TaskOutput to read the output later.",
53
+ },
49
54
  },
50
55
  required: ["description", "prompt", "subagent_type"],
51
56
  },
@@ -53,84 +58,141 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
53
58
  };
54
59
  },
55
60
 
61
+ prompt: () => `
62
+ - When doing file search, prefer to use the ${TASK_TOOL_NAME} tool in order to reduce context usage.
63
+ - You should proactively use the ${TASK_TOOL_NAME} tool with specialized agents when the task at hand matches the agent's description.
64
+ - 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 instead of running search commands directly.`,
65
+
56
66
  execute: async (
57
67
  args: Record<string, unknown>,
58
68
  context: ToolContext,
59
69
  ): Promise<ToolResult> => {
60
- // Input validation
61
- const description = args.description as string;
62
- const prompt = args.prompt as string;
63
- const subagent_type = args.subagent_type as string;
64
-
65
- if (!description || typeof description !== "string") {
66
- return {
67
- success: false,
68
- content: "",
69
- error: "description parameter is required and must be a string",
70
- shortResult: "Task delegation failed",
71
- };
72
- }
73
-
74
- if (!prompt || typeof prompt !== "string") {
75
- return {
76
- success: false,
77
- content: "",
78
- error: "prompt parameter is required and must be a string",
79
- shortResult: "Task delegation failed",
80
- };
81
- }
82
-
83
- if (!subagent_type || typeof subagent_type !== "string") {
84
- return {
85
- success: false,
86
- content: "",
87
- error: "subagent_type parameter is required and must be a string",
88
- shortResult: "Task delegation failed",
89
- };
90
- }
91
-
92
- try {
93
- // Subagent selection logic with explicit name matching only
94
- const configuration = await subagentManager.findSubagent(subagent_type);
95
-
96
- if (!configuration) {
97
- // Error handling for nonexistent subagents with available subagents listing
98
- const allConfigs = subagentManager.getConfigurations();
99
- const availableNames = allConfigs.map((c) => c.name).join(", ");
100
-
101
- return {
102
- success: false,
103
- content: "",
104
- error: `No subagent found matching "${subagent_type}". Available subagents: ${availableNames || "none"}`,
105
- shortResult: "Subagent not found",
106
- };
107
- }
108
-
109
- // Create subagent instance and execute task
110
- const instance = await subagentManager.createInstance(configuration, {
111
- description,
112
- prompt,
113
- subagent_type,
114
- });
115
- const response = await subagentManager.executeTask(
116
- instance,
117
- prompt,
118
- context.abortSignal,
119
- );
120
-
121
- return {
122
- success: true,
123
- content: response,
124
- shortResult: `Task completed by ${configuration.name}`,
125
- };
126
- } catch (error) {
127
- return {
128
- success: false,
129
- content: "",
130
- error: `Task delegation failed: ${error instanceof Error ? error.message : String(error)}`,
131
- shortResult: "Delegation error",
132
- };
133
- }
70
+ return new Promise((resolve) => {
71
+ (async () => {
72
+ // Input validation
73
+ const description = args.description as string;
74
+ const prompt = args.prompt as string;
75
+ const subagent_type = args.subagent_type as string;
76
+ const run_in_background = args.run_in_background as boolean;
77
+
78
+ if (!description || typeof description !== "string") {
79
+ return resolve({
80
+ success: false,
81
+ content: "",
82
+ error: "description parameter is required and must be a string",
83
+ shortResult: "Task delegation failed",
84
+ });
85
+ }
86
+
87
+ if (!prompt || typeof prompt !== "string") {
88
+ return resolve({
89
+ success: false,
90
+ content: "",
91
+ error: "prompt parameter is required and must be a string",
92
+ shortResult: "Task delegation failed",
93
+ });
94
+ }
95
+
96
+ if (!subagent_type || typeof subagent_type !== "string") {
97
+ return resolve({
98
+ success: false,
99
+ content: "",
100
+ error: "subagent_type parameter is required and must be a string",
101
+ shortResult: "Task delegation failed",
102
+ });
103
+ }
104
+
105
+ try {
106
+ // Subagent selection logic with explicit name matching only
107
+ const configuration =
108
+ await subagentManager.findSubagent(subagent_type);
109
+
110
+ if (!configuration) {
111
+ // Error handling for nonexistent subagents with available subagents listing
112
+ const allConfigs = subagentManager.getConfigurations();
113
+ const availableNames = allConfigs.map((c) => c.name).join(", ");
114
+
115
+ return resolve({
116
+ success: false,
117
+ content: "",
118
+ error: `No subagent found matching "${subagent_type}". Available subagents: ${availableNames || "none"}`,
119
+ shortResult: "Subagent not found",
120
+ });
121
+ }
122
+
123
+ // Create subagent instance and execute task
124
+ const instance = await subagentManager.createInstance(
125
+ configuration,
126
+ {
127
+ description,
128
+ prompt,
129
+ subagent_type,
130
+ },
131
+ run_in_background,
132
+ );
133
+
134
+ let isBackgrounded = false;
135
+
136
+ // Register for backgrounding if not already in background
137
+ if (!run_in_background && context.foregroundTaskManager) {
138
+ context.foregroundTaskManager.registerForegroundTask({
139
+ id: instance.subagentId,
140
+ backgroundHandler: async () => {
141
+ isBackgrounded = true;
142
+ const taskId = await subagentManager.backgroundInstance(
143
+ instance.subagentId,
144
+ );
145
+ // Resolve the tool execution early so the main agent can continue
146
+ resolve({
147
+ success: true,
148
+ content: `Task moved to background with ID: ${taskId}.`,
149
+ shortResult: "Task backgrounded",
150
+ isManuallyBackgrounded: true,
151
+ });
152
+ },
153
+ });
154
+ }
155
+
156
+ try {
157
+ const result = await subagentManager.executeTask(
158
+ instance,
159
+ prompt,
160
+ context.abortSignal,
161
+ run_in_background,
162
+ );
163
+
164
+ if (isBackgrounded) return;
165
+
166
+ if (run_in_background) {
167
+ return resolve({
168
+ success: true,
169
+ content: `Task started in background with ID: ${result}`,
170
+ shortResult: `Task started in background: ${result}`,
171
+ });
172
+ }
173
+
174
+ return resolve({
175
+ success: true,
176
+ content: result,
177
+ shortResult: `Task completed by ${configuration.name}`,
178
+ });
179
+ } finally {
180
+ if (!run_in_background && context.foregroundTaskManager) {
181
+ context.foregroundTaskManager.unregisterForegroundTask(
182
+ instance.subagentId,
183
+ );
184
+ }
185
+ }
186
+ } catch (error) {
187
+ return resolve({
188
+ success: false,
189
+ content: "",
190
+ error: `Task delegation failed: ${error instanceof Error ? error.message : String(error)}`,
191
+ shortResult: "Delegation error",
192
+ });
193
+ }
194
+ })();
195
+ });
134
196
  },
135
197
 
136
198
  formatCompactParams: (params: Record<string, unknown>) => {
@@ -19,6 +19,10 @@ export interface ToolPlugin {
19
19
  params: Record<string, unknown>,
20
20
  context: ToolContext,
21
21
  ) => string;
22
+ /**
23
+ * Optional function to provide a prompt to be added to the system prompt
24
+ */
25
+ prompt?: () => string;
22
26
  }
23
27
 
24
28
  export interface ToolResult {
@@ -34,11 +38,14 @@ export interface ToolResult {
34
38
  data: string; // base64 encoded image data
35
39
  mediaType?: string; // Image media type, such as "image/png"
36
40
  }>;
41
+ // Whether the tool was manually backgrounded by the user (e.g. via Ctrl-B)
42
+ isManuallyBackgrounded?: boolean;
37
43
  }
38
44
 
39
45
  export interface ToolContext {
40
46
  abortSignal?: AbortSignal;
41
47
  backgroundBashManager?: import("../managers/backgroundBashManager.js").BackgroundBashManager;
48
+ backgroundTaskManager?: import("../managers/backgroundTaskManager.js").BackgroundTaskManager;
42
49
  workdir: string;
43
50
  /** Permission mode for this tool execution */
44
51
  permissionMode?: PermissionMode;
@@ -54,4 +61,10 @@ export interface ToolContext {
54
61
  reversionManager?: import("../managers/reversionManager.js").ReversionManager;
55
62
  /** Current message ID for associating snapshots */
56
63
  messageId?: string;
64
+ /** Foreground task manager for backgrounding tasks */
65
+ foregroundTaskManager?: import("../types/processes.js").IForegroundTaskManager;
66
+ /** Task manager instance for task management */
67
+ taskManager: import("../services/taskManager.js").TaskManager;
68
+ /** Current session ID */
69
+ sessionId?: string;
57
70
  }
@@ -13,8 +13,7 @@ export const writeTool: ToolPlugin = {
13
13
  type: "function",
14
14
  function: {
15
15
  name: "Write",
16
- description:
17
- "Writes a file to the local filesystem.\n\nUsage:\n- This tool will overwrite the existing file if there is one at the provided path.\n- If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.\n- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n- NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.\n- Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.\n- IMPORTANT: Always provide file_path parameter before content parameter when calling this tool.",
16
+ description: "Writes a file to the local filesystem.",
18
17
  parameters: {
19
18
  type: "object",
20
19
  properties: {
@@ -33,6 +32,14 @@ export const writeTool: ToolPlugin = {
33
32
  },
34
33
  },
35
34
  },
35
+ prompt: () => `
36
+ Usage:
37
+ - This tool will overwrite the existing file if there is one at the provided path.
38
+ - If this is an existing file, you MUST use the Read tool first to read the file's contents. This tool will fail if you did not read the file first.
39
+ - ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
40
+ - NEVER proactively create documentation files (*.md) or README files. Only create documentation files if explicitly requested by the User.
41
+ - Only use emojis if the user explicitly requests it. Avoid writing emojis to files unless asked.
42
+ - IMPORTANT: Always provide file_path parameter before content parameter when calling this tool.`,
36
43
  execute: async (
37
44
  args: Record<string, unknown>,
38
45
  context: ToolContext,
@@ -33,3 +33,4 @@ export * from "./plugins.js";
33
33
  export * from "./marketplace.js";
34
34
  export * from "./memoryRule.js";
35
35
  export * from "./history.js";
36
+ export * from "./tasks.js";
@@ -49,6 +49,7 @@ export interface InstalledPlugin {
49
49
  version: string;
50
50
  cachePath: string;
51
51
  scope?: Scope;
52
+ projectPath?: string;
52
53
  }
53
54
 
54
55
  export interface InstalledPluginsRegistry {
@@ -26,7 +26,6 @@ export type MessageBlock =
26
26
  | ImageBlock
27
27
  | CommandOutputBlock
28
28
  | CompressBlock
29
- | MemoryBlock
30
29
  | SubagentBlock
31
30
  | ReasoningBlock
32
31
  | FileHistoryBlock;
@@ -67,6 +66,7 @@ export interface ToolBlock {
67
66
  error?: string | Error;
68
67
  compactParams?: string; // Compact parameter display
69
68
  parametersChunk?: string; // Incremental parameter updates for streaming
69
+ isManuallyBackgrounded?: boolean; // Whether the tool was manually backgrounded by the user
70
70
  }
71
71
 
72
72
  export interface ImageBlock {
@@ -88,14 +88,6 @@ export interface CompressBlock {
88
88
  sessionId: string;
89
89
  }
90
90
 
91
- export interface MemoryBlock {
92
- type: "memory";
93
- content: string;
94
- isSuccess: boolean;
95
- memoryType?: "project" | "user"; // Memory type
96
- storagePath?: string; // Storage path text
97
- }
98
-
99
91
  export interface SubagentBlock {
100
92
  type: "subagent";
101
93
  subagentId: string;
@@ -103,6 +95,7 @@ export interface SubagentBlock {
103
95
  status: "active" | "completed" | "error" | "aborted";
104
96
  sessionId: string;
105
97
  configuration: SubagentConfiguration;
98
+ runInBackground?: boolean;
106
99
  }
107
100
 
108
101
  export interface ReasoningBlock {
@@ -5,14 +5,49 @@
5
5
 
6
6
  import type { ChildProcess } from "child_process";
7
7
 
8
- export interface BackgroundShell {
8
+ export type BackgroundTaskStatus =
9
+ | "running"
10
+ | "completed"
11
+ | "failed"
12
+ | "killed";
13
+ export type BackgroundTaskType = "shell" | "subagent";
14
+
15
+ export interface BackgroundTaskBase {
9
16
  id: string;
10
- process: ChildProcess;
11
- command: string;
17
+ type: BackgroundTaskType;
18
+ status: BackgroundTaskStatus;
12
19
  startTime: number;
13
- status: "running" | "completed" | "killed";
20
+ endTime?: number;
21
+ command?: string; // for shell
22
+ description?: string; // for subagent
14
23
  stdout: string;
15
24
  stderr: string;
16
25
  exitCode?: number;
17
26
  runtime?: number;
27
+ /**
28
+ * Optional callback to be executed when the task is stopped.
29
+ * This allows tasks to define their own cleanup/abortion logic.
30
+ */
31
+ onStop?: () => void | Promise<void>;
32
+ }
33
+
34
+ export interface BackgroundShell extends BackgroundTaskBase {
35
+ type: "shell";
36
+ process: ChildProcess;
37
+ }
38
+
39
+ export interface BackgroundSubagent extends BackgroundTaskBase {
40
+ type: "subagent";
41
+ }
42
+
43
+ export type BackgroundTask = BackgroundShell | BackgroundSubagent;
44
+
45
+ export interface ForegroundTask {
46
+ id: string;
47
+ backgroundHandler: () => Promise<void>;
48
+ }
49
+
50
+ export interface IForegroundTaskManager {
51
+ registerForegroundTask(task: ForegroundTask): void;
52
+ unregisterForegroundTask(id: string): void;
18
53
  }