wave-agent-sdk 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/agent.d.ts +0 -5
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +3 -67
  4. package/dist/constants/subagents.d.ts +5 -0
  5. package/dist/constants/subagents.d.ts.map +1 -0
  6. package/dist/constants/subagents.js +4 -0
  7. package/dist/managers/aiManager.d.ts.map +1 -1
  8. package/dist/managers/aiManager.js +9 -25
  9. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  10. package/dist/managers/backgroundTaskManager.js +4 -0
  11. package/dist/managers/messageManager.d.ts +0 -18
  12. package/dist/managers/messageManager.d.ts.map +1 -1
  13. package/dist/managers/messageManager.js +1 -36
  14. package/dist/managers/reversionManager.d.ts.map +1 -1
  15. package/dist/managers/reversionManager.js +23 -2
  16. package/dist/managers/slashCommandManager.js +1 -1
  17. package/dist/managers/subagentManager.d.ts +4 -14
  18. package/dist/managers/subagentManager.d.ts.map +1 -1
  19. package/dist/managers/subagentManager.js +35 -109
  20. package/dist/{constants/prompts.d.ts → prompts/index.d.ts} +7 -8
  21. package/dist/prompts/index.d.ts.map +1 -0
  22. package/dist/{constants/prompts.js → prompts/index.js} +127 -11
  23. package/dist/services/aiService.js +1 -1
  24. package/dist/services/taskManager.d.ts +5 -1
  25. package/dist/services/taskManager.d.ts.map +1 -1
  26. package/dist/services/taskManager.js +6 -0
  27. package/dist/tools/bashTool.d.ts.map +1 -1
  28. package/dist/tools/bashTool.js +34 -29
  29. package/dist/tools/exitPlanMode.js +1 -1
  30. package/dist/tools/taskManagementTools.d.ts.map +1 -1
  31. package/dist/tools/taskManagementTools.js +8 -0
  32. package/dist/tools/taskTool.d.ts.map +1 -1
  33. package/dist/tools/taskTool.js +32 -2
  34. package/dist/tools/types.d.ts +2 -0
  35. package/dist/tools/types.d.ts.map +1 -1
  36. package/dist/types/messaging.d.ts +1 -11
  37. package/dist/types/messaging.d.ts.map +1 -1
  38. package/dist/types/processes.d.ts +5 -0
  39. package/dist/types/processes.d.ts.map +1 -1
  40. package/dist/utils/builtinSubagents.d.ts.map +1 -1
  41. package/dist/utils/builtinSubagents.js +28 -50
  42. package/dist/utils/editUtils.d.ts.map +1 -1
  43. package/dist/utils/editUtils.js +2 -2
  44. package/dist/utils/gitUtils.d.ts +7 -0
  45. package/dist/utils/gitUtils.d.ts.map +1 -0
  46. package/dist/utils/gitUtils.js +24 -0
  47. package/dist/utils/messageOperations.d.ts +1 -23
  48. package/dist/utils/messageOperations.d.ts.map +1 -1
  49. package/dist/utils/messageOperations.js +0 -49
  50. package/package.json +1 -1
  51. package/src/agent.ts +3 -89
  52. package/src/constants/subagents.ts +4 -0
  53. package/src/managers/aiManager.ts +9 -25
  54. package/src/managers/backgroundTaskManager.ts +5 -0
  55. package/src/managers/messageManager.ts +0 -80
  56. package/src/managers/reversionManager.ts +26 -2
  57. package/src/managers/slashCommandManager.ts +1 -1
  58. package/src/managers/subagentManager.ts +42 -145
  59. package/src/{constants/prompts.ts → prompts/index.ts} +136 -13
  60. package/src/services/aiService.ts +1 -1
  61. package/src/services/taskManager.ts +8 -1
  62. package/src/tools/bashTool.ts +35 -30
  63. package/src/tools/exitPlanMode.ts +1 -1
  64. package/src/tools/taskManagementTools.ts +18 -0
  65. package/src/tools/taskTool.ts +39 -1
  66. package/src/tools/types.ts +2 -0
  67. package/src/types/messaging.ts +0 -12
  68. package/src/types/processes.ts +5 -0
  69. package/src/utils/builtinSubagents.ts +41 -51
  70. package/src/utils/editUtils.ts +2 -6
  71. package/src/utils/gitUtils.ts +24 -0
  72. package/src/utils/messageOperations.ts +1 -93
  73. package/dist/constants/prompts.d.ts.map +0 -1
package/src/agent.ts CHANGED
@@ -50,7 +50,6 @@ import {
50
50
  loadSessionFromJsonl,
51
51
  handleSessionRestoration,
52
52
  } from "./services/session.js";
53
- import type { SubagentConfiguration } from "./utils/subagentParser.js";
54
53
  import { setGlobalLogger } from "./utils/globalLogger.js";
55
54
  import { ConfigurationService } from "./services/configurationService.js";
56
55
  import * as fs from "fs/promises";
@@ -232,9 +231,6 @@ export class Agent {
232
231
  );
233
232
  callbacks.onSessionIdChange?.(sessionId);
234
233
  },
235
- onSubagentTaskStopRequested: (subagentId) => {
236
- this.backgroundTaskManager.stopTask(subagentId);
237
- },
238
234
  },
239
235
  workdir: this.workdir,
240
236
  logger: this.logger,
@@ -362,7 +358,6 @@ export class Agent {
362
358
  this.subagentManager = new SubagentManager({
363
359
  workdir: this.workdir,
364
360
  parentToolManager: this.toolManager,
365
- parentMessageManager: this.messageManager,
366
361
  callbacks: {
367
362
  onSubagentUserMessageAdded: callbacks.onSubagentUserMessageAdded,
368
363
  onSubagentAssistantMessageAdded:
@@ -812,9 +807,6 @@ export class Agent {
812
807
  // Rebuild usage array from restored messages
813
808
  this.rebuildUsageFromMessages(sessionToRestore?.messages || []);
814
809
 
815
- // After main session is restored, restore any associated subagent sessions
816
- await this.restoreSubagentSessions(sessionToRestore?.messages || []);
817
-
818
810
  if (sessionToRestore) {
819
811
  this.messageManager.initializeFromSession(sessionToRestore);
820
812
 
@@ -830,85 +822,6 @@ export class Agent {
830
822
  }
831
823
  }
832
824
 
833
- /**
834
- * Restore subagent sessions associated with the current main session
835
- * This method is called after the main session is restored to load any subagent sessions
836
- */
837
- private async restoreSubagentSessions(messages: Message[]): Promise<void> {
838
- try {
839
- // Only attempt to restore subagent sessions if we have messages (session was restored)
840
- if (messages.length === 0) {
841
- return;
842
- }
843
-
844
- // Extract sessionId -> subagentId mapping from SubagentBlocks
845
- const subagentBlockMap = new Map<
846
- string,
847
- { subagentId: string; configuration: SubagentConfiguration }
848
- >(); // sessionId -> { subagentId, configuration }
849
-
850
- for (const message of messages) {
851
- if (message.role === "assistant" && message.blocks) {
852
- for (const block of message.blocks) {
853
- if (
854
- block.type === "subagent" &&
855
- block.sessionId &&
856
- block.subagentId &&
857
- block.configuration
858
- ) {
859
- subagentBlockMap.set(block.sessionId, {
860
- subagentId: block.subagentId,
861
- configuration: block.configuration,
862
- });
863
- }
864
- }
865
- }
866
- }
867
-
868
- if (subagentBlockMap.size === 0) {
869
- return; // No subagent blocks found
870
- }
871
-
872
- // Load subagent sessions using sessionIds
873
- const subagentSessions = [];
874
- for (const [sessionId, blockData] of subagentBlockMap) {
875
- try {
876
- const sessionData = await loadSessionFromJsonl(
877
- sessionId,
878
- this.messageManager.getWorkdir(),
879
- "subagent",
880
- );
881
- if (sessionData) {
882
- subagentSessions.push({
883
- sessionData,
884
- subagentId: blockData.subagentId, // Use the subagentId from SubagentBlock
885
- configuration: blockData.configuration, // Include configuration
886
- });
887
- }
888
- } catch (error) {
889
- this.logger?.warn(
890
- `Failed to load subagent session ${sessionId}:`,
891
- error,
892
- );
893
- }
894
- }
895
-
896
- if (subagentSessions.length > 0) {
897
- this.logger?.debug(
898
- `Found ${subagentSessions.length} subagent sessions to restore`,
899
- );
900
-
901
- // Restore subagent sessions through the SubagentManager
902
- await this.subagentManager.restoreSubagentSessions(subagentSessions);
903
-
904
- this.logger?.debug("Subagent sessions restored successfully");
905
- }
906
- } catch (error) {
907
- this.logger?.warn("Failed to restore subagent sessions:", error);
908
- // Don't throw error to prevent app startup failure
909
- }
910
- }
911
-
912
825
  /**
913
826
  * Restore a session by ID, switching to the target session without destroying the Agent instance
914
827
  * @param sessionId - The ID of the session to restore
@@ -943,9 +856,8 @@ export class Agent {
943
856
  this.abortMessage(); // Abort any running operations
944
857
  this.subagentManager.cleanup(); // Clean up active subagents
945
858
 
946
- // 5. Rebuild usage and restore subagents (in correct order)
859
+ // 5. Rebuild usage (in correct order)
947
860
  this.rebuildUsageFromMessages(sessionData.messages);
948
- await this.restoreSubagentSessions(sessionData.messages);
949
861
 
950
862
  // 6. Initialize session state last
951
863
  this.messageManager.initializeFromSession(sessionData);
@@ -1240,6 +1152,8 @@ export class Agent {
1240
1152
  */
1241
1153
  public async truncateHistory(index: number): Promise<void> {
1242
1154
  await this.messageManager.truncateHistory(index, this.reversionManager);
1155
+ // After truncating history, the task list might have changed, so refresh it.
1156
+ await this.taskManager.refreshTasks();
1243
1157
  }
1244
1158
 
1245
1159
  /**
@@ -0,0 +1,4 @@
1
+ export const BASH_SUBAGENT_TYPE = "Bash";
2
+ export const EXPLORE_SUBAGENT_TYPE = "Explore";
3
+ export const PLAN_SUBAGENT_TYPE = "Plan";
4
+ export const GENERAL_PURPOSE_SUBAGENT_TYPE = "general-purpose";
@@ -1,5 +1,3 @@
1
- import * as os from "node:os";
2
- import * as path from "node:path";
3
1
  import {
4
2
  callAgent,
5
3
  compressMessages,
@@ -7,7 +5,6 @@ import {
7
5
  } from "../services/aiService.js";
8
6
  import { convertMessagesForAPI } from "../utils/convertMessagesForAPI.js";
9
7
  import { calculateComprehensiveTotalTokens } from "../utils/tokenCalculation.js";
10
- import * as fsSync from "node:fs";
11
8
  import * as fs from "node:fs/promises";
12
9
  import type {
13
10
  Logger,
@@ -23,24 +20,7 @@ import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
23
20
  import type { HookManager } from "./hookManager.js";
24
21
  import type { ExtendedHookExecutionContext } from "../types/hooks.js";
25
22
  import type { PermissionManager } from "./permissionManager.js";
26
- import { buildSystemPrompt } from "../constants/prompts.js";
27
-
28
- function isGitRepository(dirPath: string): string {
29
- try {
30
- // Check if .git directory exists in current directory or any parent directory
31
- let currentPath = path.resolve(dirPath);
32
- while (currentPath !== path.dirname(currentPath)) {
33
- const gitPath = path.join(currentPath, ".git");
34
- if (fsSync.existsSync(gitPath)) {
35
- return "Yes";
36
- }
37
- currentPath = path.dirname(currentPath);
38
- }
39
- return "No";
40
- } catch {
41
- return "No";
42
- }
43
- }
23
+ import { buildSystemPrompt } from "../prompts/index.js";
44
24
 
45
25
  export interface AIManagerCallbacks {
46
26
  onCompressionStateChange?: (isCompressing: boolean) => void;
@@ -399,12 +379,9 @@ export class AIManager {
399
379
  filteredToolPlugins,
400
380
  {
401
381
  workdir: this.workdir,
402
- isGitRepo: isGitRepository(this.workdir),
403
- platform: os.platform(),
404
- osVersion: `${os.type()} ${os.release()}`,
405
- today: new Date().toISOString().split("T")[0],
406
382
  memory: combinedMemory,
407
383
  language: this.getLanguage(),
384
+ isSubagent: !!this.subagentType,
408
385
  planMode: planModeOptions,
409
386
  },
410
387
  ), // Pass custom system prompt
@@ -643,6 +620,13 @@ export class AIManager {
643
620
  messageId: this.messageManager.getMessages().slice(-1)[0]?.id,
644
621
  sessionId: this.messageManager.getSessionId(),
645
622
  taskManager: this.taskManager,
623
+ onShortResultUpdate: (shortResult: string) => {
624
+ this.messageManager.updateToolBlock({
625
+ id: toolId,
626
+ shortResult,
627
+ stage: "running", // Keep it in running stage while updating shortResult
628
+ });
629
+ },
646
630
  };
647
631
 
648
632
  // Execute tool
@@ -285,6 +285,11 @@ export class BackgroundTaskManager {
285
285
  }
286
286
  }
287
287
 
288
+ // If it's a subagent task, we should also notify the subagent manager to cleanup
289
+ // However, to avoid circular dependency, we rely on the onStop callback
290
+ // which is already set to instance.aiManager.abortAIMessage()
291
+ // The subagentManager.cleanupInstance will be called by the tool or by status change.
292
+
288
293
  task.status = "killed";
289
294
  task.endTime = Date.now();
290
295
  task.runtime = task.endTime - task.startTime;
@@ -6,15 +6,10 @@ import {
6
6
  addCommandOutputMessage,
7
7
  updateCommandOutputInMessage,
8
8
  completeCommandInMessage,
9
- addSubagentBlockToMessage,
10
- updateSubagentBlockInMessage,
11
9
  removeLastUserMessage,
12
10
  UserMessageParams,
13
- type AddSubagentBlockParams,
14
- type UpdateSubagentBlockParams,
15
11
  type AgentToolBlockUpdateParams,
16
12
  } from "../utils/messageOperations.js";
17
- import type { SubagentConfiguration } from "../utils/subagentParser.js";
18
13
  import type { Logger, Message, Usage, SlashCommand } from "../types/index.js";
19
14
  import { join } from "path";
20
15
  import {
@@ -59,23 +54,9 @@ export interface MessageManagerCallbacks {
59
54
  onInfoBlockAdded?: (content: string) => void;
60
55
  // Rewind callbacks
61
56
  onShowRewind?: () => void;
62
- // Subagent callbacks
63
- onSubAgentBlockAdded?: (
64
- subagentId: string,
65
- parameters: {
66
- description: string;
67
- prompt: string;
68
- subagent_type: string;
69
- },
70
- ) => void;
71
- onSubAgentBlockUpdated?: (
72
- subagentId: string,
73
- status: "active" | "completed" | "error" | "aborted",
74
- ) => void;
75
57
  onFileHistoryBlockAdded?: (
76
58
  snapshots: import("../types/reversion.js").FileSnapshot[],
77
59
  ) => void;
78
- onSubagentTaskStopRequested?: (subagentId: string) => void;
79
60
  }
80
61
 
81
62
  export interface MessageManagerOptions {
@@ -505,58 +486,6 @@ export class MessageManager {
505
486
  this.callbacks.onCompleteCommandMessage?.(command, exitCode);
506
487
  }
507
488
 
508
- // Subagent block methods
509
- public addSubagentBlock(
510
- subagentId: string,
511
- subagentName: string,
512
- sessionId: string,
513
- configuration: SubagentConfiguration,
514
- status: "active" | "completed" | "error" | "aborted" = "active",
515
- parameters: {
516
- description: string;
517
- prompt: string;
518
- subagent_type: string;
519
- },
520
- runInBackground?: boolean,
521
- ): void {
522
- const params: AddSubagentBlockParams = {
523
- messages: this.messages,
524
- subagentId,
525
- subagentName,
526
- sessionId,
527
- status,
528
- configuration,
529
- runInBackground,
530
- };
531
- const updatedMessages = addSubagentBlockToMessage(params);
532
- this.setMessages(updatedMessages);
533
- this.callbacks.onSubAgentBlockAdded?.(params.subagentId, parameters);
534
- }
535
-
536
- public updateSubagentBlock(
537
- subagentId: string,
538
- updates: Partial<{
539
- status: "active" | "completed" | "error" | "aborted";
540
- sessionId: string;
541
- runInBackground: boolean;
542
- }>,
543
- ): void {
544
- const updatedMessages = updateSubagentBlockInMessage(
545
- this.messages,
546
- subagentId,
547
- updates,
548
- );
549
- this.setMessages(updatedMessages);
550
- const params: UpdateSubagentBlockParams = {
551
- messages: this.messages,
552
- subagentId,
553
- status: updates.status || "active",
554
- };
555
- if (updates.status) {
556
- this.callbacks.onSubAgentBlockUpdated?.(params.subagentId, params.status);
557
- }
558
- }
559
-
560
489
  /**
561
490
  * Trigger usage change callback with all usage data from assistant messages
562
491
  */
@@ -773,15 +702,6 @@ export class MessageManager {
773
702
  targetIndexInSession,
774
703
  );
775
704
 
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
- }
784
-
785
705
  // Update target session file
786
706
  this.sessionId = targetSessionId;
787
707
  this.rootSessionId = targetSessionData.rootSessionId || targetSessionId;
@@ -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 (!snapshot.snapshotPath) {
129
- // File didn't exist before, so delete it
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
  }
@@ -21,7 +21,7 @@ import {
21
21
  } from "../utils/markdownParser.js";
22
22
  import { exec } from "child_process";
23
23
  import { promisify } from "util";
24
- import { INIT_PROMPT } from "../constants/prompts.js";
24
+ import { INIT_PROMPT } from "../prompts/index.js";
25
25
 
26
26
  const execAsync = promisify(exec);
27
27