wave-agent-sdk 0.5.0 → 0.6.2

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 (169) hide show
  1. package/dist/agent.d.ts +14 -11
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +64 -151
  4. package/dist/constants/subagents.d.ts +5 -0
  5. package/dist/constants/subagents.d.ts.map +1 -0
  6. package/dist/constants/subagents.js +4 -0
  7. package/dist/constants/tools.d.ts +4 -1
  8. package/dist/constants/tools.d.ts.map +1 -1
  9. package/dist/constants/tools.js +4 -1
  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/aiManager.d.ts +2 -5
  14. package/dist/managers/aiManager.d.ts.map +1 -1
  15. package/dist/managers/aiManager.js +43 -48
  16. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  17. package/dist/managers/backgroundTaskManager.js +63 -53
  18. package/dist/managers/foregroundTaskManager.d.ts.map +1 -1
  19. package/dist/managers/foregroundTaskManager.js +3 -2
  20. package/dist/managers/mcpManager.d.ts.map +1 -1
  21. package/dist/managers/messageManager.d.ts +13 -27
  22. package/dist/managers/messageManager.d.ts.map +1 -1
  23. package/dist/managers/messageManager.js +94 -89
  24. package/dist/managers/permissionManager.d.ts.map +1 -1
  25. package/dist/managers/permissionManager.js +25 -15
  26. package/dist/managers/planManager.d.ts +1 -1
  27. package/dist/managers/planManager.d.ts.map +1 -1
  28. package/dist/managers/planManager.js +2 -2
  29. package/dist/managers/reversionManager.d.ts.map +1 -1
  30. package/dist/managers/reversionManager.js +23 -2
  31. package/dist/managers/slashCommandManager.d.ts +3 -0
  32. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  33. package/dist/managers/slashCommandManager.js +8 -3
  34. package/dist/managers/subagentManager.d.ts +8 -14
  35. package/dist/managers/subagentManager.d.ts.map +1 -1
  36. package/dist/managers/subagentManager.js +46 -112
  37. package/dist/managers/toolManager.d.ts +11 -0
  38. package/dist/managers/toolManager.d.ts.map +1 -1
  39. package/dist/managers/toolManager.js +20 -2
  40. package/dist/{constants/prompts.d.ts → prompts/index.d.ts} +17 -15
  41. package/dist/prompts/index.d.ts.map +1 -0
  42. package/dist/prompts/index.js +309 -0
  43. package/dist/services/aiService.d.ts +0 -1
  44. package/dist/services/aiService.d.ts.map +1 -1
  45. package/dist/services/aiService.js +4 -140
  46. package/dist/services/memory.d.ts +0 -3
  47. package/dist/services/memory.d.ts.map +1 -1
  48. package/dist/services/memory.js +0 -59
  49. package/dist/services/session.d.ts +15 -1
  50. package/dist/services/session.d.ts.map +1 -1
  51. package/dist/services/session.js +57 -1
  52. package/dist/services/taskManager.d.ts +25 -0
  53. package/dist/services/taskManager.d.ts.map +1 -0
  54. package/dist/services/taskManager.js +164 -0
  55. package/dist/tools/askUserQuestion.d.ts.map +1 -1
  56. package/dist/tools/askUserQuestion.js +39 -25
  57. package/dist/tools/bashTool.d.ts.map +1 -1
  58. package/dist/tools/bashTool.js +13 -11
  59. package/dist/tools/editTool.d.ts.map +1 -1
  60. package/dist/tools/editTool.js +2 -1
  61. package/dist/tools/exitPlanMode.d.ts.map +1 -1
  62. package/dist/tools/exitPlanMode.js +26 -2
  63. package/dist/tools/globTool.d.ts.map +1 -1
  64. package/dist/tools/globTool.js +8 -2
  65. package/dist/tools/grepTool.d.ts.map +1 -1
  66. package/dist/tools/grepTool.js +17 -6
  67. package/dist/tools/lsTool.d.ts.map +1 -1
  68. package/dist/tools/lsTool.js +3 -1
  69. package/dist/tools/readTool.d.ts.map +1 -1
  70. package/dist/tools/readTool.js +16 -1
  71. package/dist/tools/taskManagementTools.d.ts +6 -0
  72. package/dist/tools/taskManagementTools.d.ts.map +1 -0
  73. package/dist/tools/taskManagementTools.js +461 -0
  74. package/dist/tools/taskOutputTool.d.ts.map +1 -1
  75. package/dist/tools/taskOutputTool.js +32 -8
  76. package/dist/tools/taskStopTool.d.ts.map +1 -1
  77. package/dist/tools/taskStopTool.js +7 -1
  78. package/dist/tools/taskTool.d.ts.map +1 -1
  79. package/dist/tools/taskTool.js +37 -2
  80. package/dist/tools/types.d.ts +11 -0
  81. package/dist/tools/types.d.ts.map +1 -1
  82. package/dist/tools/writeTool.d.ts.map +1 -1
  83. package/dist/tools/writeTool.js +9 -1
  84. package/dist/types/index.d.ts +1 -0
  85. package/dist/types/index.d.ts.map +1 -1
  86. package/dist/types/index.js +1 -0
  87. package/dist/types/messaging.d.ts +2 -18
  88. package/dist/types/messaging.d.ts.map +1 -1
  89. package/dist/types/processes.d.ts +16 -6
  90. package/dist/types/processes.d.ts.map +1 -1
  91. package/dist/types/tasks.d.ts +13 -0
  92. package/dist/types/tasks.d.ts.map +1 -0
  93. package/dist/types/tasks.js +1 -0
  94. package/dist/types/tools.d.ts +4 -1
  95. package/dist/types/tools.d.ts.map +1 -1
  96. package/dist/utils/builtinSubagents.d.ts.map +1 -1
  97. package/dist/utils/builtinSubagents.js +59 -44
  98. package/dist/utils/cacheControlUtils.d.ts.map +1 -1
  99. package/dist/utils/cacheControlUtils.js +18 -12
  100. package/dist/utils/constants.d.ts +0 -4
  101. package/dist/utils/constants.d.ts.map +1 -1
  102. package/dist/utils/constants.js +0 -4
  103. package/dist/utils/convertMessagesForAPI.js +2 -2
  104. package/dist/utils/editUtils.d.ts.map +1 -1
  105. package/dist/utils/editUtils.js +2 -2
  106. package/dist/utils/gitUtils.d.ts +7 -0
  107. package/dist/utils/gitUtils.d.ts.map +1 -0
  108. package/dist/utils/gitUtils.js +24 -0
  109. package/dist/utils/messageOperations.d.ts +3 -58
  110. package/dist/utils/messageOperations.d.ts.map +1 -1
  111. package/dist/utils/messageOperations.js +4 -146
  112. package/dist/utils/nameGenerator.d.ts +1 -1
  113. package/dist/utils/nameGenerator.d.ts.map +1 -1
  114. package/dist/utils/nameGenerator.js +19 -3
  115. package/package.json +1 -1
  116. package/src/agent.ts +86 -183
  117. package/src/constants/subagents.ts +4 -0
  118. package/src/constants/tools.ts +4 -1
  119. package/src/index.ts +1 -0
  120. package/src/managers/aiManager.ts +63 -70
  121. package/src/managers/backgroundTaskManager.ts +58 -54
  122. package/src/managers/foregroundTaskManager.ts +3 -2
  123. package/src/managers/mcpManager.ts +6 -3
  124. package/src/managers/messageManager.ts +126 -142
  125. package/src/managers/permissionManager.ts +32 -21
  126. package/src/managers/planManager.ts +2 -2
  127. package/src/managers/reversionManager.ts +26 -2
  128. package/src/managers/slashCommandManager.ts +12 -3
  129. package/src/managers/subagentManager.ts +60 -144
  130. package/src/managers/toolManager.ts +32 -2
  131. package/src/prompts/index.ts +366 -0
  132. package/src/services/aiService.ts +3 -145
  133. package/src/services/memory.ts +0 -72
  134. package/src/services/session.ts +73 -0
  135. package/src/services/taskManager.ts +195 -0
  136. package/src/tools/askUserQuestion.ts +51 -29
  137. package/src/tools/bashTool.ts +15 -17
  138. package/src/tools/editTool.ts +3 -1
  139. package/src/tools/exitPlanMode.ts +27 -3
  140. package/src/tools/globTool.ts +10 -2
  141. package/src/tools/grepTool.ts +17 -6
  142. package/src/tools/lsTool.ts +3 -1
  143. package/src/tools/readTool.ts +17 -1
  144. package/src/tools/taskManagementTools.ts +516 -0
  145. package/src/tools/taskOutputTool.ts +34 -12
  146. package/src/tools/taskStopTool.ts +7 -1
  147. package/src/tools/taskTool.ts +45 -1
  148. package/src/tools/types.ts +12 -0
  149. package/src/tools/writeTool.ts +9 -2
  150. package/src/types/index.ts +1 -0
  151. package/src/types/messaging.ts +1 -21
  152. package/src/types/processes.ts +18 -7
  153. package/src/types/tasks.ts +13 -0
  154. package/src/types/tools.ts +4 -1
  155. package/src/utils/builtinSubagents.ts +81 -45
  156. package/src/utils/cacheControlUtils.ts +26 -18
  157. package/src/utils/constants.ts +0 -5
  158. package/src/utils/convertMessagesForAPI.ts +2 -2
  159. package/src/utils/editUtils.ts +2 -6
  160. package/src/utils/gitUtils.ts +24 -0
  161. package/src/utils/messageOperations.ts +6 -229
  162. package/src/utils/nameGenerator.ts +20 -3
  163. package/dist/constants/prompts.d.ts.map +0 -1
  164. package/dist/constants/prompts.js +0 -118
  165. package/dist/tools/todoWriteTool.d.ts +0 -6
  166. package/dist/tools/todoWriteTool.d.ts.map +0 -1
  167. package/dist/tools/todoWriteTool.js +0 -220
  168. package/src/constants/prompts.ts +0 -155
  169. package/src/tools/todoWriteTool.ts +0 -257
@@ -10,38 +10,47 @@ export const taskOutputTool: ToolPlugin = {
10
10
  type: "function",
11
11
  function: {
12
12
  name: TASK_OUTPUT_TOOL_NAME,
13
- description:
14
- "Retrieves output from a running or completed background task",
13
+ description: "Retrieves output from a running or completed task",
15
14
  parameters: {
16
15
  type: "object",
17
16
  properties: {
18
17
  task_id: {
19
18
  type: "string",
20
- description:
21
- "The ID of the background task to retrieve output from",
22
- },
23
- filter: {
24
- type: "string",
25
- description:
26
- "Optional regular expression to filter the output lines.",
19
+ description: "The task ID to get output from",
27
20
  },
28
21
  block: {
29
22
  type: "boolean",
30
- description:
31
- "If true, wait for the task to complete before returning output. If false, return current output immediately.",
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
32
  },
33
33
  },
34
34
  required: ["task_id"],
35
35
  },
36
36
  },
37
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`,
38
46
  execute: async (
39
47
  args: Record<string, unknown>,
40
48
  context: ToolContext,
41
49
  ): Promise<ToolResult> => {
42
50
  const taskId = args.task_id as string;
43
51
  const filter = args.filter as string | undefined;
44
- const block = args.block as boolean | undefined;
52
+ const block = (args.block as boolean | undefined) ?? true;
53
+ const timeout = (args.timeout as number | undefined) ?? 30000;
45
54
 
46
55
  if (!taskId || typeof taskId !== "string") {
47
56
  return {
@@ -91,6 +100,7 @@ export const taskOutputTool: ToolPlugin = {
91
100
  return new Promise((resolve) => {
92
101
  let timeoutHandle: NodeJS.Timeout | null = null;
93
102
  let isAborted = false;
103
+ const startTime = Date.now();
94
104
 
95
105
  const cleanup = () => {
96
106
  if (timeoutHandle) {
@@ -122,6 +132,18 @@ export const taskOutputTool: ToolPlugin = {
122
132
  const check = () => {
123
133
  if (isAborted) return;
124
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
+
125
147
  const task = backgroundTaskManager.getTask(taskId);
126
148
  if (!task) {
127
149
  if (context.abortSignal) {
@@ -7,7 +7,7 @@ export const taskStopTool: ToolPlugin = {
7
7
  type: "function",
8
8
  function: {
9
9
  name: TASK_STOP_TOOL_NAME,
10
- description: "Stops a running background task",
10
+ description: "Stop a running background task by ID",
11
11
  parameters: {
12
12
  type: "object",
13
13
  properties: {
@@ -20,6 +20,12 @@ export const taskStopTool: ToolPlugin = {
20
20
  },
21
21
  },
22
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
+ `,
23
29
  execute: async (
24
30
  args: Record<string, unknown>,
25
31
  context: ToolContext,
@@ -1,5 +1,6 @@
1
1
  import type { ToolPlugin, ToolResult, ToolContext } from "./types.js";
2
2
  import type { SubagentManager } from "../managers/subagentManager.js";
3
+ import { EXPLORE_SUBAGENT_TYPE } from "../constants/subagents.js";
3
4
  import { TASK_TOOL_NAME } from "../constants/tools.js";
4
5
 
5
6
  /**
@@ -58,6 +59,11 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
58
59
  };
59
60
  },
60
61
 
62
+ prompt: () => `
63
+ - When doing file search, prefer to use the ${TASK_TOOL_NAME} tool in order to reduce context usage.
64
+ - You should proactively use the ${TASK_TOOL_NAME} tool with specialized agents when the task at hand matches the agent's description.
65
+ - 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.`,
66
+
61
67
  execute: async (
62
68
  args: Record<string, unknown>,
63
69
  context: ToolContext,
@@ -115,6 +121,36 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
115
121
  });
116
122
  }
117
123
 
124
+ // Set up callback to update shortResult with tool names, tool count and tokens
125
+ const updateShortResult = () => {
126
+ const messages = instance.messageManager.getMessages();
127
+ const tokens = instance.messageManager.getlatestTotalTokens();
128
+ const lastTools = instance.lastTools;
129
+
130
+ // Count tool blocks in messages
131
+ let toolCount = 0;
132
+ messages.forEach((msg) => {
133
+ msg.blocks.forEach((block) => {
134
+ if (block.type === "tool") {
135
+ toolCount++;
136
+ }
137
+ });
138
+ });
139
+
140
+ let shortResult = "";
141
+ if (lastTools.length > 0) {
142
+ shortResult += `${lastTools.join(", ")} `;
143
+ }
144
+
145
+ shortResult += `(${toolCount} tools`;
146
+ if (tokens > 0) {
147
+ shortResult += ` | ${tokens.toLocaleString()} tokens`;
148
+ }
149
+ shortResult += ")";
150
+
151
+ context.onShortResultUpdate?.(shortResult);
152
+ };
153
+
118
154
  // Create subagent instance and execute task
119
155
  const instance = await subagentManager.createInstance(
120
156
  configuration,
@@ -124,8 +160,12 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
124
160
  subagent_type,
125
161
  },
126
162
  run_in_background,
163
+ updateShortResult,
127
164
  );
128
165
 
166
+ // Initial update
167
+ updateShortResult();
168
+
129
169
  let isBackgrounded = false;
130
170
 
131
171
  // Register for backgrounding if not already in background
@@ -140,8 +180,9 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
140
180
  // Resolve the tool execution early so the main agent can continue
141
181
  resolve({
142
182
  success: true,
143
- content: `Task moved to background with ID: ${taskId}. Use TaskOutput to monitor progress.`,
183
+ content: `Task moved to background with ID: ${taskId}.`,
144
184
  shortResult: "Task backgrounded",
185
+ isManuallyBackgrounded: true,
145
186
  });
146
187
  },
147
188
  });
@@ -165,6 +206,9 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
165
206
  });
166
207
  }
167
208
 
209
+ // Cleanup subagent instance after task completion
210
+ subagentManager.cleanupInstance(instance.subagentId);
211
+
168
212
  return resolve({
169
213
  success: true,
170
214
  content: result,
@@ -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,6 +38,8 @@ 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 {
@@ -57,4 +63,10 @@ export interface ToolContext {
57
63
  messageId?: string;
58
64
  /** Foreground task manager for backgrounding tasks */
59
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;
70
+ /** Callback to update the short result of the current tool block */
71
+ onShortResultUpdate?: (shortResult: string) => void;
60
72
  }
@@ -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";
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import type { Usage } from "./core.js";
7
- import type { SubagentConfiguration } from "../utils/subagentParser.js";
8
7
 
9
8
  export enum MessageSource {
10
9
  USER = "user",
@@ -26,8 +25,6 @@ export type MessageBlock =
26
25
  | ImageBlock
27
26
  | CommandOutputBlock
28
27
  | CompressBlock
29
- | MemoryBlock
30
- | SubagentBlock
31
28
  | ReasoningBlock
32
29
  | FileHistoryBlock;
33
30
 
@@ -67,6 +64,7 @@ export interface ToolBlock {
67
64
  error?: string | Error;
68
65
  compactParams?: string; // Compact parameter display
69
66
  parametersChunk?: string; // Incremental parameter updates for streaming
67
+ isManuallyBackgrounded?: boolean; // Whether the tool was manually backgrounded by the user
70
68
  }
71
69
 
72
70
  export interface ImageBlock {
@@ -88,24 +86,6 @@ export interface CompressBlock {
88
86
  sessionId: string;
89
87
  }
90
88
 
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
- export interface SubagentBlock {
100
- type: "subagent";
101
- subagentId: string;
102
- subagentName: string;
103
- status: "active" | "completed" | "error" | "aborted";
104
- sessionId: string;
105
- configuration: SubagentConfiguration;
106
- runInBackground?: boolean;
107
- }
108
-
109
89
  export interface ReasoningBlock {
110
90
  type: "reasoning";
111
91
  content: string;
@@ -12,7 +12,7 @@ export type BackgroundTaskStatus =
12
12
  | "killed";
13
13
  export type BackgroundTaskType = "shell" | "subagent";
14
14
 
15
- export interface BackgroundTask {
15
+ export interface BackgroundTaskBase {
16
16
  id: string;
17
17
  type: BackgroundTaskType;
18
18
  status: BackgroundTaskStatus;
@@ -24,13 +24,29 @@ export interface BackgroundTask {
24
24
  stderr: string;
25
25
  exitCode?: number;
26
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
+ * Optional subagent ID associated with this task.
34
+ * Used for cleanup when the task is stopped.
35
+ */
36
+ subagentId?: string;
27
37
  }
28
38
 
29
- export interface BackgroundShell extends BackgroundTask {
39
+ export interface BackgroundShell extends BackgroundTaskBase {
30
40
  type: "shell";
31
41
  process: ChildProcess;
32
42
  }
33
43
 
44
+ export interface BackgroundSubagent extends BackgroundTaskBase {
45
+ type: "subagent";
46
+ }
47
+
48
+ export type BackgroundTask = BackgroundShell | BackgroundSubagent;
49
+
34
50
  export interface ForegroundTask {
35
51
  id: string;
36
52
  backgroundHandler: () => Promise<void>;
@@ -40,8 +56,3 @@ export interface IForegroundTaskManager {
40
56
  registerForegroundTask(task: ForegroundTask): void;
41
57
  unregisterForegroundTask(id: string): void;
42
58
  }
43
-
44
- export interface IForegroundTaskManager {
45
- registerForegroundTask(task: ForegroundTask): void;
46
- unregisterForegroundTask(id: string): void;
47
- }
@@ -0,0 +1,13 @@
1
+ export type TaskStatus = "pending" | "in_progress" | "completed" | "deleted";
2
+
3
+ export interface Task {
4
+ id: string;
5
+ subject: string;
6
+ description: string;
7
+ status: TaskStatus;
8
+ activeForm?: string;
9
+ owner?: string;
10
+ blocks: string[];
11
+ blockedBy: string[];
12
+ metadata: Record<string, unknown>;
13
+ }
@@ -8,7 +8,6 @@
8
8
  export interface AskUserQuestionOption {
9
9
  label: string;
10
10
  description?: string;
11
- isRecommended?: boolean;
12
11
  }
13
12
 
14
13
  export interface AskUserQuestion {
@@ -20,6 +19,10 @@ export interface AskUserQuestion {
20
19
 
21
20
  export interface AskUserQuestionInput {
22
21
  questions: AskUserQuestion[];
22
+ answers?: Record<string, string>;
23
+ metadata?: {
24
+ source?: string;
25
+ };
23
26
  }
24
27
 
25
28
  /**
@@ -1,4 +1,23 @@
1
- import { GENERAL_PURPOSE_SYSTEM_PROMPT } from "../constants/prompts.js";
1
+ import {
2
+ BASH_SUBAGENT_TYPE,
3
+ EXPLORE_SUBAGENT_TYPE,
4
+ PLAN_SUBAGENT_TYPE,
5
+ GENERAL_PURPOSE_SUBAGENT_TYPE,
6
+ } from "../constants/subagents.js";
7
+ import {
8
+ BASH_SUBAGENT_SYSTEM_PROMPT,
9
+ GENERAL_PURPOSE_SYSTEM_PROMPT,
10
+ PLAN_SUBAGENT_SYSTEM_PROMPT,
11
+ EXPLORE_SUBAGENT_SYSTEM_PROMPT,
12
+ } from "../prompts/index.js";
13
+ import {
14
+ BASH_TOOL_NAME,
15
+ GLOB_TOOL_NAME,
16
+ GREP_TOOL_NAME,
17
+ READ_TOOL_NAME,
18
+ LS_TOOL_NAME,
19
+ LSP_TOOL_NAME,
20
+ } from "../constants/tools.js";
2
21
  import type { SubagentConfiguration } from "./subagentParser.js";
3
22
 
4
23
  /**
@@ -7,23 +26,43 @@ import type { SubagentConfiguration } from "./subagentParser.js";
7
26
  */
8
27
  export function getBuiltinSubagents(): SubagentConfiguration[] {
9
28
  return [
29
+ createBashSubagent(),
10
30
  createExploreSubagent(),
11
31
  createGeneralPurposeSubagent(),
32
+ createPlanSubagent(),
12
33
  // Add more built-in subagents here as needed
13
34
  ];
14
35
  }
15
36
 
37
+ /**
38
+ * Create the Bash built-in subagent configuration
39
+ * Specialized for executing bash commands and git operations
40
+ */
41
+ function createBashSubagent(): SubagentConfiguration {
42
+ return {
43
+ name: BASH_SUBAGENT_TYPE,
44
+ description:
45
+ "Command execution specialist for running bash commands. Use this for git operations, command execution, and other terminal tasks.",
46
+ systemPrompt: BASH_SUBAGENT_SYSTEM_PROMPT,
47
+ tools: [BASH_TOOL_NAME],
48
+ model: "inherit",
49
+ filePath: `<builtin:${BASH_SUBAGENT_TYPE}>`,
50
+ scope: "builtin",
51
+ priority: 3,
52
+ };
53
+ }
54
+
16
55
  /**
17
56
  * Create the General-Purpose built-in subagent configuration
18
57
  * Specialized for multi-step research and implementation tasks
19
58
  */
20
59
  function createGeneralPurposeSubagent(): SubagentConfiguration {
21
60
  return {
22
- name: "general-purpose",
61
+ name: GENERAL_PURPOSE_SUBAGENT_TYPE,
23
62
  description:
24
63
  "General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you.",
25
64
  systemPrompt: GENERAL_PURPOSE_SYSTEM_PROMPT,
26
- filePath: "<builtin:general-purpose>",
65
+ filePath: `<builtin:${GENERAL_PURPOSE_SUBAGENT_TYPE}>`,
27
66
  scope: "builtin",
28
67
  priority: 3,
29
68
  };
@@ -34,55 +73,52 @@ function createGeneralPurposeSubagent(): SubagentConfiguration {
34
73
  * Specialized for codebase exploration and file search tasks
35
74
  */
36
75
  function createExploreSubagent(): SubagentConfiguration {
37
- const systemPrompt = `You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
38
-
39
- === CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
40
- This is a READ-ONLY exploration task. You are STRICTLY PROHIBITED from:
41
- - Creating new files (no Write, touch, or file creation of any kind)
42
- - Modifying existing files (no Edit operations)
43
- - Deleting files (no rm or deletion)
44
- - Moving or copying files (no mv or cp)
45
- - Creating temporary files anywhere, including /tmp
46
- - Using redirect operators (>, >>, |) or heredocs to write to files
47
- - Running ANY commands that change system state
48
-
49
- Your role is EXCLUSIVELY to search and analyze existing code. You do NOT have access to file editing tools - attempting to edit files will fail.
50
-
51
- Your strengths:
52
- - Rapidly finding files using glob patterns
53
- - Searching code and text with powerful regex patterns
54
- - Reading and analyzing file contents
55
- - Using Language Server Protocol (LSP) for deep code intelligence (definitions, references, etc.)
56
-
57
- Guidelines:
58
- - Use Glob for broad file pattern matching
59
- - Use Grep for searching file contents with regex
60
- - Use Read when you know the specific file path you need to read
61
- - Use LSP for code intelligence features like finding definitions, references, implementations, and symbols. This is especially useful for understanding complex code relationships.
62
- - Use Bash ONLY for read-only operations (ls, git status, git log, git diff, find, cat, head, tail)
63
- - NEVER use Bash for: mkdir, touch, rm, cp, mv, git add, git commit, npm install, pip install, or any file creation/modification
64
- - Adapt your search approach based on the thoroughness level specified by the caller
65
- - Return file paths as absolute paths in your final response
66
- - For clear communication, avoid using emojis
67
- - Communicate your final report directly as a regular message - do NOT attempt to create files
68
-
69
- NOTE: You are meant to be a fast agent that returns output as quickly as possible. In order to achieve this you must:
70
- - Make efficient use of the tools that you have at your disposal: be smart about how you search for files and implementations
71
- - Wherever possible you should try to spawn multiple parallel tool calls for grepping and reading files
72
-
73
- Complete the user's search request efficiently and report your findings clearly.`;
74
-
75
76
  // Define allowed tools for read-only operations
76
- const allowedTools = ["Glob", "Grep", "Read", "Bash", "LS", "LSP"];
77
+ const allowedTools = [
78
+ GLOB_TOOL_NAME,
79
+ GREP_TOOL_NAME,
80
+ READ_TOOL_NAME,
81
+ BASH_TOOL_NAME,
82
+ LS_TOOL_NAME,
83
+ LSP_TOOL_NAME,
84
+ ];
77
85
 
78
86
  return {
79
- name: "Explore",
87
+ name: EXPLORE_SUBAGENT_TYPE,
80
88
  description:
81
89
  'Fast agent specialized for exploring codebases. Use this when you need to quickly find files by patterns (eg. "src/components/**/*.tsx"), search code for keywords (eg. "API endpoints"), or answer questions about the codebase (eg. "how do API endpoints work?"). When calling this agent, specify the desired thoroughness level: "quick" for basic searches, "medium" for moderate exploration, or "very thorough" for comprehensive analysis across multiple locations and naming conventions.',
82
- systemPrompt,
90
+ systemPrompt: EXPLORE_SUBAGENT_SYSTEM_PROMPT,
83
91
  tools: allowedTools,
84
92
  model: "fastModel", // Special value that will use parent's fastModel
85
- filePath: "<builtin:Explore>",
93
+ filePath: `<builtin:${EXPLORE_SUBAGENT_TYPE}>`,
94
+ scope: "builtin",
95
+ priority: 3, // Lowest priority - can be overridden by user configs
96
+ };
97
+ }
98
+
99
+ /**
100
+ * Create the Plan built-in subagent configuration
101
+ * Specialized for designing implementation plans and exploring codebases in read-only mode
102
+ */
103
+ function createPlanSubagent(): SubagentConfiguration {
104
+ // Define allowed tools for read-only operations
105
+ const allowedTools = [
106
+ GLOB_TOOL_NAME,
107
+ GREP_TOOL_NAME,
108
+ READ_TOOL_NAME,
109
+ BASH_TOOL_NAME,
110
+ LS_TOOL_NAME,
111
+ LSP_TOOL_NAME,
112
+ ];
113
+
114
+ return {
115
+ name: PLAN_SUBAGENT_TYPE,
116
+ description:
117
+ "Software architect agent for designing implementation plans. Use this when you need to plan the implementation strategy for a task. Returns step-by-step plans, identifies critical files, and considers architectural trade-offs.",
118
+ systemPrompt: PLAN_SUBAGENT_SYSTEM_PROMPT,
119
+ tools: allowedTools,
120
+ model: "inherit", // Uses parent agent's model
121
+ filePath: `<builtin:${PLAN_SUBAGENT_TYPE}>`,
86
122
  scope: "builtin",
87
123
  priority: 3, // Lowest priority - can be overridden by user configs
88
124
  };
@@ -316,14 +316,8 @@ export function transformMessagesForClaudeCache(
316
316
  // Find the latest interval message index (20th, 40th, 60th, etc.)
317
317
  const intervalMessageIndex = findIntervalMessageIndex(messages);
318
318
 
319
- // Find last system message index
320
- let lastSystemIndex = -1;
321
- for (let i = messages.length - 1; i >= 0; i--) {
322
- if (messages[i].role === "system") {
323
- lastSystemIndex = i;
324
- break;
325
- }
326
- }
319
+ // Find first system message index
320
+ const firstSystemIndex = messages.findIndex((m) => m.role === "system");
327
321
 
328
322
  const result = messages.map((message, index) => {
329
323
  // Validate message structure
@@ -332,14 +326,27 @@ export function transformMessagesForClaudeCache(
332
326
  return message; // Return as-is to avoid breaking the flow
333
327
  }
334
328
 
335
- // Last system message: always cached (hardcoded)
336
- if (message.role === "system" && index === lastSystemIndex) {
329
+ // First system message: always cached (hardcoded)
330
+ if (message.role === "system" && index === firstSystemIndex) {
331
+ const content =
332
+ (message.content as string | ChatCompletionContentPart[]) || "";
333
+ // If content is already an array, check if it already has cache control
334
+ if (Array.isArray(content)) {
335
+ const hasCacheControl = content.some(
336
+ (part) =>
337
+ part.type === "text" &&
338
+ (part as ClaudeChatCompletionContentPartText).cache_control,
339
+ );
340
+ if (hasCacheControl) {
341
+ return message;
342
+ }
343
+ }
344
+
345
+ const transformedContent = addCacheControlToContent(content, true);
346
+
337
347
  return {
338
348
  ...message,
339
- content: addCacheControlToContent(
340
- (message.content as string | ChatCompletionContentPart[]) || "",
341
- true,
342
- ),
349
+ content: transformedContent,
343
350
  } as ChatCompletionMessageParam;
344
351
  }
345
352
 
@@ -364,12 +371,13 @@ export function transformMessagesForClaudeCache(
364
371
  } as ChatCompletionMessageParam;
365
372
  } else {
366
373
  // For other message types without tool calls, cache the content
374
+ const content =
375
+ (message.content as string | ChatCompletionContentPart[]) || "";
376
+ const transformedContent = addCacheControlToContent(content, true);
377
+
367
378
  return {
368
379
  ...message,
369
- content: addCacheControlToContent(
370
- (message.content as string | ChatCompletionContentPart[]) || "",
371
- true,
372
- ),
380
+ content: transformedContent,
373
381
  } as ChatCompletionMessageParam;
374
382
  }
375
383
  }
@@ -31,8 +31,3 @@ export const USER_MEMORY_FILE = path.join(DATA_DIRECTORY, "AGENTS.md");
31
31
  */
32
32
  export const DEFAULT_WAVE_MAX_INPUT_TOKENS = 96000; // Default token limit
33
33
  export const DEFAULT_WAVE_MAX_OUTPUT_TOKENS = 8192; // Default output token limit
34
-
35
- /**
36
- * Default number of messages to keep uncompressed
37
- */
38
- export const DEFAULT_KEEP_LAST_MESSAGES_COUNT = 7;
@@ -57,8 +57,8 @@ export function convertMessagesForAPI(
57
57
  );
58
58
  if (compressBlock && compressBlock.type === "compress") {
59
59
  recentMessages.unshift({
60
- role: "system",
61
- content: `[Compressed Message Summary] ${compressBlock.content}`,
60
+ role: "assistant",
61
+ content: compressBlock.content,
62
62
  });
63
63
  }
64
64
  break;
@@ -77,12 +77,8 @@ export function analyzeEditMismatch(
77
77
  if (actualLine === expectedLine) {
78
78
  reportLines.push(`${lineNum.toString().padStart(4)} | ${actualLine}`);
79
79
  } else {
80
- reportLines.push(
81
- `${lineNum.toString().padStart(4)} | - ${expectedLine} (expected)`,
82
- );
83
- reportLines.push(
84
- `${lineNum.toString().padStart(4)} | + ${actualLine} (actual)`,
85
- );
80
+ reportLines.push(`${lineNum.toString().padStart(4)} | - ${expectedLine}`);
81
+ reportLines.push(`${lineNum.toString().padStart(4)} | + ${actualLine}`);
86
82
  }
87
83
  }
88
84