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.
- package/dist/agent.d.ts +42 -11
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +114 -115
- package/dist/constants/prompts.d.ts +18 -14
- package/dist/constants/prompts.d.ts.map +1 -1
- package/dist/constants/prompts.js +130 -54
- package/dist/constants/tools.d.ts +6 -3
- package/dist/constants/tools.d.ts.map +1 -1
- package/dist/constants/tools.js +6 -3
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/managers/MemoryRuleManager.js +1 -1
- package/dist/managers/aiManager.d.ts +5 -3
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +57 -20
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +1 -0
- package/dist/managers/backgroundTaskManager.d.ts +35 -0
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -0
- package/dist/managers/backgroundTaskManager.js +255 -0
- package/dist/managers/foregroundTaskManager.d.ts +9 -0
- package/dist/managers/foregroundTaskManager.d.ts.map +1 -0
- package/dist/managers/foregroundTaskManager.js +21 -0
- package/dist/managers/liveConfigManager.d.ts +1 -1
- package/dist/managers/lspManager.d.ts.map +1 -1
- package/dist/managers/lspManager.js +3 -1
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/messageManager.d.ts +26 -12
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +138 -64
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +26 -22
- package/dist/managers/planManager.d.ts +1 -1
- package/dist/managers/planManager.d.ts.map +1 -1
- package/dist/managers/planManager.js +2 -2
- package/dist/managers/pluginManager.d.ts.map +1 -1
- package/dist/managers/pluginManager.js +3 -2
- package/dist/managers/slashCommandManager.d.ts +6 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +8 -2
- package/dist/managers/subagentManager.d.ts +15 -2
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +153 -39
- package/dist/managers/toolManager.d.ts +18 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +29 -5
- package/dist/services/GitService.d.ts.map +1 -1
- package/dist/services/GitService.js +6 -2
- package/dist/services/MarketplaceService.d.ts +2 -2
- package/dist/services/MarketplaceService.d.ts.map +1 -1
- package/dist/services/MarketplaceService.js +18 -11
- package/dist/services/MemoryRuleService.d.ts +1 -1
- package/dist/services/MemoryRuleService.d.ts.map +1 -1
- package/dist/services/MemoryRuleService.js +13 -2
- package/dist/services/aiService.d.ts +0 -1
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +4 -140
- package/dist/services/memory.d.ts +0 -3
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +1 -60
- package/dist/services/session.d.ts +15 -1
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +57 -1
- package/dist/services/taskManager.d.ts +21 -0
- package/dist/services/taskManager.d.ts.map +1 -0
- package/dist/services/taskManager.js +158 -0
- package/dist/tools/askUserQuestion.d.ts.map +1 -1
- package/dist/tools/askUserQuestion.js +39 -25
- package/dist/tools/bashTool.d.ts +0 -8
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +48 -172
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +8 -6
- package/dist/tools/exitPlanMode.d.ts.map +1 -1
- package/dist/tools/exitPlanMode.js +25 -1
- package/dist/tools/globTool.d.ts.map +1 -1
- package/dist/tools/globTool.js +8 -2
- package/dist/tools/grepTool.d.ts.map +1 -1
- package/dist/tools/grepTool.js +17 -6
- package/dist/tools/lsTool.d.ts.map +1 -1
- package/dist/tools/lsTool.js +3 -1
- package/dist/tools/multiEditTool.d.ts.map +1 -1
- package/dist/tools/multiEditTool.js +7 -6
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +16 -1
- package/dist/tools/taskManagementTools.d.ts +6 -0
- package/dist/tools/taskManagementTools.d.ts.map +1 -0
- package/dist/tools/taskManagementTools.js +453 -0
- package/dist/tools/taskOutputTool.d.ts +3 -0
- package/dist/tools/taskOutputTool.d.ts.map +1 -0
- package/dist/tools/taskOutputTool.js +173 -0
- package/dist/tools/taskStopTool.d.ts +3 -0
- package/dist/tools/taskStopTool.d.ts.map +1 -0
- package/dist/tools/taskStopTool.js +71 -0
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +110 -63
- package/dist/tools/types.d.ts +12 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/writeTool.d.ts.map +1 -1
- package/dist/tools/writeTool.js +9 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/marketplace.d.ts +1 -0
- package/dist/types/marketplace.d.ts.map +1 -1
- package/dist/types/messaging.d.ts +3 -8
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/processes.d.ts +29 -4
- package/dist/types/processes.d.ts.map +1 -1
- package/dist/types/tasks.d.ts +13 -0
- package/dist/types/tasks.d.ts.map +1 -0
- package/dist/types/tasks.js +1 -0
- package/dist/types/tools.d.ts +4 -1
- package/dist/types/tools.d.ts.map +1 -1
- package/dist/utils/builtinSubagents.d.ts.map +1 -1
- package/dist/utils/builtinSubagents.js +38 -1
- package/dist/utils/cacheControlUtils.d.ts.map +1 -1
- package/dist/utils/cacheControlUtils.js +18 -12
- package/dist/utils/constants.d.ts +0 -4
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +0 -4
- package/dist/utils/convertMessagesForAPI.js +2 -2
- package/dist/utils/editUtils.d.ts +2 -11
- package/dist/utils/editUtils.d.ts.map +1 -1
- package/dist/utils/editUtils.js +52 -79
- package/dist/utils/messageOperations.d.ts +5 -36
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +9 -98
- package/dist/utils/nameGenerator.d.ts +1 -1
- package/dist/utils/nameGenerator.d.ts.map +1 -1
- package/dist/utils/nameGenerator.js +19 -3
- package/package.json +5 -5
- package/src/agent.ts +157 -134
- package/src/constants/prompts.ts +156 -65
- package/src/constants/tools.ts +6 -3
- package/src/index.ts +1 -0
- package/src/managers/MemoryRuleManager.ts +1 -1
- package/src/managers/aiManager.ts +77 -35
- package/src/managers/backgroundBashManager.ts +1 -0
- package/src/managers/backgroundTaskManager.ts +305 -0
- package/src/managers/foregroundTaskManager.ts +27 -0
- package/src/managers/lspManager.ts +3 -1
- package/src/managers/mcpManager.ts +6 -3
- package/src/managers/messageManager.ts +185 -75
- package/src/managers/permissionManager.ts +33 -28
- package/src/managers/planManager.ts +2 -2
- package/src/managers/pluginManager.ts +4 -3
- package/src/managers/slashCommandManager.ts +15 -2
- package/src/managers/subagentManager.ts +194 -35
- package/src/managers/toolManager.ts +48 -6
- package/src/services/GitService.ts +6 -2
- package/src/services/MarketplaceService.ts +30 -12
- package/src/services/MemoryRuleService.ts +18 -6
- package/src/services/aiService.ts +3 -145
- package/src/services/memory.ts +1 -73
- package/src/services/session.ts +73 -0
- package/src/services/taskManager.ts +188 -0
- package/src/tools/askUserQuestion.ts +51 -29
- package/src/tools/bashTool.ts +63 -196
- package/src/tools/editTool.ts +9 -18
- package/src/tools/exitPlanMode.ts +26 -2
- package/src/tools/globTool.ts +10 -2
- package/src/tools/grepTool.ts +17 -6
- package/src/tools/lsTool.ts +3 -1
- package/src/tools/multiEditTool.ts +7 -18
- package/src/tools/readTool.ts +17 -1
- package/src/tools/taskManagementTools.ts +498 -0
- package/src/tools/taskOutputTool.ts +196 -0
- package/src/tools/taskStopTool.ts +78 -0
- package/src/tools/taskTool.ts +136 -74
- package/src/tools/types.ts +13 -0
- package/src/tools/writeTool.ts +9 -2
- package/src/types/index.ts +1 -0
- package/src/types/marketplace.ts +1 -0
- package/src/types/messaging.ts +2 -9
- package/src/types/processes.ts +39 -4
- package/src/types/tasks.ts +13 -0
- package/src/types/tools.ts +4 -1
- package/src/utils/builtinSubagents.ts +47 -1
- package/src/utils/cacheControlUtils.ts +26 -18
- package/src/utils/constants.ts +0 -5
- package/src/utils/convertMessagesForAPI.ts +2 -2
- package/src/utils/editUtils.ts +65 -103
- package/src/utils/messageOperations.ts +12 -136
- package/src/utils/nameGenerator.ts +20 -3
- package/dist/tools/todoWriteTool.d.ts +0 -6
- package/dist/tools/todoWriteTool.d.ts.map +0 -1
- package/dist/tools/todoWriteTool.js +0 -220
- package/src/tools/todoWriteTool.ts +0 -257
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
updateToolBlockInMessage,
|
|
4
4
|
addErrorBlockToMessage,
|
|
5
5
|
addUserMessageToMessages,
|
|
6
|
-
extractUserInputHistory,
|
|
7
6
|
addCommandOutputMessage,
|
|
8
7
|
updateCommandOutputInMessage,
|
|
9
8
|
completeCommandInMessage,
|
|
@@ -26,13 +25,13 @@ import {
|
|
|
26
25
|
SESSION_DIR,
|
|
27
26
|
} from "../services/session.js";
|
|
28
27
|
import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
28
|
+
import type { MemoryRuleManager } from "./MemoryRuleManager.js";
|
|
29
29
|
import { pathEncoder } from "../utils/pathEncoder.js";
|
|
30
30
|
|
|
31
31
|
export interface MessageManagerCallbacks {
|
|
32
32
|
onMessagesChange?: (messages: Message[]) => void;
|
|
33
33
|
onSessionIdChange?: (sessionId: string) => void;
|
|
34
34
|
onLatestTotalTokensChange?: (latestTotalTokens: number) => void;
|
|
35
|
-
onUserInputHistoryChange?: (history: string[]) => void;
|
|
36
35
|
onUsagesChange?: (usages: Usage[]) => void;
|
|
37
36
|
// Incremental callback
|
|
38
37
|
onUserMessageAdded?: (params: UserMessageParams) => void;
|
|
@@ -44,7 +43,7 @@ export interface MessageManagerCallbacks {
|
|
|
44
43
|
onAssistantReasoningUpdated?: (chunk: string, accumulated: string) => void;
|
|
45
44
|
onToolBlockUpdated?: (params: AgentToolBlockUpdateParams) => void;
|
|
46
45
|
onErrorBlockAdded?: (error: string) => void;
|
|
47
|
-
onCompressBlockAdded?: (
|
|
46
|
+
onCompressBlockAdded?: (content: string) => void;
|
|
48
47
|
onCompressionStateChange?: (isCompressing: boolean) => void;
|
|
49
48
|
onMemoryBlockAdded?: (
|
|
50
49
|
content: string,
|
|
@@ -57,6 +56,7 @@ export interface MessageManagerCallbacks {
|
|
|
57
56
|
onUpdateCommandOutputMessage?: (command: string, output: string) => void;
|
|
58
57
|
onCompleteCommandMessage?: (command: string, exitCode: number) => void;
|
|
59
58
|
onSlashCommandsChange?: (commands: SlashCommand[]) => void;
|
|
59
|
+
onInfoBlockAdded?: (content: string) => void;
|
|
60
60
|
// Rewind callbacks
|
|
61
61
|
onShowRewind?: () => void;
|
|
62
62
|
// Subagent callbacks
|
|
@@ -72,6 +72,10 @@ export interface MessageManagerCallbacks {
|
|
|
72
72
|
subagentId: string,
|
|
73
73
|
status: "active" | "completed" | "error" | "aborted",
|
|
74
74
|
) => void;
|
|
75
|
+
onFileHistoryBlockAdded?: (
|
|
76
|
+
snapshots: import("../types/reversion.js").FileSnapshot[],
|
|
77
|
+
) => void;
|
|
78
|
+
onSubagentTaskStopRequested?: (subagentId: string) => void;
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
export interface MessageManagerOptions {
|
|
@@ -80,14 +84,16 @@ export interface MessageManagerOptions {
|
|
|
80
84
|
logger?: Logger;
|
|
81
85
|
sessionType?: "main" | "subagent";
|
|
82
86
|
subagentType?: string;
|
|
87
|
+
memoryRuleManager?: MemoryRuleManager;
|
|
83
88
|
}
|
|
84
89
|
|
|
85
90
|
export class MessageManager {
|
|
86
91
|
// Private state properties
|
|
87
92
|
private sessionId: string;
|
|
93
|
+
private rootSessionId: string;
|
|
94
|
+
private parentSessionId?: string;
|
|
88
95
|
private messages: Message[];
|
|
89
96
|
private latestTotalTokens: number;
|
|
90
|
-
private userInputHistory: string[];
|
|
91
97
|
private workdir: string;
|
|
92
98
|
private encodedWorkdir: string; // Cached encoded workdir
|
|
93
99
|
private logger?: Logger; // Add optional logger property
|
|
@@ -95,14 +101,15 @@ export class MessageManager {
|
|
|
95
101
|
private transcriptPath: string; // Cached transcript path
|
|
96
102
|
private savedMessageCount: number; // Track how many messages have been saved to prevent duplication
|
|
97
103
|
private filesInContext: Set<string> = new Set(); // Track files mentioned in the conversation
|
|
104
|
+
private memoryRuleManager?: MemoryRuleManager;
|
|
98
105
|
private sessionType: "main" | "subagent";
|
|
99
106
|
private subagentType?: string;
|
|
100
107
|
|
|
101
108
|
constructor(options: MessageManagerOptions) {
|
|
102
109
|
this.sessionId = generateSessionId();
|
|
110
|
+
this.rootSessionId = this.sessionId;
|
|
103
111
|
this.messages = [];
|
|
104
112
|
this.latestTotalTokens = 0;
|
|
105
|
-
this.userInputHistory = [];
|
|
106
113
|
this.workdir = options.workdir;
|
|
107
114
|
this.encodedWorkdir = pathEncoder.encodeSync(this.workdir); // Cache encoded workdir
|
|
108
115
|
this.callbacks = options.callbacks;
|
|
@@ -110,6 +117,7 @@ export class MessageManager {
|
|
|
110
117
|
this.savedMessageCount = 0; // Initialize saved message count tracker
|
|
111
118
|
this.sessionType = options.sessionType || "main";
|
|
112
119
|
this.subagentType = options.subagentType;
|
|
120
|
+
this.memoryRuleManager = options.memoryRuleManager;
|
|
113
121
|
|
|
114
122
|
// Compute and cache the transcript path
|
|
115
123
|
this.transcriptPath = this.computeTranscriptPath();
|
|
@@ -120,6 +128,14 @@ export class MessageManager {
|
|
|
120
128
|
return this.sessionId;
|
|
121
129
|
}
|
|
122
130
|
|
|
131
|
+
public getRootSessionId(): string {
|
|
132
|
+
return this.rootSessionId;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
public getParentSessionId(): string | undefined {
|
|
136
|
+
return this.parentSessionId;
|
|
137
|
+
}
|
|
138
|
+
|
|
123
139
|
public getMessages(): Message[] {
|
|
124
140
|
return [...this.messages];
|
|
125
141
|
}
|
|
@@ -128,10 +144,6 @@ export class MessageManager {
|
|
|
128
144
|
return this.latestTotalTokens;
|
|
129
145
|
}
|
|
130
146
|
|
|
131
|
-
public getUserInputHistory(): string[] {
|
|
132
|
-
return [...this.userInputHistory];
|
|
133
|
-
}
|
|
134
|
-
|
|
135
147
|
public getWorkdir(): string {
|
|
136
148
|
return this.workdir;
|
|
137
149
|
}
|
|
@@ -151,6 +163,30 @@ export class MessageManager {
|
|
|
151
163
|
return this.transcriptPath;
|
|
152
164
|
}
|
|
153
165
|
|
|
166
|
+
/**
|
|
167
|
+
* Get combined memory content (project memory + user memory + modular rules)
|
|
168
|
+
*/
|
|
169
|
+
public async getCombinedMemory(): Promise<string> {
|
|
170
|
+
const memory = await import("../services/memory.js");
|
|
171
|
+
let combined = await memory.getCombinedMemoryContent(this.workdir);
|
|
172
|
+
|
|
173
|
+
if (this.memoryRuleManager) {
|
|
174
|
+
const filesInContext = this.getFilesInContext();
|
|
175
|
+
const activeRules = this.memoryRuleManager.getActiveRules(filesInContext);
|
|
176
|
+
if (activeRules.length > 0) {
|
|
177
|
+
this.logger?.debug(
|
|
178
|
+
`Active modular rules (${activeRules.length}): ${activeRules.map((r) => r.id).join(", ")}`,
|
|
179
|
+
);
|
|
180
|
+
if (combined) {
|
|
181
|
+
combined += "\n\n";
|
|
182
|
+
}
|
|
183
|
+
combined += activeRules.map((r) => r.content).join("\n\n");
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return combined;
|
|
188
|
+
}
|
|
189
|
+
|
|
154
190
|
/**
|
|
155
191
|
* Compute the transcript path using cached encoded workdir
|
|
156
192
|
* Called during construction and when sessionId changes
|
|
@@ -218,6 +254,8 @@ export class MessageManager {
|
|
|
218
254
|
unsavedMessages, // Only append new messages
|
|
219
255
|
this.workdir,
|
|
220
256
|
this.sessionType,
|
|
257
|
+
this.rootSessionId,
|
|
258
|
+
this.parentSessionId,
|
|
221
259
|
);
|
|
222
260
|
|
|
223
261
|
// Update the saved message count
|
|
@@ -235,18 +273,13 @@ export class MessageManager {
|
|
|
235
273
|
}
|
|
236
274
|
}
|
|
237
275
|
|
|
238
|
-
public setUserInputHistory(userInputHistory: string[]): void {
|
|
239
|
-
this.userInputHistory = [...userInputHistory];
|
|
240
|
-
this.callbacks.onUserInputHistoryChange?.(this.userInputHistory);
|
|
241
|
-
}
|
|
242
|
-
|
|
243
276
|
/**
|
|
244
|
-
* Clear messages
|
|
277
|
+
* Clear messages
|
|
245
278
|
*/
|
|
246
279
|
public clearMessages(): void {
|
|
247
280
|
this.setMessages([]);
|
|
248
|
-
this.setUserInputHistory([]);
|
|
249
281
|
this.setSessionId(generateSessionId());
|
|
282
|
+
this.rootSessionId = this.sessionId;
|
|
250
283
|
this.setlatestTotalTokens(0);
|
|
251
284
|
this.savedMessageCount = 0; // Reset saved message count
|
|
252
285
|
}
|
|
@@ -268,36 +301,17 @@ export class MessageManager {
|
|
|
268
301
|
// Initialize state from session data
|
|
269
302
|
public initializeFromSession(sessionData: SessionData): void {
|
|
270
303
|
this.setSessionId(sessionData.id);
|
|
304
|
+
this.rootSessionId = sessionData.rootSessionId || sessionData.id;
|
|
305
|
+
this.parentSessionId = sessionData.parentSessionId;
|
|
271
306
|
this.setMessages([...sessionData.messages]);
|
|
272
307
|
this.updateFilesInContext(sessionData.messages);
|
|
273
308
|
this.setlatestTotalTokens(sessionData.metadata.latestTotalTokens);
|
|
274
309
|
|
|
275
|
-
// Extract user input history from session messages
|
|
276
|
-
this.setUserInputHistory(extractUserInputHistory(sessionData.messages));
|
|
277
|
-
|
|
278
310
|
// Set saved message count to the number of loaded messages since they're already saved
|
|
279
311
|
// This must be done after setSessionId which resets it to 0
|
|
280
312
|
this.savedMessageCount = sessionData.messages.length;
|
|
281
313
|
}
|
|
282
314
|
|
|
283
|
-
// Add to input history
|
|
284
|
-
public addToInputHistory(input: string): void {
|
|
285
|
-
// Avoid adding duplicate inputs
|
|
286
|
-
if (
|
|
287
|
-
this.userInputHistory.length > 0 &&
|
|
288
|
-
this.userInputHistory[this.userInputHistory.length - 1] === input
|
|
289
|
-
) {
|
|
290
|
-
return;
|
|
291
|
-
}
|
|
292
|
-
// Limit history records, keep the latest 100
|
|
293
|
-
this.setUserInputHistory([...this.userInputHistory, input].slice(-100));
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Clear input history
|
|
297
|
-
public clearInputHistory(): void {
|
|
298
|
-
this.setUserInputHistory([]);
|
|
299
|
-
}
|
|
300
|
-
|
|
301
315
|
// Encapsulated message operation functions
|
|
302
316
|
public addUserMessage(params: UserMessageParams): void {
|
|
303
317
|
const newMessages = addUserMessageToMessages({
|
|
@@ -373,17 +387,7 @@ export class MessageManager {
|
|
|
373
387
|
public updateToolBlock(params: AgentToolBlockUpdateParams): void {
|
|
374
388
|
const newMessages = updateToolBlockInMessage({
|
|
375
389
|
messages: this.messages,
|
|
376
|
-
|
|
377
|
-
parameters: params.parameters,
|
|
378
|
-
result: params.result,
|
|
379
|
-
success: params.success,
|
|
380
|
-
error: params.error,
|
|
381
|
-
stage: params.stage,
|
|
382
|
-
name: params.name,
|
|
383
|
-
shortResult: params.shortResult,
|
|
384
|
-
images: params.images,
|
|
385
|
-
compactParams: params.compactParams,
|
|
386
|
-
parametersChunk: params.parametersChunk,
|
|
390
|
+
...params,
|
|
387
391
|
});
|
|
388
392
|
this.setMessages(newMessages);
|
|
389
393
|
this.callbacks.onToolBlockUpdated?.(params);
|
|
@@ -400,15 +404,27 @@ export class MessageManager {
|
|
|
400
404
|
this.callbacks.onErrorBlockAdded?.(error);
|
|
401
405
|
}
|
|
402
406
|
|
|
407
|
+
public addInfoBlock(content: string): void {
|
|
408
|
+
const lastMessage = this.messages[this.messages.length - 1];
|
|
409
|
+
if (lastMessage && lastMessage.role === "assistant") {
|
|
410
|
+
lastMessage.blocks.push({
|
|
411
|
+
type: "info",
|
|
412
|
+
content,
|
|
413
|
+
} as unknown as import("../types/index.js").MessageBlock);
|
|
414
|
+
this.setMessages([...this.messages]);
|
|
415
|
+
this.callbacks.onInfoBlockAdded?.(content);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
403
419
|
/**
|
|
404
|
-
* Compress messages and update session, delete compressed messages, only keep compressed messages and
|
|
420
|
+
* Compress messages and update session, delete compressed messages, only keep compressed messages and last 3 messages
|
|
405
421
|
*/
|
|
406
422
|
public compressMessagesAndUpdateSession(
|
|
407
|
-
insertIndex: number,
|
|
408
423
|
compressedContent: string,
|
|
409
424
|
usage?: Usage,
|
|
410
425
|
): void {
|
|
411
|
-
|
|
426
|
+
// Get last 3 messages to preserve
|
|
427
|
+
const lastThreeMessages = this.messages.slice(-3);
|
|
412
428
|
|
|
413
429
|
// Create compressed message
|
|
414
430
|
const compressMessage: Message = {
|
|
@@ -423,24 +439,24 @@ export class MessageManager {
|
|
|
423
439
|
...(usage && { usage }),
|
|
424
440
|
};
|
|
425
441
|
|
|
426
|
-
//
|
|
427
|
-
const
|
|
428
|
-
insertIndex < 0 ? currentMessages.length + insertIndex : insertIndex;
|
|
429
|
-
|
|
430
|
-
// Build new message array: keep compressed message and all messages from actualIndex onwards
|
|
431
|
-
const newMessages: Message[] = [
|
|
432
|
-
compressMessage,
|
|
433
|
-
...currentMessages.slice(actualIndex),
|
|
434
|
-
];
|
|
442
|
+
// Build new message array: keep the compressed message and last 3 messages
|
|
443
|
+
const newMessages: Message[] = [compressMessage, ...lastThreeMessages];
|
|
435
444
|
|
|
436
|
-
// Update sessionId
|
|
445
|
+
// Update sessionId and parentSessionId
|
|
446
|
+
const oldSessionId = this.sessionId;
|
|
437
447
|
this.setSessionId(generateSessionId());
|
|
448
|
+
this.parentSessionId = oldSessionId;
|
|
449
|
+
|
|
450
|
+
// Trigger task list update if this is the main session to ensure continuity
|
|
451
|
+
if (this.sessionType === "main") {
|
|
452
|
+
this.callbacks.onSessionIdChange?.(this.sessionId);
|
|
453
|
+
}
|
|
438
454
|
|
|
439
455
|
// Set new message list
|
|
440
456
|
this.setMessages(newMessages);
|
|
441
457
|
|
|
442
|
-
// Trigger compression callback
|
|
443
|
-
this.callbacks.onCompressBlockAdded?.(
|
|
458
|
+
// Trigger compression callback
|
|
459
|
+
this.callbacks.onCompressBlockAdded?.(compressedContent);
|
|
444
460
|
}
|
|
445
461
|
|
|
446
462
|
public addFileHistoryBlock(
|
|
@@ -455,6 +471,7 @@ export class MessageManager {
|
|
|
455
471
|
snapshots,
|
|
456
472
|
} as unknown as import("../types/index.js").MessageBlock);
|
|
457
473
|
this.setMessages([...this.messages]);
|
|
474
|
+
this.callbacks.onFileHistoryBlockAdded?.(snapshots);
|
|
458
475
|
}
|
|
459
476
|
}
|
|
460
477
|
|
|
@@ -494,12 +511,13 @@ export class MessageManager {
|
|
|
494
511
|
subagentName: string,
|
|
495
512
|
sessionId: string,
|
|
496
513
|
configuration: SubagentConfiguration,
|
|
497
|
-
status: "active" | "completed" | "error" = "active",
|
|
514
|
+
status: "active" | "completed" | "error" | "aborted" = "active",
|
|
498
515
|
parameters: {
|
|
499
516
|
description: string;
|
|
500
517
|
prompt: string;
|
|
501
518
|
subagent_type: string;
|
|
502
519
|
},
|
|
520
|
+
runInBackground?: boolean,
|
|
503
521
|
): void {
|
|
504
522
|
const params: AddSubagentBlockParams = {
|
|
505
523
|
messages: this.messages,
|
|
@@ -508,6 +526,7 @@ export class MessageManager {
|
|
|
508
526
|
sessionId,
|
|
509
527
|
status,
|
|
510
528
|
configuration,
|
|
529
|
+
runInBackground,
|
|
511
530
|
};
|
|
512
531
|
const updatedMessages = addSubagentBlockToMessage(params);
|
|
513
532
|
this.setMessages(updatedMessages);
|
|
@@ -519,6 +538,7 @@ export class MessageManager {
|
|
|
519
538
|
updates: Partial<{
|
|
520
539
|
status: "active" | "completed" | "error" | "aborted";
|
|
521
540
|
sessionId: string;
|
|
541
|
+
runInBackground: boolean;
|
|
522
542
|
}>,
|
|
523
543
|
): void {
|
|
524
544
|
const updatedMessages = updateSubagentBlockInMessage(
|
|
@@ -532,7 +552,9 @@ export class MessageManager {
|
|
|
532
552
|
subagentId,
|
|
533
553
|
status: updates.status || "active",
|
|
534
554
|
};
|
|
535
|
-
|
|
555
|
+
if (updates.status) {
|
|
556
|
+
this.callbacks.onSubAgentBlockUpdated?.(params.subagentId, params.status);
|
|
557
|
+
}
|
|
536
558
|
}
|
|
537
559
|
|
|
538
560
|
/**
|
|
@@ -657,6 +679,14 @@ export class MessageManager {
|
|
|
657
679
|
this.setMessages(newMessages);
|
|
658
680
|
}
|
|
659
681
|
|
|
682
|
+
public async getFullMessageThread(): Promise<{
|
|
683
|
+
messages: Message[];
|
|
684
|
+
sessionIds: string[];
|
|
685
|
+
}> {
|
|
686
|
+
const { loadFullMessageThread } = await import("../services/session.js");
|
|
687
|
+
return loadFullMessageThread(this.sessionId, this.workdir);
|
|
688
|
+
}
|
|
689
|
+
|
|
660
690
|
/**
|
|
661
691
|
* Truncate history to a specific index and revert file changes.
|
|
662
692
|
* @param index - The index of the user message to truncate to.
|
|
@@ -666,30 +696,110 @@ export class MessageManager {
|
|
|
666
696
|
index: number,
|
|
667
697
|
reversionManager?: import("./reversionManager.js").ReversionManager,
|
|
668
698
|
): Promise<void> {
|
|
669
|
-
|
|
699
|
+
const { messages, sessionIds } = await this.getFullMessageThread();
|
|
700
|
+
|
|
701
|
+
if (index < 0 || index >= messages.length) {
|
|
670
702
|
throw new Error(`Invalid message index: ${index}`);
|
|
671
703
|
}
|
|
672
704
|
|
|
673
|
-
//
|
|
674
|
-
|
|
705
|
+
// Find which session the index belongs to
|
|
706
|
+
let targetSessionId = this.sessionId;
|
|
707
|
+
let targetIndexInSession = index;
|
|
708
|
+
|
|
709
|
+
// We need to be careful here because loadFullMessageThread might have removed "compress" blocks
|
|
710
|
+
// Let's re-calculate based on the actual messages returned.
|
|
711
|
+
// Actually, it's easier to just load sessions one by one again or keep track of counts.
|
|
712
|
+
|
|
713
|
+
// For simplicity, let's assume we want to truncate the WHOLE thread.
|
|
714
|
+
// If the index is in a previous session, we need to:
|
|
715
|
+
// 1. Load that session.
|
|
716
|
+
// 2. Truncate it.
|
|
717
|
+
// 3. Make it the current session.
|
|
718
|
+
// 4. Delete/Invalidate subsequent sessions.
|
|
719
|
+
|
|
720
|
+
// To correctly map 'index' to a session, we need to know the message count of each session
|
|
721
|
+
// as they appear in the concatenated 'messages' array.
|
|
722
|
+
|
|
723
|
+
let remainingIndex = index;
|
|
724
|
+
const { loadSessionFromJsonl } = await import("../services/session.js");
|
|
725
|
+
|
|
726
|
+
for (const sid of sessionIds) {
|
|
727
|
+
const sessionData = await loadSessionFromJsonl(sid, this.workdir);
|
|
728
|
+
if (!sessionData) continue;
|
|
729
|
+
|
|
730
|
+
const sessionMessages = sessionData.messages;
|
|
731
|
+
// If this is not the first session in the thread, it might have a compress block at the start
|
|
732
|
+
// that was removed in getFullMessageThread.
|
|
733
|
+
const hasCompressBlock = sessionMessages[0]?.blocks.some(
|
|
734
|
+
(b) => b.type === "compress",
|
|
735
|
+
);
|
|
736
|
+
const effectiveMessages =
|
|
737
|
+
hasCompressBlock && sid !== sessionIds[0]
|
|
738
|
+
? sessionMessages.slice(1)
|
|
739
|
+
: sessionMessages;
|
|
740
|
+
|
|
741
|
+
if (remainingIndex < effectiveMessages.length) {
|
|
742
|
+
targetSessionId = sid;
|
|
743
|
+
targetIndexInSession = hasCompressBlock
|
|
744
|
+
? remainingIndex + 1
|
|
745
|
+
: remainingIndex;
|
|
746
|
+
break;
|
|
747
|
+
}
|
|
748
|
+
remainingIndex -= effectiveMessages.length;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// Load the target session to perform truncation
|
|
752
|
+
const targetSessionData = await loadSessionFromJsonl(
|
|
753
|
+
targetSessionId,
|
|
754
|
+
this.workdir,
|
|
755
|
+
);
|
|
756
|
+
if (!targetSessionData)
|
|
757
|
+
throw new Error(`Target session ${targetSessionId} not found`);
|
|
758
|
+
|
|
759
|
+
// Identify messages to be removed (from the whole thread)
|
|
760
|
+
const messagesToRemove = messages.slice(index);
|
|
675
761
|
const messageIdsToRemove = messagesToRemove
|
|
676
762
|
.map((m) => m.id as string)
|
|
677
763
|
.filter((id) => !!id);
|
|
678
764
|
|
|
679
765
|
// Revert file changes if manager is provided
|
|
680
766
|
if (reversionManager && messageIdsToRemove.length > 0) {
|
|
681
|
-
await reversionManager.revertTo(messageIdsToRemove,
|
|
767
|
+
await reversionManager.revertTo(messageIdsToRemove, messages);
|
|
682
768
|
}
|
|
683
769
|
|
|
684
|
-
// Truncate messages in
|
|
685
|
-
const
|
|
686
|
-
|
|
770
|
+
// Truncate messages in the target session
|
|
771
|
+
const newMessagesInSession = targetSessionData.messages.slice(
|
|
772
|
+
0,
|
|
773
|
+
targetIndexInSession,
|
|
774
|
+
);
|
|
775
|
+
|
|
776
|
+
// Identify subagent tasks to stop
|
|
777
|
+
for (const message of messagesToRemove) {
|
|
778
|
+
for (const block of message.blocks) {
|
|
779
|
+
if (block.type === "subagent" && block.subagentId) {
|
|
780
|
+
this.callbacks.onSubagentTaskStopRequested?.(block.subagentId);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
}
|
|
687
784
|
|
|
688
|
-
// Update
|
|
689
|
-
|
|
785
|
+
// Update target session file
|
|
786
|
+
this.sessionId = targetSessionId;
|
|
787
|
+
this.rootSessionId = targetSessionData.rootSessionId || targetSessionId;
|
|
788
|
+
this.parentSessionId = targetSessionData.parentSessionId;
|
|
789
|
+
this.transcriptPath = this.computeTranscriptPath();
|
|
790
|
+
|
|
791
|
+
await this.rewriteSessionFile(newMessagesInSession);
|
|
792
|
+
|
|
793
|
+
// Update in-memory messages to the truncated session messages
|
|
794
|
+
// We do NOT include ancestor messages here to avoid exceeding context limits.
|
|
795
|
+
// The 'compress' block at the start of the session (if any) already summarizes them.
|
|
796
|
+
this.setMessages(newMessagesInSession);
|
|
690
797
|
|
|
691
798
|
// Update saved message count
|
|
692
|
-
this.savedMessageCount =
|
|
799
|
+
this.savedMessageCount = newMessagesInSession.length;
|
|
800
|
+
|
|
801
|
+
// Notify session ID change if it changed
|
|
802
|
+
this.callbacks.onSessionIdChange?.(this.sessionId);
|
|
693
803
|
}
|
|
694
804
|
|
|
695
805
|
/**
|
|
@@ -237,13 +237,7 @@ export class PermissionManager {
|
|
|
237
237
|
* Get the current effective permission mode for tool execution context
|
|
238
238
|
*/
|
|
239
239
|
getCurrentEffectiveMode(cliPermissionMode?: PermissionMode): PermissionMode {
|
|
240
|
-
|
|
241
|
-
this.logger?.debug("getCurrentEffectiveMode", {
|
|
242
|
-
cliPermissionMode,
|
|
243
|
-
configuredDefaultMode: this.configuredDefaultMode,
|
|
244
|
-
resolvedMode: mode,
|
|
245
|
-
});
|
|
246
|
-
return mode;
|
|
240
|
+
return this.resolveEffectivePermissionMode(cliPermissionMode);
|
|
247
241
|
}
|
|
248
242
|
|
|
249
243
|
/**
|
|
@@ -329,40 +323,30 @@ export class PermissionManager {
|
|
|
329
323
|
workdir,
|
|
330
324
|
);
|
|
331
325
|
if (!isInside) {
|
|
332
|
-
this.logger?.
|
|
333
|
-
"File operation outside the Safe Zone in acceptEdits mode",
|
|
326
|
+
this.logger?.info(
|
|
327
|
+
"File operation outside the Safe Zone in acceptEdits mode, falling back to manual confirmation",
|
|
334
328
|
{
|
|
335
329
|
toolName: context.toolName,
|
|
336
330
|
targetPath,
|
|
337
331
|
resolvedPath,
|
|
338
332
|
},
|
|
339
333
|
);
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
334
|
+
// Fall through to normal permission check flow to trigger confirmation prompt
|
|
335
|
+
} else {
|
|
336
|
+
this.logger?.debug(
|
|
337
|
+
"Permission automatically accepted for tool in acceptEdits mode",
|
|
338
|
+
{
|
|
339
|
+
toolName: context.toolName,
|
|
340
|
+
},
|
|
341
|
+
);
|
|
342
|
+
return { behavior: "allow" };
|
|
344
343
|
}
|
|
345
344
|
}
|
|
346
|
-
|
|
347
|
-
this.logger?.debug(
|
|
348
|
-
"Permission automatically accepted for tool in acceptEdits mode",
|
|
349
|
-
{
|
|
350
|
-
toolName: context.toolName,
|
|
351
|
-
},
|
|
352
|
-
);
|
|
353
|
-
return { behavior: "allow" };
|
|
354
345
|
}
|
|
355
346
|
}
|
|
356
347
|
|
|
357
348
|
// 1.3 If plan mode, allow Read-only tools and Edit/Write for plan file
|
|
358
349
|
if (context.permissionMode === "plan") {
|
|
359
|
-
if (context.toolName === BASH_TOOL_NAME) {
|
|
360
|
-
return {
|
|
361
|
-
behavior: "deny",
|
|
362
|
-
message: "Bash commands are not allowed in plan mode.",
|
|
363
|
-
};
|
|
364
|
-
}
|
|
365
|
-
|
|
366
350
|
const writeTools = [
|
|
367
351
|
EDIT_TOOL_NAME,
|
|
368
352
|
MULTI_EDIT_TOOL_NAME,
|
|
@@ -498,6 +482,27 @@ export class PermissionManager {
|
|
|
498
482
|
suggestedPrefix,
|
|
499
483
|
};
|
|
500
484
|
|
|
485
|
+
// Set hidePersistentOption for out-of-bounds file operations
|
|
486
|
+
const fileTools = [
|
|
487
|
+
EDIT_TOOL_NAME,
|
|
488
|
+
MULTI_EDIT_TOOL_NAME,
|
|
489
|
+
DELETE_FILE_TOOL_NAME,
|
|
490
|
+
WRITE_TOOL_NAME,
|
|
491
|
+
];
|
|
492
|
+
if (fileTools.includes(toolName)) {
|
|
493
|
+
const targetPath = (toolInput?.file_path || toolInput?.target_file) as
|
|
494
|
+
| string
|
|
495
|
+
| undefined;
|
|
496
|
+
const workdir = toolInput?.workdir as string | undefined;
|
|
497
|
+
|
|
498
|
+
if (targetPath) {
|
|
499
|
+
const { isInside } = this.isInsideSafeZone(targetPath, workdir);
|
|
500
|
+
if (!isInside) {
|
|
501
|
+
context.hidePersistentOption = true;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
501
506
|
// Set hidePersistentOption for dangerous or out-of-bounds bash commands
|
|
502
507
|
if (toolName === BASH_TOOL_NAME && toolInput?.command) {
|
|
503
508
|
const command = String(toolInput.command);
|
|
@@ -17,7 +17,7 @@ export class PlanManager {
|
|
|
17
17
|
/**
|
|
18
18
|
* Ensures the plan directory exists and generates a new plan file path with a random name
|
|
19
19
|
*/
|
|
20
|
-
public async getOrGeneratePlanFilePath(): Promise<{
|
|
20
|
+
public async getOrGeneratePlanFilePath(seed?: string): Promise<{
|
|
21
21
|
path: string;
|
|
22
22
|
name: string;
|
|
23
23
|
}> {
|
|
@@ -30,7 +30,7 @@ export class PlanManager {
|
|
|
30
30
|
);
|
|
31
31
|
throw error;
|
|
32
32
|
}
|
|
33
|
-
const name = generateRandomName();
|
|
33
|
+
const name = generateRandomName(seed);
|
|
34
34
|
const filePath = path.join(this.planDir, `${name}.md`);
|
|
35
35
|
this.logger?.info(`Generated plan file path: ${filePath}`);
|
|
36
36
|
return { path: filePath, name };
|
|
@@ -149,9 +149,7 @@ export class PluginManager {
|
|
|
149
149
|
* @param configs Array of plugin configurations
|
|
150
150
|
*/
|
|
151
151
|
async loadPlugins(configs: PluginConfig[]): Promise<void> {
|
|
152
|
-
// Load
|
|
153
|
-
await this.loadInstalledPlugins();
|
|
154
|
-
|
|
152
|
+
// Load plugins from configuration (e.g. --plugin-dir) first to give them higher priority
|
|
155
153
|
for (const config of configs) {
|
|
156
154
|
if (config.type !== "local") {
|
|
157
155
|
this.logger?.warn(`Unsupported plugin type: ${config.type}`);
|
|
@@ -164,6 +162,9 @@ export class PluginManager {
|
|
|
164
162
|
|
|
165
163
|
await this.loadSinglePlugin(absolutePath);
|
|
166
164
|
}
|
|
165
|
+
|
|
166
|
+
// Load installed plugins from marketplace
|
|
167
|
+
await this.loadInstalledPlugins();
|
|
167
168
|
}
|
|
168
169
|
|
|
169
170
|
/**
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { MessageManager } from "./messageManager.js";
|
|
2
2
|
import type { AIManager } from "./aiManager.js";
|
|
3
|
+
import type { BackgroundTaskManager } from "./backgroundTaskManager.js";
|
|
4
|
+
import type { TaskManager } from "../services/taskManager.js";
|
|
3
5
|
import type {
|
|
4
6
|
SlashCommand,
|
|
5
7
|
CustomSlashCommand,
|
|
@@ -26,6 +28,8 @@ const execAsync = promisify(exec);
|
|
|
26
28
|
export interface SlashCommandManagerOptions {
|
|
27
29
|
messageManager: MessageManager;
|
|
28
30
|
aiManager: AIManager;
|
|
31
|
+
backgroundTaskManager: BackgroundTaskManager;
|
|
32
|
+
taskManager: TaskManager;
|
|
29
33
|
workdir: string;
|
|
30
34
|
logger?: Logger;
|
|
31
35
|
}
|
|
@@ -35,12 +39,16 @@ export class SlashCommandManager {
|
|
|
35
39
|
private customCommands = new Map<string, CustomSlashCommand>();
|
|
36
40
|
private messageManager: MessageManager;
|
|
37
41
|
private aiManager: AIManager;
|
|
42
|
+
private backgroundTaskManager: BackgroundTaskManager;
|
|
43
|
+
private taskManager: TaskManager;
|
|
38
44
|
private workdir: string;
|
|
39
45
|
private logger?: Logger;
|
|
40
46
|
|
|
41
47
|
constructor(options: SlashCommandManagerOptions) {
|
|
42
48
|
this.messageManager = options.messageManager;
|
|
43
49
|
this.aiManager = options.aiManager;
|
|
50
|
+
this.backgroundTaskManager = options.backgroundTaskManager;
|
|
51
|
+
this.taskManager = options.taskManager;
|
|
44
52
|
this.workdir = options.workdir;
|
|
45
53
|
this.logger = options.logger;
|
|
46
54
|
|
|
@@ -57,8 +65,13 @@ export class SlashCommandManager {
|
|
|
57
65
|
handler: () => {
|
|
58
66
|
// Clear chat messages
|
|
59
67
|
this.messageManager.clearMessages();
|
|
60
|
-
|
|
61
|
-
|
|
68
|
+
|
|
69
|
+
// Reset task list if WAVE_TASK_LIST_ID is not set
|
|
70
|
+
if (!process.env.WAVE_TASK_LIST_ID) {
|
|
71
|
+
const newTaskListId = this.messageManager.getRootSessionId();
|
|
72
|
+
this.taskManager.setTaskListId(newTaskListId);
|
|
73
|
+
this.taskManager.emit("tasksChange", newTaskListId);
|
|
74
|
+
}
|
|
62
75
|
},
|
|
63
76
|
});
|
|
64
77
|
|