wave-agent-sdk 0.6.1 → 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.
- package/dist/agent.d.ts +0 -5
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +3 -67
- package/dist/constants/subagents.d.ts +5 -0
- package/dist/constants/subagents.d.ts.map +1 -0
- package/dist/constants/subagents.js +4 -0
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +9 -25
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +4 -0
- package/dist/managers/messageManager.d.ts +0 -18
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +1 -36
- package/dist/managers/reversionManager.d.ts.map +1 -1
- package/dist/managers/reversionManager.js +23 -2
- package/dist/managers/slashCommandManager.js +1 -1
- package/dist/managers/subagentManager.d.ts +4 -14
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +35 -109
- package/dist/{constants/prompts.d.ts → prompts/index.d.ts} +4 -6
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/{constants/prompts.js → prompts/index.js} +124 -9
- package/dist/services/aiService.js +1 -1
- package/dist/services/taskManager.d.ts +5 -1
- package/dist/services/taskManager.d.ts.map +1 -1
- package/dist/services/taskManager.js +6 -0
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +6 -2
- package/dist/tools/exitPlanMode.js +1 -1
- package/dist/tools/taskManagementTools.d.ts.map +1 -1
- package/dist/tools/taskManagementTools.js +8 -0
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +32 -2
- package/dist/tools/types.d.ts +2 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/messaging.d.ts +1 -11
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/processes.d.ts +5 -0
- package/dist/types/processes.d.ts.map +1 -1
- package/dist/utils/builtinSubagents.d.ts.map +1 -1
- package/dist/utils/builtinSubagents.js +28 -50
- package/dist/utils/editUtils.d.ts.map +1 -1
- package/dist/utils/editUtils.js +2 -2
- package/dist/utils/gitUtils.d.ts +7 -0
- package/dist/utils/gitUtils.d.ts.map +1 -0
- package/dist/utils/gitUtils.js +24 -0
- package/dist/utils/messageOperations.d.ts +1 -23
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +0 -49
- package/package.json +1 -1
- package/src/agent.ts +3 -89
- package/src/constants/subagents.ts +4 -0
- package/src/managers/aiManager.ts +9 -25
- package/src/managers/backgroundTaskManager.ts +5 -0
- package/src/managers/messageManager.ts +0 -80
- package/src/managers/reversionManager.ts +26 -2
- package/src/managers/slashCommandManager.ts +1 -1
- package/src/managers/subagentManager.ts +42 -145
- package/src/{constants/prompts.ts → prompts/index.ts} +132 -12
- package/src/services/aiService.ts +1 -1
- package/src/services/taskManager.ts +8 -1
- package/src/tools/bashTool.ts +6 -2
- package/src/tools/exitPlanMode.ts +1 -1
- package/src/tools/taskManagementTools.ts +18 -0
- package/src/tools/taskTool.ts +39 -1
- package/src/tools/types.ts +2 -0
- package/src/types/messaging.ts +0 -12
- package/src/types/processes.ts +5 -0
- package/src/utils/builtinSubagents.ts +41 -51
- package/src/utils/editUtils.ts +2 -6
- package/src/utils/gitUtils.ts +24 -0
- package/src/utils/messageOperations.ts +1 -93
- package/dist/constants/prompts.d.ts.map +0 -1
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
import * as os from "node:os";
|
|
1
2
|
import { ToolPlugin } from "../tools/types.js";
|
|
3
|
+
import { isGitRepository } from "../utils/gitUtils.js";
|
|
4
|
+
import {
|
|
5
|
+
EXPLORE_SUBAGENT_TYPE,
|
|
6
|
+
PLAN_SUBAGENT_TYPE,
|
|
7
|
+
} from "../constants/subagents.js";
|
|
2
8
|
import {
|
|
3
9
|
ASK_USER_QUESTION_TOOL_NAME,
|
|
4
10
|
BASH_TOOL_NAME,
|
|
@@ -11,7 +17,8 @@ import {
|
|
|
11
17
|
TASK_UPDATE_TOOL_NAME,
|
|
12
18
|
TASK_LIST_TOOL_NAME,
|
|
13
19
|
WRITE_TOOL_NAME,
|
|
14
|
-
|
|
20
|
+
EXIT_PLAN_MODE_TOOL_NAME,
|
|
21
|
+
} from "../constants/tools.js";
|
|
15
22
|
|
|
16
23
|
export const BASE_SYSTEM_PROMPT = `You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
|
17
24
|
|
|
@@ -39,17 +46,90 @@ It is critical that you mark tasks as completed as soon as you are done with a t
|
|
|
39
46
|
export function buildPlanModePrompt(
|
|
40
47
|
planFilePath: string,
|
|
41
48
|
planExists: boolean,
|
|
49
|
+
isSubagent: boolean = false,
|
|
42
50
|
): string {
|
|
43
51
|
const planFileInfo = planExists
|
|
44
52
|
? `A plan file already exists at ${planFilePath}. You can read it and make incremental edits using the ${EDIT_TOOL_NAME} tool if you need to.`
|
|
45
53
|
: `No plan file exists yet. You should create your plan at ${planFilePath} using the ${WRITE_TOOL_NAME} tool if you need to.`;
|
|
46
54
|
|
|
47
|
-
|
|
55
|
+
if (isSubagent) {
|
|
56
|
+
return `Plan mode is active. The user indicated that they do not want you to execute yet -- you MUST NOT make any edits, run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supercedes any other instructions you have received (for example, to make edits). Instead, you should:
|
|
57
|
+
|
|
58
|
+
## Plan File Info:
|
|
59
|
+
${planFileInfo}
|
|
60
|
+
You should build your plan incrementally by writing to or editing this file. NOTE that this is the only file you are allowed to edit - other than this you are only allowed to take READ-ONLY actions.
|
|
61
|
+
Answer the user's query comprehensively, using the ${ASK_USER_QUESTION_TOOL_NAME} tool if you need to ask the user clarifying questions. If you do use the ${ASK_USER_QUESTION_TOOL_NAME}, make sure to ask all clarifying questions you need to fully understand the user's intent before proceeding.`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return `Plan mode is active. The user indicated that they do not want you to execute yet -- you MUST NOT make any edits (with the exception of the plan file mentioned below), run any non-readonly tools (including changing configs or making commits), or otherwise make any changes to the system. This supercedes any other instructions you have received.
|
|
48
65
|
|
|
49
66
|
## Plan File Info:
|
|
50
67
|
${planFileInfo}
|
|
51
68
|
You should build your plan incrementally by writing to or editing this file. NOTE that this is the only file you are allowed to edit - other than this you are only allowed to take READ-ONLY actions.
|
|
52
|
-
|
|
69
|
+
|
|
70
|
+
## Plan Workflow
|
|
71
|
+
|
|
72
|
+
### Phase 1: Initial Understanding
|
|
73
|
+
Goal: Gain a comprehensive understanding of the user's request by reading through code and asking them questions. Critical: In this phase you should only use the Task subagent type with subagent_type=${EXPLORE_SUBAGENT_TYPE}.
|
|
74
|
+
|
|
75
|
+
1. Focus on understanding the user's request and the code associated with their request. Actively search for existing functions, utilities, and patterns that can be reused — avoid proposing new code when suitable implementations already exist.
|
|
76
|
+
|
|
77
|
+
2. **Launch up to 3 ${EXPLORE_SUBAGENT_TYPE} agents IN PARALLEL** (single message, multiple tool calls) to efficiently explore the codebase.
|
|
78
|
+
- Use 1 agent when the task is isolated to known files, the user provided specific file paths, or you're making a small targeted change.
|
|
79
|
+
- Use multiple agents when: the scope is uncertain, multiple areas of the codebase are involved, or you need to understand existing patterns before planning.
|
|
80
|
+
- Quality over quantity - 3 agents maximum, but you should try to use the minimum number of agents necessary (usually just 1)
|
|
81
|
+
- If using multiple agents: Provide each agent with a specific search focus or area to explore. Example: One agent searches for existing implementations, another explores related components, a third investigating testing patterns
|
|
82
|
+
|
|
83
|
+
### Phase 2: Design
|
|
84
|
+
Goal: Design an implementation approach.
|
|
85
|
+
|
|
86
|
+
Launch Task agent(s) with subagent_type=${PLAN_SUBAGENT_TYPE} to design the implementation based on the user's intent and your exploration results from Phase 1.
|
|
87
|
+
|
|
88
|
+
You can launch up to 3 agent(s) in parallel.
|
|
89
|
+
|
|
90
|
+
**Guidelines:**
|
|
91
|
+
- **Default**: Launch at least 1 Plan agent for most tasks - it helps validate your understanding and consider alternatives
|
|
92
|
+
- **Skip agents**: Only for truly trivial tasks (typo fixes, single-line changes, simple renames)
|
|
93
|
+
- **Multiple agents**: Use up to 3 agents for complex tasks that benefit from different perspectives
|
|
94
|
+
|
|
95
|
+
Examples of when to use multiple agents:
|
|
96
|
+
- The task touches multiple parts of the codebase
|
|
97
|
+
- It's a large refactor or architectural change
|
|
98
|
+
- There are many edge cases to consider
|
|
99
|
+
- You'd benefit from exploring different approaches
|
|
100
|
+
|
|
101
|
+
Example perspectives by task type:
|
|
102
|
+
- New feature: simplicity vs performance vs maintainability
|
|
103
|
+
- Bug fix: root cause vs workaround vs prevention
|
|
104
|
+
- Refactoring: minimal change vs clean architecture
|
|
105
|
+
|
|
106
|
+
In the agent prompt:
|
|
107
|
+
- Provide comprehensive background context from Phase 1 exploration including filenames and code path traces
|
|
108
|
+
- Describe requirements and constraints
|
|
109
|
+
- Request a detailed implementation plan
|
|
110
|
+
|
|
111
|
+
### Phase 3: Review
|
|
112
|
+
Goal: Review the plan(s) from Phase 2 and ensure alignment with the user's intentions.
|
|
113
|
+
1. Read the critical files identified by agents to deepen your understanding
|
|
114
|
+
2. Ensure that the plans align with the user's original request
|
|
115
|
+
3. Use ${ASK_USER_QUESTION_TOOL_NAME} to clarify any remaining questions with the user
|
|
116
|
+
|
|
117
|
+
### Phase 4: Final Plan
|
|
118
|
+
Goal: Write your final plan to the plan file (the only file you can edit).
|
|
119
|
+
- Begin with a **Context** section: explain why this change is being made — the problem or need it addresses, what prompted it, and the intended outcome
|
|
120
|
+
- Include only your recommended approach, not all alternatives
|
|
121
|
+
- Ensure that the plan file is concise enough to scan quickly, but detailed enough to execute effectively
|
|
122
|
+
- Include the paths of critical files to be modified
|
|
123
|
+
- Reference existing functions and utilities you found that should be reused, with their file paths
|
|
124
|
+
- Include a verification section describing how to test the changes end-to-end (run the code, use MCP tools, run tests)
|
|
125
|
+
|
|
126
|
+
### Phase 5: Call ${EXIT_PLAN_MODE_TOOL_NAME}
|
|
127
|
+
At the very end of your turn, once you have asked the user questions and are happy with your final plan file - you should always call ${EXIT_PLAN_MODE_TOOL_NAME} to indicate to the user that you are done planning.
|
|
128
|
+
This is critical - your turn should only end with either using the ${ASK_USER_QUESTION_TOOL_NAME} tool OR calling ${EXIT_PLAN_MODE_TOOL_NAME}. Do not stop unless it's for these 2 reasons
|
|
129
|
+
|
|
130
|
+
**Important:** Use ${ASK_USER_QUESTION_TOOL_NAME} ONLY to clarify requirements or choose between approaches. Use ${EXIT_PLAN_MODE_TOOL_NAME} to request plan approval. Do NOT ask about plan approval in any other way - no text questions, no AskUserQuestion. Phrases like "Is this plan okay?", "Should I proceed?", "How does this plan look?", "Any changes before we start?", or similar MUST use ${EXIT_PLAN_MODE_TOOL_NAME}.
|
|
131
|
+
|
|
132
|
+
NOTE: At any point in time through this workflow you should feel free to ask the user questions or clarifications using the ${ASK_USER_QUESTION_TOOL_NAME} tool. Don't make large assumptions about user intent. The goal is to present a well researched plan to the user, and tie any loose ends before implementation begins.`;
|
|
53
133
|
}
|
|
54
134
|
|
|
55
135
|
export const DEFAULT_SYSTEM_PROMPT = BASE_SYSTEM_PROMPT;
|
|
@@ -84,6 +164,44 @@ Guidelines:
|
|
|
84
164
|
- In your final response always share relevant file names and code snippets. Any file paths you return in your response MUST be absolute. Do NOT use relative paths.
|
|
85
165
|
- For clear communication, avoid using emojis.`;
|
|
86
166
|
|
|
167
|
+
export const EXPLORE_SUBAGENT_SYSTEM_PROMPT = `You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
|
|
168
|
+
|
|
169
|
+
=== CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
|
|
170
|
+
This is a READ-ONLY exploration task. You are STRICTLY PROHIBITED from:
|
|
171
|
+
- Creating new files (no Write, touch, or file creation of any kind)
|
|
172
|
+
- Modifying existing files (no Edit operations)
|
|
173
|
+
- Deleting files (no rm or deletion)
|
|
174
|
+
- Moving or copying files (no mv or cp)
|
|
175
|
+
- Creating temporary files anywhere, including /tmp
|
|
176
|
+
- Using redirect operators (>, >>, |) or heredocs to write to files
|
|
177
|
+
- Running ANY commands that change system state
|
|
178
|
+
|
|
179
|
+
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.
|
|
180
|
+
|
|
181
|
+
Your strengths:
|
|
182
|
+
- Rapidly finding files using glob patterns
|
|
183
|
+
- Searching code and text with powerful regex patterns
|
|
184
|
+
- Reading and analyzing file contents
|
|
185
|
+
- Using Language Server Protocol (LSP) for deep code intelligence (definitions, references, etc.)
|
|
186
|
+
|
|
187
|
+
Guidelines:
|
|
188
|
+
- Use ${GLOB_TOOL_NAME} for broad file pattern matching
|
|
189
|
+
- Use ${GREP_TOOL_NAME} for searching file contents with regex
|
|
190
|
+
- Use ${READ_TOOL_NAME} when you know the specific file path you need to read
|
|
191
|
+
- Use LSP for code intelligence features like finding definitions, references, implementations, and symbols. This is especially useful for understanding complex code relationships.
|
|
192
|
+
- Use ${BASH_TOOL_NAME} ONLY for read-only operations (ls, git status, git log, git diff, find, cat, head, tail)
|
|
193
|
+
- NEVER use ${BASH_TOOL_NAME} for: mkdir, touch, rm, cp, mv, git add, git commit, npm install, pip install, or any file creation/modification
|
|
194
|
+
- Adapt your search approach based on the thoroughness level specified by the caller
|
|
195
|
+
- Return file paths as absolute paths in your final response
|
|
196
|
+
- For clear communication, avoid using emojis
|
|
197
|
+
- Communicate your final report directly as a regular message - do NOT attempt to create files
|
|
198
|
+
|
|
199
|
+
NOTE: You are meant to be a fast agent that returns output as quickly as possible. In order to achieve this you must:
|
|
200
|
+
- Make efficient use of the tools that you have at your disposal: be smart about how you search for files and implementations
|
|
201
|
+
- Wherever possible you should try to spawn multiple parallel tool calls for grepping and reading files
|
|
202
|
+
|
|
203
|
+
Complete the user's search request efficiently and report your findings clearly.`;
|
|
204
|
+
|
|
87
205
|
export const PLAN_SUBAGENT_SYSTEM_PROMPT = `You are a software architect and planning specialist. Your role is to explore the codebase and design implementation plans.
|
|
88
206
|
|
|
89
207
|
=== CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
|
|
@@ -186,12 +304,9 @@ export function buildSystemPrompt(
|
|
|
186
304
|
tools: ToolPlugin[],
|
|
187
305
|
options: {
|
|
188
306
|
workdir?: string;
|
|
189
|
-
isGitRepo?: string;
|
|
190
|
-
platform?: string;
|
|
191
|
-
osVersion?: string;
|
|
192
|
-
today?: string;
|
|
193
307
|
memory?: string;
|
|
194
308
|
language?: string;
|
|
309
|
+
isSubagent?: boolean;
|
|
195
310
|
planMode?: {
|
|
196
311
|
planFilePath: string;
|
|
197
312
|
planExists: boolean;
|
|
@@ -221,19 +336,24 @@ export function buildSystemPrompt(
|
|
|
221
336
|
}
|
|
222
337
|
|
|
223
338
|
if (options.planMode) {
|
|
224
|
-
prompt += `\n\n${buildPlanModePrompt(options.planMode.planFilePath, options.planMode.planExists)}`;
|
|
339
|
+
prompt += `\n\n${buildPlanModePrompt(options.planMode.planFilePath, options.planMode.planExists, options.isSubagent)}`;
|
|
225
340
|
}
|
|
226
341
|
|
|
227
342
|
if (options.workdir) {
|
|
343
|
+
const isGitRepo = isGitRepository(options.workdir);
|
|
344
|
+
const platform = os.platform();
|
|
345
|
+
const osVersion = `${os.type()} ${os.release()}`;
|
|
346
|
+
const today = new Date().toISOString().split("T")[0];
|
|
347
|
+
|
|
228
348
|
prompt += `
|
|
229
349
|
|
|
230
350
|
Here is useful information about the environment you are running in:
|
|
231
351
|
<env>
|
|
232
352
|
Working directory: ${options.workdir}
|
|
233
|
-
Is directory a git repo: ${
|
|
234
|
-
Platform: ${
|
|
235
|
-
OS Version: ${
|
|
236
|
-
Today's date: ${
|
|
353
|
+
Is directory a git repo: ${isGitRepo}
|
|
354
|
+
Platform: ${platform}
|
|
355
|
+
OS Version: ${osVersion}
|
|
356
|
+
Today's date: ${today}
|
|
237
357
|
</env>
|
|
238
358
|
`;
|
|
239
359
|
}
|
|
@@ -21,7 +21,7 @@ import * as os from "os";
|
|
|
21
21
|
import * as fs from "fs";
|
|
22
22
|
import * as path from "path";
|
|
23
23
|
|
|
24
|
-
import { COMPRESS_MESSAGES_SYSTEM_PROMPT } from "../
|
|
24
|
+
import { COMPRESS_MESSAGES_SYSTEM_PROMPT } from "../prompts/index.js";
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Interface for debug data saved during 400 errors
|
|
@@ -27,7 +27,7 @@ export class TaskManager extends EventEmitter {
|
|
|
27
27
|
return join(this.baseDir, this.taskListId);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
public getTaskPath(taskId: string): string {
|
|
31
31
|
return join(this.getSessionDir(), `${taskId}.json`);
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -185,4 +185,11 @@ export class TaskManager extends EventEmitter {
|
|
|
185
185
|
|
|
186
186
|
return (Math.max(...ids) + 1).toString();
|
|
187
187
|
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Refreshes the task list by re-reading tasks from disk and emitting a change event.
|
|
191
|
+
*/
|
|
192
|
+
public async refreshTasks(): Promise<void> {
|
|
193
|
+
this.emit("tasksChange", this.taskListId);
|
|
194
|
+
}
|
|
188
195
|
}
|
package/src/tools/bashTool.ts
CHANGED
|
@@ -306,13 +306,17 @@ Usage notes:
|
|
|
306
306
|
|
|
307
307
|
child.stdout?.on("data", (data) => {
|
|
308
308
|
if (!isAborted && !isBackgrounded) {
|
|
309
|
-
|
|
309
|
+
const chunk = stripAnsiColors(data.toString());
|
|
310
|
+
outputBuffer += chunk;
|
|
311
|
+
context.onShortResultUpdate?.(chunk.trim().split("\n").pop() || "");
|
|
310
312
|
}
|
|
311
313
|
});
|
|
312
314
|
|
|
313
315
|
child.stderr?.on("data", (data) => {
|
|
314
316
|
if (!isAborted && !isBackgrounded) {
|
|
315
|
-
|
|
317
|
+
const chunk = stripAnsiColors(data.toString());
|
|
318
|
+
errorBuffer += chunk;
|
|
319
|
+
context.onShortResultUpdate?.(chunk.trim().split("\n").pop() || "");
|
|
316
320
|
}
|
|
317
321
|
});
|
|
318
322
|
|
|
@@ -93,7 +93,7 @@ Ensure your plan is complete and unambiguous:
|
|
|
93
93
|
if (permissionResult.behavior === "deny") {
|
|
94
94
|
return {
|
|
95
95
|
success: false,
|
|
96
|
-
content: permissionResult.message || "Plan rejected by user"
|
|
96
|
+
content: `User feedback: ${permissionResult.message || "Plan rejected by user"}. Please update your proposal accordingly.`,
|
|
97
97
|
error: permissionResult.message ? undefined : "Plan rejected by user",
|
|
98
98
|
};
|
|
99
99
|
}
|
|
@@ -114,6 +114,15 @@ NOTE that you should not use this tool if there is only one trivial task to do.
|
|
|
114
114
|
|
|
115
115
|
const taskId = await taskManager.createTask(task);
|
|
116
116
|
|
|
117
|
+
if (context.reversionManager && context.messageId) {
|
|
118
|
+
const taskPath = taskManager.getTaskPath(taskId);
|
|
119
|
+
await context.reversionManager.recordSnapshot(
|
|
120
|
+
context.messageId,
|
|
121
|
+
taskPath,
|
|
122
|
+
"create",
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
117
126
|
return {
|
|
118
127
|
success: true,
|
|
119
128
|
content: `Task created with ID: ${taskId}`,
|
|
@@ -324,6 +333,15 @@ Set up task dependencies:
|
|
|
324
333
|
};
|
|
325
334
|
}
|
|
326
335
|
|
|
336
|
+
if (context.reversionManager && context.messageId) {
|
|
337
|
+
const taskPath = taskManager.getTaskPath(taskId);
|
|
338
|
+
await context.reversionManager.recordSnapshot(
|
|
339
|
+
context.messageId,
|
|
340
|
+
taskPath,
|
|
341
|
+
"modify",
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
|
|
327
345
|
const updatedFields: string[] = [];
|
|
328
346
|
|
|
329
347
|
const updatedTask: Task = {
|
package/src/tools/taskTool.ts
CHANGED
|
@@ -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
|
/**
|
|
@@ -61,7 +62,7 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
|
|
|
61
62
|
prompt: () => `
|
|
62
63
|
- When doing file search, prefer to use the ${TASK_TOOL_NAME} tool in order to reduce context usage.
|
|
63
64
|
- 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
|
|
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.`,
|
|
65
66
|
|
|
66
67
|
execute: async (
|
|
67
68
|
args: Record<string, unknown>,
|
|
@@ -120,6 +121,36 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
|
|
|
120
121
|
});
|
|
121
122
|
}
|
|
122
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
|
+
|
|
123
154
|
// Create subagent instance and execute task
|
|
124
155
|
const instance = await subagentManager.createInstance(
|
|
125
156
|
configuration,
|
|
@@ -129,8 +160,12 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
|
|
|
129
160
|
subagent_type,
|
|
130
161
|
},
|
|
131
162
|
run_in_background,
|
|
163
|
+
updateShortResult,
|
|
132
164
|
);
|
|
133
165
|
|
|
166
|
+
// Initial update
|
|
167
|
+
updateShortResult();
|
|
168
|
+
|
|
134
169
|
let isBackgrounded = false;
|
|
135
170
|
|
|
136
171
|
// Register for backgrounding if not already in background
|
|
@@ -171,6 +206,9 @@ export function createTaskTool(subagentManager: SubagentManager): ToolPlugin {
|
|
|
171
206
|
});
|
|
172
207
|
}
|
|
173
208
|
|
|
209
|
+
// Cleanup subagent instance after task completion
|
|
210
|
+
subagentManager.cleanupInstance(instance.subagentId);
|
|
211
|
+
|
|
174
212
|
return resolve({
|
|
175
213
|
success: true,
|
|
176
214
|
content: result,
|
package/src/tools/types.ts
CHANGED
|
@@ -67,4 +67,6 @@ export interface ToolContext {
|
|
|
67
67
|
taskManager: import("../services/taskManager.js").TaskManager;
|
|
68
68
|
/** Current session ID */
|
|
69
69
|
sessionId?: string;
|
|
70
|
+
/** Callback to update the short result of the current tool block */
|
|
71
|
+
onShortResultUpdate?: (shortResult: string) => void;
|
|
70
72
|
}
|
package/src/types/messaging.ts
CHANGED
|
@@ -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,7 +25,6 @@ export type MessageBlock =
|
|
|
26
25
|
| ImageBlock
|
|
27
26
|
| CommandOutputBlock
|
|
28
27
|
| CompressBlock
|
|
29
|
-
| SubagentBlock
|
|
30
28
|
| ReasoningBlock
|
|
31
29
|
| FileHistoryBlock;
|
|
32
30
|
|
|
@@ -88,16 +86,6 @@ export interface CompressBlock {
|
|
|
88
86
|
sessionId: string;
|
|
89
87
|
}
|
|
90
88
|
|
|
91
|
-
export interface SubagentBlock {
|
|
92
|
-
type: "subagent";
|
|
93
|
-
subagentId: string;
|
|
94
|
-
subagentName: string;
|
|
95
|
-
status: "active" | "completed" | "error" | "aborted";
|
|
96
|
-
sessionId: string;
|
|
97
|
-
configuration: SubagentConfiguration;
|
|
98
|
-
runInBackground?: boolean;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
89
|
export interface ReasoningBlock {
|
|
102
90
|
type: "reasoning";
|
|
103
91
|
content: string;
|
package/src/types/processes.ts
CHANGED
|
@@ -29,6 +29,11 @@ export interface BackgroundTaskBase {
|
|
|
29
29
|
* This allows tasks to define their own cleanup/abortion logic.
|
|
30
30
|
*/
|
|
31
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;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
export interface BackgroundShell extends BackgroundTaskBase {
|
|
@@ -1,9 +1,23 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BASH_SUBAGENT_TYPE,
|
|
3
|
+
EXPLORE_SUBAGENT_TYPE,
|
|
4
|
+
PLAN_SUBAGENT_TYPE,
|
|
5
|
+
GENERAL_PURPOSE_SUBAGENT_TYPE,
|
|
6
|
+
} from "../constants/subagents.js";
|
|
1
7
|
import {
|
|
2
8
|
BASH_SUBAGENT_SYSTEM_PROMPT,
|
|
3
9
|
GENERAL_PURPOSE_SYSTEM_PROMPT,
|
|
4
10
|
PLAN_SUBAGENT_SYSTEM_PROMPT,
|
|
5
|
-
|
|
6
|
-
|
|
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";
|
|
7
21
|
import type { SubagentConfiguration } from "./subagentParser.js";
|
|
8
22
|
|
|
9
23
|
/**
|
|
@@ -26,13 +40,13 @@ export function getBuiltinSubagents(): SubagentConfiguration[] {
|
|
|
26
40
|
*/
|
|
27
41
|
function createBashSubagent(): SubagentConfiguration {
|
|
28
42
|
return {
|
|
29
|
-
name:
|
|
43
|
+
name: BASH_SUBAGENT_TYPE,
|
|
30
44
|
description:
|
|
31
45
|
"Command execution specialist for running bash commands. Use this for git operations, command execution, and other terminal tasks.",
|
|
32
46
|
systemPrompt: BASH_SUBAGENT_SYSTEM_PROMPT,
|
|
33
47
|
tools: [BASH_TOOL_NAME],
|
|
34
48
|
model: "inherit",
|
|
35
|
-
filePath:
|
|
49
|
+
filePath: `<builtin:${BASH_SUBAGENT_TYPE}>`,
|
|
36
50
|
scope: "builtin",
|
|
37
51
|
priority: 3,
|
|
38
52
|
};
|
|
@@ -44,11 +58,11 @@ function createBashSubagent(): SubagentConfiguration {
|
|
|
44
58
|
*/
|
|
45
59
|
function createGeneralPurposeSubagent(): SubagentConfiguration {
|
|
46
60
|
return {
|
|
47
|
-
name:
|
|
61
|
+
name: GENERAL_PURPOSE_SUBAGENT_TYPE,
|
|
48
62
|
description:
|
|
49
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.",
|
|
50
64
|
systemPrompt: GENERAL_PURPOSE_SYSTEM_PROMPT,
|
|
51
|
-
filePath:
|
|
65
|
+
filePath: `<builtin:${GENERAL_PURPOSE_SUBAGENT_TYPE}>`,
|
|
52
66
|
scope: "builtin",
|
|
53
67
|
priority: 3,
|
|
54
68
|
};
|
|
@@ -59,55 +73,24 @@ function createGeneralPurposeSubagent(): SubagentConfiguration {
|
|
|
59
73
|
* Specialized for codebase exploration and file search tasks
|
|
60
74
|
*/
|
|
61
75
|
function createExploreSubagent(): SubagentConfiguration {
|
|
62
|
-
const systemPrompt = `You are a file search specialist. You excel at thoroughly navigating and exploring codebases.
|
|
63
|
-
|
|
64
|
-
=== CRITICAL: READ-ONLY MODE - NO FILE MODIFICATIONS ===
|
|
65
|
-
This is a READ-ONLY exploration task. You are STRICTLY PROHIBITED from:
|
|
66
|
-
- Creating new files (no Write, touch, or file creation of any kind)
|
|
67
|
-
- Modifying existing files (no Edit operations)
|
|
68
|
-
- Deleting files (no rm or deletion)
|
|
69
|
-
- Moving or copying files (no mv or cp)
|
|
70
|
-
- Creating temporary files anywhere, including /tmp
|
|
71
|
-
- Using redirect operators (>, >>, |) or heredocs to write to files
|
|
72
|
-
- Running ANY commands that change system state
|
|
73
|
-
|
|
74
|
-
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.
|
|
75
|
-
|
|
76
|
-
Your strengths:
|
|
77
|
-
- Rapidly finding files using glob patterns
|
|
78
|
-
- Searching code and text with powerful regex patterns
|
|
79
|
-
- Reading and analyzing file contents
|
|
80
|
-
- Using Language Server Protocol (LSP) for deep code intelligence (definitions, references, etc.)
|
|
81
|
-
|
|
82
|
-
Guidelines:
|
|
83
|
-
- Use Glob for broad file pattern matching
|
|
84
|
-
- Use Grep for searching file contents with regex
|
|
85
|
-
- Use Read when you know the specific file path you need to read
|
|
86
|
-
- Use LSP for code intelligence features like finding definitions, references, implementations, and symbols. This is especially useful for understanding complex code relationships.
|
|
87
|
-
- Use Bash ONLY for read-only operations (ls, git status, git log, git diff, find, cat, head, tail)
|
|
88
|
-
- NEVER use Bash for: mkdir, touch, rm, cp, mv, git add, git commit, npm install, pip install, or any file creation/modification
|
|
89
|
-
- Adapt your search approach based on the thoroughness level specified by the caller
|
|
90
|
-
- Return file paths as absolute paths in your final response
|
|
91
|
-
- For clear communication, avoid using emojis
|
|
92
|
-
- Communicate your final report directly as a regular message - do NOT attempt to create files
|
|
93
|
-
|
|
94
|
-
NOTE: You are meant to be a fast agent that returns output as quickly as possible. In order to achieve this you must:
|
|
95
|
-
- Make efficient use of the tools that you have at your disposal: be smart about how you search for files and implementations
|
|
96
|
-
- Wherever possible you should try to spawn multiple parallel tool calls for grepping and reading files
|
|
97
|
-
|
|
98
|
-
Complete the user's search request efficiently and report your findings clearly.`;
|
|
99
|
-
|
|
100
76
|
// Define allowed tools for read-only operations
|
|
101
|
-
const allowedTools = [
|
|
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
|
+
];
|
|
102
85
|
|
|
103
86
|
return {
|
|
104
|
-
name:
|
|
87
|
+
name: EXPLORE_SUBAGENT_TYPE,
|
|
105
88
|
description:
|
|
106
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.',
|
|
107
|
-
systemPrompt,
|
|
90
|
+
systemPrompt: EXPLORE_SUBAGENT_SYSTEM_PROMPT,
|
|
108
91
|
tools: allowedTools,
|
|
109
92
|
model: "fastModel", // Special value that will use parent's fastModel
|
|
110
|
-
filePath:
|
|
93
|
+
filePath: `<builtin:${EXPLORE_SUBAGENT_TYPE}>`,
|
|
111
94
|
scope: "builtin",
|
|
112
95
|
priority: 3, // Lowest priority - can be overridden by user configs
|
|
113
96
|
};
|
|
@@ -119,16 +102,23 @@ Complete the user's search request efficiently and report your findings clearly.
|
|
|
119
102
|
*/
|
|
120
103
|
function createPlanSubagent(): SubagentConfiguration {
|
|
121
104
|
// Define allowed tools for read-only operations
|
|
122
|
-
const allowedTools = [
|
|
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
|
+
];
|
|
123
113
|
|
|
124
114
|
return {
|
|
125
|
-
name:
|
|
115
|
+
name: PLAN_SUBAGENT_TYPE,
|
|
126
116
|
description:
|
|
127
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.",
|
|
128
118
|
systemPrompt: PLAN_SUBAGENT_SYSTEM_PROMPT,
|
|
129
119
|
tools: allowedTools,
|
|
130
120
|
model: "inherit", // Uses parent agent's model
|
|
131
|
-
filePath:
|
|
121
|
+
filePath: `<builtin:${PLAN_SUBAGENT_TYPE}>`,
|
|
132
122
|
scope: "builtin",
|
|
133
123
|
priority: 3, // Lowest priority - can be overridden by user configs
|
|
134
124
|
};
|
package/src/utils/editUtils.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import * as fsSync from "node:fs";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Check if a directory is a git repository
|
|
6
|
+
* @param dirPath Directory path
|
|
7
|
+
* @returns "Yes" if it's a git repository, "No" otherwise
|
|
8
|
+
*/
|
|
9
|
+
export function isGitRepository(dirPath: string): string {
|
|
10
|
+
try {
|
|
11
|
+
// Check if .git directory exists in current directory or any parent directory
|
|
12
|
+
let currentPath = path.resolve(dirPath);
|
|
13
|
+
while (currentPath !== path.dirname(currentPath)) {
|
|
14
|
+
const gitPath = path.join(currentPath, ".git");
|
|
15
|
+
if (fsSync.existsSync(gitPath)) {
|
|
16
|
+
return "Yes";
|
|
17
|
+
}
|
|
18
|
+
currentPath = path.dirname(currentPath);
|
|
19
|
+
}
|
|
20
|
+
return "No";
|
|
21
|
+
} catch {
|
|
22
|
+
return "No";
|
|
23
|
+
}
|
|
24
|
+
}
|