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.
- package/dist/agent.d.ts +14 -11
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +64 -151
- 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/constants/tools.d.ts +4 -1
- package/dist/constants/tools.d.ts.map +1 -1
- package/dist/constants/tools.js +4 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/managers/aiManager.d.ts +2 -5
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +43 -48
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +63 -53
- package/dist/managers/foregroundTaskManager.d.ts.map +1 -1
- package/dist/managers/foregroundTaskManager.js +3 -2
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/messageManager.d.ts +13 -27
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +94 -89
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +25 -15
- 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/reversionManager.d.ts.map +1 -1
- package/dist/managers/reversionManager.js +23 -2
- package/dist/managers/slashCommandManager.d.ts +3 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +8 -3
- package/dist/managers/subagentManager.d.ts +8 -14
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +46 -112
- package/dist/managers/toolManager.d.ts +11 -0
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +20 -2
- package/dist/{constants/prompts.d.ts → prompts/index.d.ts} +17 -15
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +309 -0
- 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 +0 -59
- 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 +25 -0
- package/dist/services/taskManager.d.ts.map +1 -0
- package/dist/services/taskManager.js +164 -0
- package/dist/tools/askUserQuestion.d.ts.map +1 -1
- package/dist/tools/askUserQuestion.js +39 -25
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +13 -11
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +2 -1
- package/dist/tools/exitPlanMode.d.ts.map +1 -1
- package/dist/tools/exitPlanMode.js +26 -2
- 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/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 +461 -0
- package/dist/tools/taskOutputTool.d.ts.map +1 -1
- package/dist/tools/taskOutputTool.js +32 -8
- package/dist/tools/taskStopTool.d.ts.map +1 -1
- package/dist/tools/taskStopTool.js +7 -1
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +37 -2
- package/dist/tools/types.d.ts +11 -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/messaging.d.ts +2 -18
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/processes.d.ts +16 -6
- 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 +59 -44
- 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.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 +3 -58
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +4 -146
- 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 +1 -1
- package/src/agent.ts +86 -183
- package/src/constants/subagents.ts +4 -0
- package/src/constants/tools.ts +4 -1
- package/src/index.ts +1 -0
- package/src/managers/aiManager.ts +63 -70
- package/src/managers/backgroundTaskManager.ts +58 -54
- package/src/managers/foregroundTaskManager.ts +3 -2
- package/src/managers/mcpManager.ts +6 -3
- package/src/managers/messageManager.ts +126 -142
- package/src/managers/permissionManager.ts +32 -21
- package/src/managers/planManager.ts +2 -2
- package/src/managers/reversionManager.ts +26 -2
- package/src/managers/slashCommandManager.ts +12 -3
- package/src/managers/subagentManager.ts +60 -144
- package/src/managers/toolManager.ts +32 -2
- package/src/prompts/index.ts +366 -0
- package/src/services/aiService.ts +3 -145
- package/src/services/memory.ts +0 -72
- package/src/services/session.ts +73 -0
- package/src/services/taskManager.ts +195 -0
- package/src/tools/askUserQuestion.ts +51 -29
- package/src/tools/bashTool.ts +15 -17
- package/src/tools/editTool.ts +3 -1
- package/src/tools/exitPlanMode.ts +27 -3
- package/src/tools/globTool.ts +10 -2
- package/src/tools/grepTool.ts +17 -6
- package/src/tools/lsTool.ts +3 -1
- package/src/tools/readTool.ts +17 -1
- package/src/tools/taskManagementTools.ts +516 -0
- package/src/tools/taskOutputTool.ts +34 -12
- package/src/tools/taskStopTool.ts +7 -1
- package/src/tools/taskTool.ts +45 -1
- package/src/tools/types.ts +12 -0
- package/src/tools/writeTool.ts +9 -2
- package/src/types/index.ts +1 -0
- package/src/types/messaging.ts +1 -21
- package/src/types/processes.ts +18 -7
- package/src/types/tasks.ts +13 -0
- package/src/types/tools.ts +4 -1
- package/src/utils/builtinSubagents.ts +81 -45
- 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 +2 -6
- package/src/utils/gitUtils.ts +24 -0
- package/src/utils/messageOperations.ts +6 -229
- package/src/utils/nameGenerator.ts +20 -3
- package/dist/constants/prompts.d.ts.map +0 -1
- package/dist/constants/prompts.js +0 -118
- 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/constants/prompts.ts +0 -155
- package/src/tools/todoWriteTool.ts +0 -257
|
@@ -3,19 +3,13 @@ import {
|
|
|
3
3
|
updateToolBlockInMessage,
|
|
4
4
|
addErrorBlockToMessage,
|
|
5
5
|
addUserMessageToMessages,
|
|
6
|
-
extractUserInputHistory,
|
|
7
6
|
addCommandOutputMessage,
|
|
8
7
|
updateCommandOutputInMessage,
|
|
9
8
|
completeCommandInMessage,
|
|
10
|
-
addSubagentBlockToMessage,
|
|
11
|
-
updateSubagentBlockInMessage,
|
|
12
9
|
removeLastUserMessage,
|
|
13
10
|
UserMessageParams,
|
|
14
|
-
type AddSubagentBlockParams,
|
|
15
|
-
type UpdateSubagentBlockParams,
|
|
16
11
|
type AgentToolBlockUpdateParams,
|
|
17
12
|
} from "../utils/messageOperations.js";
|
|
18
|
-
import type { SubagentConfiguration } from "../utils/subagentParser.js";
|
|
19
13
|
import type { Logger, Message, Usage, SlashCommand } from "../types/index.js";
|
|
20
14
|
import { join } from "path";
|
|
21
15
|
import {
|
|
@@ -33,7 +27,6 @@ export interface MessageManagerCallbacks {
|
|
|
33
27
|
onMessagesChange?: (messages: Message[]) => void;
|
|
34
28
|
onSessionIdChange?: (sessionId: string) => void;
|
|
35
29
|
onLatestTotalTokensChange?: (latestTotalTokens: number) => void;
|
|
36
|
-
onUserInputHistoryChange?: (history: string[]) => void;
|
|
37
30
|
onUsagesChange?: (usages: Usage[]) => void;
|
|
38
31
|
// Incremental callback
|
|
39
32
|
onUserMessageAdded?: (params: UserMessageParams) => void;
|
|
@@ -45,7 +38,7 @@ export interface MessageManagerCallbacks {
|
|
|
45
38
|
onAssistantReasoningUpdated?: (chunk: string, accumulated: string) => void;
|
|
46
39
|
onToolBlockUpdated?: (params: AgentToolBlockUpdateParams) => void;
|
|
47
40
|
onErrorBlockAdded?: (error: string) => void;
|
|
48
|
-
onCompressBlockAdded?: (
|
|
41
|
+
onCompressBlockAdded?: (content: string) => void;
|
|
49
42
|
onCompressionStateChange?: (isCompressing: boolean) => void;
|
|
50
43
|
onMemoryBlockAdded?: (
|
|
51
44
|
content: string,
|
|
@@ -61,18 +54,8 @@ export interface MessageManagerCallbacks {
|
|
|
61
54
|
onInfoBlockAdded?: (content: string) => void;
|
|
62
55
|
// Rewind callbacks
|
|
63
56
|
onShowRewind?: () => void;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
subagentId: string,
|
|
67
|
-
parameters: {
|
|
68
|
-
description: string;
|
|
69
|
-
prompt: string;
|
|
70
|
-
subagent_type: string;
|
|
71
|
-
},
|
|
72
|
-
) => void;
|
|
73
|
-
onSubAgentBlockUpdated?: (
|
|
74
|
-
subagentId: string,
|
|
75
|
-
status: "active" | "completed" | "error" | "aborted",
|
|
57
|
+
onFileHistoryBlockAdded?: (
|
|
58
|
+
snapshots: import("../types/reversion.js").FileSnapshot[],
|
|
76
59
|
) => void;
|
|
77
60
|
}
|
|
78
61
|
|
|
@@ -88,9 +71,10 @@ export interface MessageManagerOptions {
|
|
|
88
71
|
export class MessageManager {
|
|
89
72
|
// Private state properties
|
|
90
73
|
private sessionId: string;
|
|
74
|
+
private rootSessionId: string;
|
|
75
|
+
private parentSessionId?: string;
|
|
91
76
|
private messages: Message[];
|
|
92
77
|
private latestTotalTokens: number;
|
|
93
|
-
private userInputHistory: string[];
|
|
94
78
|
private workdir: string;
|
|
95
79
|
private encodedWorkdir: string; // Cached encoded workdir
|
|
96
80
|
private logger?: Logger; // Add optional logger property
|
|
@@ -104,9 +88,9 @@ export class MessageManager {
|
|
|
104
88
|
|
|
105
89
|
constructor(options: MessageManagerOptions) {
|
|
106
90
|
this.sessionId = generateSessionId();
|
|
91
|
+
this.rootSessionId = this.sessionId;
|
|
107
92
|
this.messages = [];
|
|
108
93
|
this.latestTotalTokens = 0;
|
|
109
|
-
this.userInputHistory = [];
|
|
110
94
|
this.workdir = options.workdir;
|
|
111
95
|
this.encodedWorkdir = pathEncoder.encodeSync(this.workdir); // Cache encoded workdir
|
|
112
96
|
this.callbacks = options.callbacks;
|
|
@@ -125,6 +109,14 @@ export class MessageManager {
|
|
|
125
109
|
return this.sessionId;
|
|
126
110
|
}
|
|
127
111
|
|
|
112
|
+
public getRootSessionId(): string {
|
|
113
|
+
return this.rootSessionId;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public getParentSessionId(): string | undefined {
|
|
117
|
+
return this.parentSessionId;
|
|
118
|
+
}
|
|
119
|
+
|
|
128
120
|
public getMessages(): Message[] {
|
|
129
121
|
return [...this.messages];
|
|
130
122
|
}
|
|
@@ -133,10 +125,6 @@ export class MessageManager {
|
|
|
133
125
|
return this.latestTotalTokens;
|
|
134
126
|
}
|
|
135
127
|
|
|
136
|
-
public getUserInputHistory(): string[] {
|
|
137
|
-
return [...this.userInputHistory];
|
|
138
|
-
}
|
|
139
|
-
|
|
140
128
|
public getWorkdir(): string {
|
|
141
129
|
return this.workdir;
|
|
142
130
|
}
|
|
@@ -247,6 +235,8 @@ export class MessageManager {
|
|
|
247
235
|
unsavedMessages, // Only append new messages
|
|
248
236
|
this.workdir,
|
|
249
237
|
this.sessionType,
|
|
238
|
+
this.rootSessionId,
|
|
239
|
+
this.parentSessionId,
|
|
250
240
|
);
|
|
251
241
|
|
|
252
242
|
// Update the saved message count
|
|
@@ -264,18 +254,13 @@ export class MessageManager {
|
|
|
264
254
|
}
|
|
265
255
|
}
|
|
266
256
|
|
|
267
|
-
public setUserInputHistory(userInputHistory: string[]): void {
|
|
268
|
-
this.userInputHistory = [...userInputHistory];
|
|
269
|
-
this.callbacks.onUserInputHistoryChange?.(this.userInputHistory);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
257
|
/**
|
|
273
|
-
* Clear messages
|
|
258
|
+
* Clear messages
|
|
274
259
|
*/
|
|
275
260
|
public clearMessages(): void {
|
|
276
261
|
this.setMessages([]);
|
|
277
|
-
this.setUserInputHistory([]);
|
|
278
262
|
this.setSessionId(generateSessionId());
|
|
263
|
+
this.rootSessionId = this.sessionId;
|
|
279
264
|
this.setlatestTotalTokens(0);
|
|
280
265
|
this.savedMessageCount = 0; // Reset saved message count
|
|
281
266
|
}
|
|
@@ -297,36 +282,17 @@ export class MessageManager {
|
|
|
297
282
|
// Initialize state from session data
|
|
298
283
|
public initializeFromSession(sessionData: SessionData): void {
|
|
299
284
|
this.setSessionId(sessionData.id);
|
|
285
|
+
this.rootSessionId = sessionData.rootSessionId || sessionData.id;
|
|
286
|
+
this.parentSessionId = sessionData.parentSessionId;
|
|
300
287
|
this.setMessages([...sessionData.messages]);
|
|
301
288
|
this.updateFilesInContext(sessionData.messages);
|
|
302
289
|
this.setlatestTotalTokens(sessionData.metadata.latestTotalTokens);
|
|
303
290
|
|
|
304
|
-
// Extract user input history from session messages
|
|
305
|
-
this.setUserInputHistory(extractUserInputHistory(sessionData.messages));
|
|
306
|
-
|
|
307
291
|
// Set saved message count to the number of loaded messages since they're already saved
|
|
308
292
|
// This must be done after setSessionId which resets it to 0
|
|
309
293
|
this.savedMessageCount = sessionData.messages.length;
|
|
310
294
|
}
|
|
311
295
|
|
|
312
|
-
// Add to input history
|
|
313
|
-
public addToInputHistory(input: string): void {
|
|
314
|
-
// Avoid adding duplicate inputs
|
|
315
|
-
if (
|
|
316
|
-
this.userInputHistory.length > 0 &&
|
|
317
|
-
this.userInputHistory[this.userInputHistory.length - 1] === input
|
|
318
|
-
) {
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
// Limit history records, keep the latest 100
|
|
322
|
-
this.setUserInputHistory([...this.userInputHistory, input].slice(-100));
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
// Clear input history
|
|
326
|
-
public clearInputHistory(): void {
|
|
327
|
-
this.setUserInputHistory([]);
|
|
328
|
-
}
|
|
329
|
-
|
|
330
296
|
// Encapsulated message operation functions
|
|
331
297
|
public addUserMessage(params: UserMessageParams): void {
|
|
332
298
|
const newMessages = addUserMessageToMessages({
|
|
@@ -402,17 +368,7 @@ export class MessageManager {
|
|
|
402
368
|
public updateToolBlock(params: AgentToolBlockUpdateParams): void {
|
|
403
369
|
const newMessages = updateToolBlockInMessage({
|
|
404
370
|
messages: this.messages,
|
|
405
|
-
|
|
406
|
-
parameters: params.parameters,
|
|
407
|
-
result: params.result,
|
|
408
|
-
success: params.success,
|
|
409
|
-
error: params.error,
|
|
410
|
-
stage: params.stage,
|
|
411
|
-
name: params.name,
|
|
412
|
-
shortResult: params.shortResult,
|
|
413
|
-
images: params.images,
|
|
414
|
-
compactParams: params.compactParams,
|
|
415
|
-
parametersChunk: params.parametersChunk,
|
|
371
|
+
...params,
|
|
416
372
|
});
|
|
417
373
|
this.setMessages(newMessages);
|
|
418
374
|
this.callbacks.onToolBlockUpdated?.(params);
|
|
@@ -442,14 +398,14 @@ export class MessageManager {
|
|
|
442
398
|
}
|
|
443
399
|
|
|
444
400
|
/**
|
|
445
|
-
* Compress messages and update session, delete compressed messages, only keep compressed messages and
|
|
401
|
+
* Compress messages and update session, delete compressed messages, only keep compressed messages and last 3 messages
|
|
446
402
|
*/
|
|
447
403
|
public compressMessagesAndUpdateSession(
|
|
448
|
-
insertIndex: number,
|
|
449
404
|
compressedContent: string,
|
|
450
405
|
usage?: Usage,
|
|
451
406
|
): void {
|
|
452
|
-
|
|
407
|
+
// Get last 3 messages to preserve
|
|
408
|
+
const lastThreeMessages = this.messages.slice(-3);
|
|
453
409
|
|
|
454
410
|
// Create compressed message
|
|
455
411
|
const compressMessage: Message = {
|
|
@@ -464,24 +420,24 @@ export class MessageManager {
|
|
|
464
420
|
...(usage && { usage }),
|
|
465
421
|
};
|
|
466
422
|
|
|
467
|
-
//
|
|
468
|
-
const
|
|
469
|
-
insertIndex < 0 ? currentMessages.length + insertIndex : insertIndex;
|
|
423
|
+
// Build new message array: keep the compressed message and last 3 messages
|
|
424
|
+
const newMessages: Message[] = [compressMessage, ...lastThreeMessages];
|
|
470
425
|
|
|
471
|
-
//
|
|
472
|
-
const
|
|
473
|
-
compressMessage,
|
|
474
|
-
...currentMessages.slice(actualIndex),
|
|
475
|
-
];
|
|
476
|
-
|
|
477
|
-
// Update sessionId
|
|
426
|
+
// Update sessionId and parentSessionId
|
|
427
|
+
const oldSessionId = this.sessionId;
|
|
478
428
|
this.setSessionId(generateSessionId());
|
|
429
|
+
this.parentSessionId = oldSessionId;
|
|
430
|
+
|
|
431
|
+
// Trigger task list update if this is the main session to ensure continuity
|
|
432
|
+
if (this.sessionType === "main") {
|
|
433
|
+
this.callbacks.onSessionIdChange?.(this.sessionId);
|
|
434
|
+
}
|
|
479
435
|
|
|
480
436
|
// Set new message list
|
|
481
437
|
this.setMessages(newMessages);
|
|
482
438
|
|
|
483
|
-
// Trigger compression callback
|
|
484
|
-
this.callbacks.onCompressBlockAdded?.(
|
|
439
|
+
// Trigger compression callback
|
|
440
|
+
this.callbacks.onCompressBlockAdded?.(compressedContent);
|
|
485
441
|
}
|
|
486
442
|
|
|
487
443
|
public addFileHistoryBlock(
|
|
@@ -496,6 +452,7 @@ export class MessageManager {
|
|
|
496
452
|
snapshots,
|
|
497
453
|
} as unknown as import("../types/index.js").MessageBlock);
|
|
498
454
|
this.setMessages([...this.messages]);
|
|
455
|
+
this.callbacks.onFileHistoryBlockAdded?.(snapshots);
|
|
499
456
|
}
|
|
500
457
|
}
|
|
501
458
|
|
|
@@ -529,58 +486,6 @@ export class MessageManager {
|
|
|
529
486
|
this.callbacks.onCompleteCommandMessage?.(command, exitCode);
|
|
530
487
|
}
|
|
531
488
|
|
|
532
|
-
// Subagent block methods
|
|
533
|
-
public addSubagentBlock(
|
|
534
|
-
subagentId: string,
|
|
535
|
-
subagentName: string,
|
|
536
|
-
sessionId: string,
|
|
537
|
-
configuration: SubagentConfiguration,
|
|
538
|
-
status: "active" | "completed" | "error" | "aborted" = "active",
|
|
539
|
-
parameters: {
|
|
540
|
-
description: string;
|
|
541
|
-
prompt: string;
|
|
542
|
-
subagent_type: string;
|
|
543
|
-
},
|
|
544
|
-
runInBackground?: boolean,
|
|
545
|
-
): void {
|
|
546
|
-
const params: AddSubagentBlockParams = {
|
|
547
|
-
messages: this.messages,
|
|
548
|
-
subagentId,
|
|
549
|
-
subagentName,
|
|
550
|
-
sessionId,
|
|
551
|
-
status,
|
|
552
|
-
configuration,
|
|
553
|
-
runInBackground,
|
|
554
|
-
};
|
|
555
|
-
const updatedMessages = addSubagentBlockToMessage(params);
|
|
556
|
-
this.setMessages(updatedMessages);
|
|
557
|
-
this.callbacks.onSubAgentBlockAdded?.(params.subagentId, parameters);
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
public updateSubagentBlock(
|
|
561
|
-
subagentId: string,
|
|
562
|
-
updates: Partial<{
|
|
563
|
-
status: "active" | "completed" | "error" | "aborted";
|
|
564
|
-
sessionId: string;
|
|
565
|
-
runInBackground: boolean;
|
|
566
|
-
}>,
|
|
567
|
-
): void {
|
|
568
|
-
const updatedMessages = updateSubagentBlockInMessage(
|
|
569
|
-
this.messages,
|
|
570
|
-
subagentId,
|
|
571
|
-
updates,
|
|
572
|
-
);
|
|
573
|
-
this.setMessages(updatedMessages);
|
|
574
|
-
const params: UpdateSubagentBlockParams = {
|
|
575
|
-
messages: this.messages,
|
|
576
|
-
subagentId,
|
|
577
|
-
status: updates.status || "active",
|
|
578
|
-
};
|
|
579
|
-
if (updates.status) {
|
|
580
|
-
this.callbacks.onSubAgentBlockUpdated?.(params.subagentId, params.status);
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
489
|
/**
|
|
585
490
|
* Trigger usage change callback with all usage data from assistant messages
|
|
586
491
|
*/
|
|
@@ -703,6 +608,14 @@ export class MessageManager {
|
|
|
703
608
|
this.setMessages(newMessages);
|
|
704
609
|
}
|
|
705
610
|
|
|
611
|
+
public async getFullMessageThread(): Promise<{
|
|
612
|
+
messages: Message[];
|
|
613
|
+
sessionIds: string[];
|
|
614
|
+
}> {
|
|
615
|
+
const { loadFullMessageThread } = await import("../services/session.js");
|
|
616
|
+
return loadFullMessageThread(this.sessionId, this.workdir);
|
|
617
|
+
}
|
|
618
|
+
|
|
706
619
|
/**
|
|
707
620
|
* Truncate history to a specific index and revert file changes.
|
|
708
621
|
* @param index - The index of the user message to truncate to.
|
|
@@ -712,30 +625,101 @@ export class MessageManager {
|
|
|
712
625
|
index: number,
|
|
713
626
|
reversionManager?: import("./reversionManager.js").ReversionManager,
|
|
714
627
|
): Promise<void> {
|
|
715
|
-
|
|
628
|
+
const { messages, sessionIds } = await this.getFullMessageThread();
|
|
629
|
+
|
|
630
|
+
if (index < 0 || index >= messages.length) {
|
|
716
631
|
throw new Error(`Invalid message index: ${index}`);
|
|
717
632
|
}
|
|
718
633
|
|
|
719
|
-
//
|
|
720
|
-
|
|
634
|
+
// Find which session the index belongs to
|
|
635
|
+
let targetSessionId = this.sessionId;
|
|
636
|
+
let targetIndexInSession = index;
|
|
637
|
+
|
|
638
|
+
// We need to be careful here because loadFullMessageThread might have removed "compress" blocks
|
|
639
|
+
// Let's re-calculate based on the actual messages returned.
|
|
640
|
+
// Actually, it's easier to just load sessions one by one again or keep track of counts.
|
|
641
|
+
|
|
642
|
+
// For simplicity, let's assume we want to truncate the WHOLE thread.
|
|
643
|
+
// If the index is in a previous session, we need to:
|
|
644
|
+
// 1. Load that session.
|
|
645
|
+
// 2. Truncate it.
|
|
646
|
+
// 3. Make it the current session.
|
|
647
|
+
// 4. Delete/Invalidate subsequent sessions.
|
|
648
|
+
|
|
649
|
+
// To correctly map 'index' to a session, we need to know the message count of each session
|
|
650
|
+
// as they appear in the concatenated 'messages' array.
|
|
651
|
+
|
|
652
|
+
let remainingIndex = index;
|
|
653
|
+
const { loadSessionFromJsonl } = await import("../services/session.js");
|
|
654
|
+
|
|
655
|
+
for (const sid of sessionIds) {
|
|
656
|
+
const sessionData = await loadSessionFromJsonl(sid, this.workdir);
|
|
657
|
+
if (!sessionData) continue;
|
|
658
|
+
|
|
659
|
+
const sessionMessages = sessionData.messages;
|
|
660
|
+
// If this is not the first session in the thread, it might have a compress block at the start
|
|
661
|
+
// that was removed in getFullMessageThread.
|
|
662
|
+
const hasCompressBlock = sessionMessages[0]?.blocks.some(
|
|
663
|
+
(b) => b.type === "compress",
|
|
664
|
+
);
|
|
665
|
+
const effectiveMessages =
|
|
666
|
+
hasCompressBlock && sid !== sessionIds[0]
|
|
667
|
+
? sessionMessages.slice(1)
|
|
668
|
+
: sessionMessages;
|
|
669
|
+
|
|
670
|
+
if (remainingIndex < effectiveMessages.length) {
|
|
671
|
+
targetSessionId = sid;
|
|
672
|
+
targetIndexInSession = hasCompressBlock
|
|
673
|
+
? remainingIndex + 1
|
|
674
|
+
: remainingIndex;
|
|
675
|
+
break;
|
|
676
|
+
}
|
|
677
|
+
remainingIndex -= effectiveMessages.length;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// Load the target session to perform truncation
|
|
681
|
+
const targetSessionData = await loadSessionFromJsonl(
|
|
682
|
+
targetSessionId,
|
|
683
|
+
this.workdir,
|
|
684
|
+
);
|
|
685
|
+
if (!targetSessionData)
|
|
686
|
+
throw new Error(`Target session ${targetSessionId} not found`);
|
|
687
|
+
|
|
688
|
+
// Identify messages to be removed (from the whole thread)
|
|
689
|
+
const messagesToRemove = messages.slice(index);
|
|
721
690
|
const messageIdsToRemove = messagesToRemove
|
|
722
691
|
.map((m) => m.id as string)
|
|
723
692
|
.filter((id) => !!id);
|
|
724
693
|
|
|
725
694
|
// Revert file changes if manager is provided
|
|
726
695
|
if (reversionManager && messageIdsToRemove.length > 0) {
|
|
727
|
-
await reversionManager.revertTo(messageIdsToRemove,
|
|
696
|
+
await reversionManager.revertTo(messageIdsToRemove, messages);
|
|
728
697
|
}
|
|
729
698
|
|
|
730
|
-
// Truncate messages in
|
|
731
|
-
const
|
|
732
|
-
|
|
699
|
+
// Truncate messages in the target session
|
|
700
|
+
const newMessagesInSession = targetSessionData.messages.slice(
|
|
701
|
+
0,
|
|
702
|
+
targetIndexInSession,
|
|
703
|
+
);
|
|
733
704
|
|
|
734
|
-
// Update
|
|
735
|
-
|
|
705
|
+
// Update target session file
|
|
706
|
+
this.sessionId = targetSessionId;
|
|
707
|
+
this.rootSessionId = targetSessionData.rootSessionId || targetSessionId;
|
|
708
|
+
this.parentSessionId = targetSessionData.parentSessionId;
|
|
709
|
+
this.transcriptPath = this.computeTranscriptPath();
|
|
710
|
+
|
|
711
|
+
await this.rewriteSessionFile(newMessagesInSession);
|
|
712
|
+
|
|
713
|
+
// Update in-memory messages to the truncated session messages
|
|
714
|
+
// We do NOT include ancestor messages here to avoid exceeding context limits.
|
|
715
|
+
// The 'compress' block at the start of the session (if any) already summarizes them.
|
|
716
|
+
this.setMessages(newMessagesInSession);
|
|
736
717
|
|
|
737
718
|
// Update saved message count
|
|
738
|
-
this.savedMessageCount =
|
|
719
|
+
this.savedMessageCount = newMessagesInSession.length;
|
|
720
|
+
|
|
721
|
+
// Notify session ID change if it changed
|
|
722
|
+
this.callbacks.onSessionIdChange?.(this.sessionId);
|
|
739
723
|
}
|
|
740
724
|
|
|
741
725
|
/**
|
|
@@ -323,40 +323,30 @@ export class PermissionManager {
|
|
|
323
323
|
workdir,
|
|
324
324
|
);
|
|
325
325
|
if (!isInside) {
|
|
326
|
-
this.logger?.
|
|
327
|
-
"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",
|
|
328
328
|
{
|
|
329
329
|
toolName: context.toolName,
|
|
330
330
|
targetPath,
|
|
331
331
|
resolvedPath,
|
|
332
332
|
},
|
|
333
333
|
);
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
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" };
|
|
338
343
|
}
|
|
339
344
|
}
|
|
340
|
-
|
|
341
|
-
this.logger?.debug(
|
|
342
|
-
"Permission automatically accepted for tool in acceptEdits mode",
|
|
343
|
-
{
|
|
344
|
-
toolName: context.toolName,
|
|
345
|
-
},
|
|
346
|
-
);
|
|
347
|
-
return { behavior: "allow" };
|
|
348
345
|
}
|
|
349
346
|
}
|
|
350
347
|
|
|
351
348
|
// 1.3 If plan mode, allow Read-only tools and Edit/Write for plan file
|
|
352
349
|
if (context.permissionMode === "plan") {
|
|
353
|
-
if (context.toolName === BASH_TOOL_NAME) {
|
|
354
|
-
return {
|
|
355
|
-
behavior: "deny",
|
|
356
|
-
message: "Bash commands are not allowed in plan mode.",
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
|
|
360
350
|
const writeTools = [
|
|
361
351
|
EDIT_TOOL_NAME,
|
|
362
352
|
MULTI_EDIT_TOOL_NAME,
|
|
@@ -492,6 +482,27 @@ export class PermissionManager {
|
|
|
492
482
|
suggestedPrefix,
|
|
493
483
|
};
|
|
494
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
|
+
|
|
495
506
|
// Set hidePersistentOption for dangerous or out-of-bounds bash commands
|
|
496
507
|
if (toolName === BASH_TOOL_NAME && toolInput?.command) {
|
|
497
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 };
|
|
@@ -123,10 +123,15 @@ export class ReversionManager {
|
|
|
123
123
|
const sortedSnapshots = snapshots.sort((a, b) => b.timestamp - a.timestamp);
|
|
124
124
|
|
|
125
125
|
let revertedCount = 0;
|
|
126
|
+
const affectedTaskListIds = new Set<string>();
|
|
127
|
+
|
|
126
128
|
for (const snapshot of sortedSnapshots) {
|
|
127
129
|
try {
|
|
128
|
-
if (
|
|
129
|
-
//
|
|
130
|
+
if (snapshot.operation === "create") {
|
|
131
|
+
// For 'create' operations, we should hard delete the file upon reversion
|
|
132
|
+
await fs.rm(snapshot.filePath, { force: true });
|
|
133
|
+
} else if (!snapshot.snapshotPath) {
|
|
134
|
+
// Fallback for older snapshots or if snapshotPath is missing
|
|
130
135
|
await fs.rm(snapshot.filePath, { force: true });
|
|
131
136
|
} else {
|
|
132
137
|
// Restore previous content
|
|
@@ -141,12 +146,31 @@ export class ReversionManager {
|
|
|
141
146
|
await fs.rm(snapshot.filePath, { force: true });
|
|
142
147
|
}
|
|
143
148
|
}
|
|
149
|
+
|
|
150
|
+
// Check if this is a task file and track the task list ID
|
|
151
|
+
if (snapshot.filePath.includes("/.wave/tasks/")) {
|
|
152
|
+
const parts = snapshot.filePath.split("/.wave/tasks/");
|
|
153
|
+
if (parts.length > 1) {
|
|
154
|
+
const taskListId = parts[1].split("/")[0];
|
|
155
|
+
if (taskListId) {
|
|
156
|
+
affectedTaskListIds.add(taskListId);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
144
161
|
revertedCount++;
|
|
145
162
|
} catch (error) {
|
|
146
163
|
console.error(`Failed to revert file ${snapshot.filePath}:`, error);
|
|
147
164
|
}
|
|
148
165
|
}
|
|
149
166
|
|
|
167
|
+
// Notify TaskManager if any task lists were affected
|
|
168
|
+
// Note: In the current architecture, TaskManager is managed by Agent and
|
|
169
|
+
// listens for file changes if it's a foreground process, or we might need
|
|
170
|
+
// to explicitly trigger a refresh. Since ReversionManager doesn't have
|
|
171
|
+
// a direct reference to TaskManager, we rely on the fact that TaskManager
|
|
172
|
+
// will see the file system changes or be refreshed by the Agent/UI.
|
|
173
|
+
|
|
150
174
|
return revertedCount;
|
|
151
175
|
}
|
|
152
176
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { MessageManager } from "./messageManager.js";
|
|
2
2
|
import type { AIManager } from "./aiManager.js";
|
|
3
3
|
import type { BackgroundTaskManager } from "./backgroundTaskManager.js";
|
|
4
|
+
import type { TaskManager } from "../services/taskManager.js";
|
|
4
5
|
import type {
|
|
5
6
|
SlashCommand,
|
|
6
7
|
CustomSlashCommand,
|
|
@@ -20,7 +21,7 @@ import {
|
|
|
20
21
|
} from "../utils/markdownParser.js";
|
|
21
22
|
import { exec } from "child_process";
|
|
22
23
|
import { promisify } from "util";
|
|
23
|
-
import { INIT_PROMPT } from "../
|
|
24
|
+
import { INIT_PROMPT } from "../prompts/index.js";
|
|
24
25
|
|
|
25
26
|
const execAsync = promisify(exec);
|
|
26
27
|
|
|
@@ -28,6 +29,7 @@ export interface SlashCommandManagerOptions {
|
|
|
28
29
|
messageManager: MessageManager;
|
|
29
30
|
aiManager: AIManager;
|
|
30
31
|
backgroundTaskManager: BackgroundTaskManager;
|
|
32
|
+
taskManager: TaskManager;
|
|
31
33
|
workdir: string;
|
|
32
34
|
logger?: Logger;
|
|
33
35
|
}
|
|
@@ -38,6 +40,7 @@ export class SlashCommandManager {
|
|
|
38
40
|
private messageManager: MessageManager;
|
|
39
41
|
private aiManager: AIManager;
|
|
40
42
|
private backgroundTaskManager: BackgroundTaskManager;
|
|
43
|
+
private taskManager: TaskManager;
|
|
41
44
|
private workdir: string;
|
|
42
45
|
private logger?: Logger;
|
|
43
46
|
|
|
@@ -45,6 +48,7 @@ export class SlashCommandManager {
|
|
|
45
48
|
this.messageManager = options.messageManager;
|
|
46
49
|
this.aiManager = options.aiManager;
|
|
47
50
|
this.backgroundTaskManager = options.backgroundTaskManager;
|
|
51
|
+
this.taskManager = options.taskManager;
|
|
48
52
|
this.workdir = options.workdir;
|
|
49
53
|
this.logger = options.logger;
|
|
50
54
|
|
|
@@ -61,8 +65,13 @@ export class SlashCommandManager {
|
|
|
61
65
|
handler: () => {
|
|
62
66
|
// Clear chat messages
|
|
63
67
|
this.messageManager.clearMessages();
|
|
64
|
-
|
|
65
|
-
|
|
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
|
+
}
|
|
66
75
|
},
|
|
67
76
|
});
|
|
68
77
|
|