wave-agent-sdk 0.5.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.
Files changed (152) hide show
  1. package/dist/agent.d.ts +14 -6
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +65 -88
  4. package/dist/constants/prompts.d.ts +18 -14
  5. package/dist/constants/prompts.d.ts.map +1 -1
  6. package/dist/constants/prompts.js +130 -54
  7. package/dist/constants/tools.d.ts +4 -1
  8. package/dist/constants/tools.d.ts.map +1 -1
  9. package/dist/constants/tools.js +4 -1
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -0
  13. package/dist/managers/aiManager.d.ts +2 -5
  14. package/dist/managers/aiManager.d.ts.map +1 -1
  15. package/dist/managers/aiManager.js +59 -48
  16. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  17. package/dist/managers/backgroundTaskManager.js +59 -53
  18. package/dist/managers/foregroundTaskManager.d.ts.map +1 -1
  19. package/dist/managers/foregroundTaskManager.js +3 -2
  20. package/dist/managers/mcpManager.d.ts.map +1 -1
  21. package/dist/managers/messageManager.d.ts +14 -10
  22. package/dist/managers/messageManager.d.ts.map +1 -1
  23. package/dist/managers/messageManager.js +102 -62
  24. package/dist/managers/permissionManager.d.ts.map +1 -1
  25. package/dist/managers/permissionManager.js +25 -15
  26. package/dist/managers/planManager.d.ts +1 -1
  27. package/dist/managers/planManager.d.ts.map +1 -1
  28. package/dist/managers/planManager.js +2 -2
  29. package/dist/managers/slashCommandManager.d.ts +3 -0
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +7 -2
  32. package/dist/managers/subagentManager.d.ts +4 -0
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +22 -14
  35. package/dist/managers/toolManager.d.ts +11 -0
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +20 -2
  38. package/dist/services/aiService.d.ts +0 -1
  39. package/dist/services/aiService.d.ts.map +1 -1
  40. package/dist/services/aiService.js +4 -140
  41. package/dist/services/memory.d.ts +0 -3
  42. package/dist/services/memory.d.ts.map +1 -1
  43. package/dist/services/memory.js +0 -59
  44. package/dist/services/session.d.ts +15 -1
  45. package/dist/services/session.d.ts.map +1 -1
  46. package/dist/services/session.js +57 -1
  47. package/dist/services/taskManager.d.ts +21 -0
  48. package/dist/services/taskManager.d.ts.map +1 -0
  49. package/dist/services/taskManager.js +158 -0
  50. package/dist/tools/askUserQuestion.d.ts.map +1 -1
  51. package/dist/tools/askUserQuestion.js +39 -25
  52. package/dist/tools/bashTool.d.ts.map +1 -1
  53. package/dist/tools/bashTool.js +7 -9
  54. package/dist/tools/editTool.d.ts.map +1 -1
  55. package/dist/tools/editTool.js +2 -1
  56. package/dist/tools/exitPlanMode.d.ts.map +1 -1
  57. package/dist/tools/exitPlanMode.js +25 -1
  58. package/dist/tools/globTool.d.ts.map +1 -1
  59. package/dist/tools/globTool.js +8 -2
  60. package/dist/tools/grepTool.d.ts.map +1 -1
  61. package/dist/tools/grepTool.js +17 -6
  62. package/dist/tools/lsTool.d.ts.map +1 -1
  63. package/dist/tools/lsTool.js +3 -1
  64. package/dist/tools/readTool.d.ts.map +1 -1
  65. package/dist/tools/readTool.js +16 -1
  66. package/dist/tools/taskManagementTools.d.ts +6 -0
  67. package/dist/tools/taskManagementTools.d.ts.map +1 -0
  68. package/dist/tools/taskManagementTools.js +453 -0
  69. package/dist/tools/taskOutputTool.d.ts.map +1 -1
  70. package/dist/tools/taskOutputTool.js +32 -8
  71. package/dist/tools/taskStopTool.d.ts.map +1 -1
  72. package/dist/tools/taskStopTool.js +7 -1
  73. package/dist/tools/taskTool.d.ts.map +1 -1
  74. package/dist/tools/taskTool.js +6 -1
  75. package/dist/tools/types.d.ts +9 -0
  76. package/dist/tools/types.d.ts.map +1 -1
  77. package/dist/tools/writeTool.d.ts.map +1 -1
  78. package/dist/tools/writeTool.js +9 -1
  79. package/dist/types/index.d.ts +1 -0
  80. package/dist/types/index.d.ts.map +1 -1
  81. package/dist/types/index.js +1 -0
  82. package/dist/types/messaging.d.ts +2 -8
  83. package/dist/types/messaging.d.ts.map +1 -1
  84. package/dist/types/processes.d.ts +11 -6
  85. package/dist/types/processes.d.ts.map +1 -1
  86. package/dist/types/tasks.d.ts +13 -0
  87. package/dist/types/tasks.d.ts.map +1 -0
  88. package/dist/types/tasks.js +1 -0
  89. package/dist/types/tools.d.ts +4 -1
  90. package/dist/types/tools.d.ts.map +1 -1
  91. package/dist/utils/builtinSubagents.d.ts.map +1 -1
  92. package/dist/utils/builtinSubagents.js +38 -1
  93. package/dist/utils/cacheControlUtils.d.ts.map +1 -1
  94. package/dist/utils/cacheControlUtils.js +18 -12
  95. package/dist/utils/constants.d.ts +0 -4
  96. package/dist/utils/constants.d.ts.map +1 -1
  97. package/dist/utils/constants.js +0 -4
  98. package/dist/utils/convertMessagesForAPI.js +2 -2
  99. package/dist/utils/messageOperations.d.ts +2 -35
  100. package/dist/utils/messageOperations.d.ts.map +1 -1
  101. package/dist/utils/messageOperations.js +4 -97
  102. package/dist/utils/nameGenerator.d.ts +1 -1
  103. package/dist/utils/nameGenerator.d.ts.map +1 -1
  104. package/dist/utils/nameGenerator.js +19 -3
  105. package/package.json +1 -1
  106. package/src/agent.ts +90 -101
  107. package/src/constants/prompts.ts +156 -65
  108. package/src/constants/tools.ts +4 -1
  109. package/src/index.ts +1 -0
  110. package/src/managers/aiManager.ts +79 -70
  111. package/src/managers/backgroundTaskManager.ts +53 -54
  112. package/src/managers/foregroundTaskManager.ts +3 -2
  113. package/src/managers/mcpManager.ts +6 -3
  114. package/src/managers/messageManager.ts +137 -73
  115. package/src/managers/permissionManager.ts +32 -21
  116. package/src/managers/planManager.ts +2 -2
  117. package/src/managers/slashCommandManager.ts +11 -2
  118. package/src/managers/subagentManager.ts +33 -14
  119. package/src/managers/toolManager.ts +32 -2
  120. package/src/services/aiService.ts +3 -145
  121. package/src/services/memory.ts +0 -72
  122. package/src/services/session.ts +73 -0
  123. package/src/services/taskManager.ts +188 -0
  124. package/src/tools/askUserQuestion.ts +51 -29
  125. package/src/tools/bashTool.ts +9 -15
  126. package/src/tools/editTool.ts +3 -1
  127. package/src/tools/exitPlanMode.ts +26 -2
  128. package/src/tools/globTool.ts +10 -2
  129. package/src/tools/grepTool.ts +17 -6
  130. package/src/tools/lsTool.ts +3 -1
  131. package/src/tools/readTool.ts +17 -1
  132. package/src/tools/taskManagementTools.ts +498 -0
  133. package/src/tools/taskOutputTool.ts +34 -12
  134. package/src/tools/taskStopTool.ts +7 -1
  135. package/src/tools/taskTool.ts +7 -1
  136. package/src/tools/types.ts +10 -0
  137. package/src/tools/writeTool.ts +9 -2
  138. package/src/types/index.ts +1 -0
  139. package/src/types/messaging.ts +1 -9
  140. package/src/types/processes.ts +13 -7
  141. package/src/types/tasks.ts +13 -0
  142. package/src/types/tools.ts +4 -1
  143. package/src/utils/builtinSubagents.ts +47 -1
  144. package/src/utils/cacheControlUtils.ts +26 -18
  145. package/src/utils/constants.ts +0 -5
  146. package/src/utils/convertMessagesForAPI.ts +2 -2
  147. package/src/utils/messageOperations.ts +5 -136
  148. package/src/utils/nameGenerator.ts +20 -3
  149. package/dist/tools/todoWriteTool.d.ts +0 -6
  150. package/dist/tools/todoWriteTool.d.ts.map +0 -1
  151. package/dist/tools/todoWriteTool.js +0 -220
  152. package/src/tools/todoWriteTool.ts +0 -257
@@ -1,25 +1,6 @@
1
- import { MessageSource } from "../types/index.js";
2
- import { DEFAULT_KEEP_LAST_MESSAGES_COUNT } from "./constants.js";
3
1
  import { readFileSync } from "fs";
4
2
  import { extname } from "path";
5
3
  import { logger } from "./globalLogger.js";
6
- /**
7
- * Extract text content from user messages in the messages array
8
- * Excludes messages with source HOOK to prevent hook-generated content from entering user history
9
- */
10
- export const extractUserInputHistory = (messages) => {
11
- return messages
12
- .filter((message) => message.role === "user")
13
- .map((message) => {
14
- // Extract text block content, excluding HOOK-sourced blocks
15
- const textBlocks = message.blocks.filter((block) => block.type === "text" && block.source !== MessageSource.HOOK);
16
- return textBlocks
17
- .map((block) => block.content)
18
- .join(" ")
19
- .trim();
20
- })
21
- .filter((text) => text.length > 0); // Filter out empty text
22
- };
23
4
  /**
24
5
  * Convert image file path to base64 format
25
6
  * @param imagePath Image file path
@@ -116,7 +97,7 @@ export const addAssistantMessageToMessages = (messages, content, toolCalls, usag
116
97
  return [...messages, initialAssistantMessage];
117
98
  };
118
99
  // Update Tool Block of the last assistant message
119
- export const updateToolBlockInMessage = ({ messages, id, parameters, result, success, error, stage, name, shortResult, images, compactParams, parametersChunk, }) => {
100
+ export const updateToolBlockInMessage = ({ messages, id, parameters, result, success, error, stage, name, shortResult, images, compactParams, parametersChunk, isManuallyBackgrounded, }) => {
120
101
  const newMessages = [...messages];
121
102
  // Find the last assistant message
122
103
  for (let i = newMessages.length - 1; i >= 0; i--) {
@@ -141,6 +122,8 @@ export const updateToolBlockInMessage = ({ messages, id, parameters, result, suc
141
122
  toolBlock.compactParams = compactParams;
142
123
  if (parametersChunk !== undefined)
143
124
  toolBlock.parametersChunk = parametersChunk;
125
+ if (isManuallyBackgrounded !== undefined)
126
+ toolBlock.isManuallyBackgrounded = isManuallyBackgrounded;
144
127
  }
145
128
  }
146
129
  else {
@@ -159,6 +142,7 @@ export const updateToolBlockInMessage = ({ messages, id, parameters, result, suc
159
142
  stage: stage ?? "start",
160
143
  compactParams: compactParams,
161
144
  parametersChunk: parametersChunk,
145
+ isManuallyBackgrounded: isManuallyBackgrounded,
162
146
  });
163
147
  }
164
148
  break;
@@ -198,83 +182,6 @@ export const addErrorBlockToMessage = ({ messages, error, }) => {
198
182
  }
199
183
  return newMessages;
200
184
  };
201
- // Add Memory Block as new assistant message
202
- export const addMemoryBlockToMessage = ({ messages, content, isSuccess, memoryType, storagePath, }) => {
203
- const newMessages = [...messages];
204
- // Create new assistant message containing MemoryBlock
205
- const memoryMessage = {
206
- role: "assistant",
207
- blocks: [
208
- {
209
- type: "memory",
210
- content,
211
- isSuccess,
212
- memoryType,
213
- storagePath,
214
- },
215
- ],
216
- };
217
- // Add to end of message list
218
- newMessages.push(memoryMessage);
219
- return newMessages;
220
- };
221
- /**
222
- * Count valid blocks from the end
223
- * Only text, image, and tool type blocks are counted
224
- * @param messages Message array
225
- * @param targetCount Number of valid blocks to count
226
- * @returns { messageIndex: number, blockCount: number } Message index and actual counted block count
227
- */
228
- export const countValidBlocksFromEnd = (messages, targetCount) => {
229
- let validBlockCount = 0;
230
- // Iterate messages from end to beginning
231
- for (let i = messages.length - 1; i >= 0; i--) {
232
- const message = messages[i];
233
- // Iterate through all blocks of current message
234
- for (const block of message.blocks) {
235
- // Only count valid block types
236
- if (block.type === "text" ||
237
- block.type === "image" ||
238
- block.type === "tool") {
239
- validBlockCount++;
240
- // If target count reached, return current message index
241
- if (validBlockCount >= targetCount) {
242
- return { messageIndex: i, blockCount: validBlockCount };
243
- }
244
- }
245
- }
246
- }
247
- // If target count not reached, return index 0
248
- return { messageIndex: 0, blockCount: validBlockCount };
249
- };
250
- /**
251
- * Get messages to be compressed and insertion position
252
- * @param messages Message array
253
- * @param keepLastCount Keep the last few valid blocks uncompressed
254
- * @returns { messagesToCompress: Message[], insertIndex: number }
255
- */
256
- export const getMessagesToCompress = (messages, keepLastCount = DEFAULT_KEEP_LAST_MESSAGES_COUNT) => {
257
- // Calculate message position to keep from end to beginning
258
- const { messageIndex } = countValidBlocksFromEnd(messages, keepLastCount);
259
- // Find the last message containing compression block
260
- let lastCompressIndex = -1;
261
- for (let i = messages.length - 1; i >= 0; i--) {
262
- const hasCompressBlock = messages[i].blocks.some((block) => block.type === "compress");
263
- if (hasCompressBlock) {
264
- lastCompressIndex = i;
265
- break;
266
- }
267
- }
268
- // Determine compression start position
269
- // If compression block exists, start from compression block position (include compression block)
270
- // If no compression block, start from beginning
271
- const startIndex = lastCompressIndex >= 0 ? lastCompressIndex : 0;
272
- // Messages to compress are all messages from start position to before calculated position
273
- const messagesToCompress = messages.slice(startIndex, messageIndex);
274
- // Change insertion position to negative number, indicating position from end
275
- const insertIndex = messageIndex - messages.length;
276
- return { messagesToCompress, insertIndex };
277
- };
278
185
  // Add command output block to message list
279
186
  export const addCommandOutputMessage = ({ messages, command, }) => {
280
187
  const outputMessage = {
@@ -4,5 +4,5 @@
4
4
  /**
5
5
  * Generates a random English name (adjective-noun)
6
6
  */
7
- export declare function generateRandomName(): string;
7
+ export declare function generateRandomName(seed?: string): string;
8
8
  //# sourceMappingURL=nameGenerator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"nameGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/nameGenerator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoEH;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C"}
1
+ {"version":3,"file":"nameGenerator.d.ts","sourceRoot":"","sources":["../../src/utils/nameGenerator.ts"],"names":[],"mappings":"AAAA;;GAEG;AAoEH;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAqBxD"}
@@ -68,8 +68,24 @@ const nouns = [
68
68
  /**
69
69
  * Generates a random English name (adjective-noun)
70
70
  */
71
- export function generateRandomName() {
72
- const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
73
- const noun = nouns[Math.floor(Math.random() * nouns.length)];
71
+ export function generateRandomName(seed) {
72
+ let adjIndex;
73
+ let nounIndex;
74
+ if (seed) {
75
+ // Simple hash function to derive indices from seed
76
+ let hash = 0;
77
+ for (let i = 0; i < seed.length; i++) {
78
+ hash = (hash << 5) - hash + seed.charCodeAt(i);
79
+ hash |= 0; // Convert to 32bit integer
80
+ }
81
+ adjIndex = Math.abs(hash) % adjectives.length;
82
+ nounIndex = Math.abs(hash >> 8) % nouns.length;
83
+ }
84
+ else {
85
+ adjIndex = Math.floor(Math.random() * adjectives.length);
86
+ nounIndex = Math.floor(Math.random() * nouns.length);
87
+ }
88
+ const adj = adjectives[adjIndex];
89
+ const noun = nouns[nounIndex];
74
90
  return `${adj}-${noun}`;
75
91
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-agent-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "SDK for building AI-powered development tools and agents",
5
5
  "keywords": [
6
6
  "ai",
package/src/agent.ts CHANGED
@@ -9,7 +9,6 @@ import {
9
9
  SubagentManager,
10
10
  type SubagentManagerCallbacks,
11
11
  } from "./managers/subagentManager.js";
12
- import * as memory from "./services/memory.js";
13
12
  import { McpManager, type McpManagerCallbacks } from "./managers/mcpManager.js";
14
13
  import { LspManager } from "./managers/lspManager.js";
15
14
  import { BashManager } from "./managers/bashManager.js";
@@ -46,6 +45,7 @@ import { MemoryRuleManager } from "./managers/MemoryRuleManager.js";
46
45
  import { LiveConfigManager } from "./managers/liveConfigManager.js";
47
46
  import { configValidator } from "./utils/configValidator.js";
48
47
  import { SkillManager } from "./managers/skillManager.js";
48
+ import { TaskManager } from "./services/taskManager.js";
49
49
  import {
50
50
  loadSessionFromJsonl,
51
51
  handleSessionRestoration,
@@ -107,7 +107,12 @@ export interface AgentCallbacks
107
107
  McpManagerCallbacks,
108
108
  SubagentManagerCallbacks {
109
109
  onTasksChange?: (tasks: BackgroundTask[]) => void;
110
+ onSessionTasksChange?: (tasks: import("./types/tasks.js").Task[]) => void;
110
111
  onPermissionModeChange?: (mode: PermissionMode) => void;
112
+ onSubagentLatestTotalTokensChange?: (
113
+ subagentId: string,
114
+ tokens: number,
115
+ ) => void;
111
116
  onBackgroundCurrentTask?: () => void;
112
117
  }
113
118
 
@@ -131,6 +136,7 @@ export class Agent {
131
136
  private reversionManager: ReversionManager;
132
137
  private memoryRuleManager: MemoryRuleManager; // Add memory rule manager instance
133
138
  private liveConfigManager: LiveConfigManager; // Add live configuration manager
139
+ private taskManager: TaskManager;
134
140
  private foregroundTaskManager: ForegroundTaskManager;
135
141
  private configurationService: ConfigurationService; // Add configuration service
136
142
  private workdir: string; // Working directory
@@ -208,6 +214,46 @@ export class Agent {
208
214
 
209
215
  this.foregroundTaskManager = new ForegroundTaskManager();
210
216
 
217
+ // Initialize memory rule manager
218
+ this.memoryRuleManager = new MemoryRuleManager({
219
+ workdir: this.workdir,
220
+ });
221
+
222
+ // Initialize MessageManager
223
+ this.messageManager = new MessageManager({
224
+ callbacks: {
225
+ ...callbacks,
226
+ onSessionIdChange: (sessionId) => {
227
+ // When session ID changes (e.g. due to compression),
228
+ // we update the task manager to use the root session ID
229
+ // to ensure the task list remains consistent.
230
+ this.taskManager.setTaskListId(
231
+ this.messageManager.getRootSessionId(),
232
+ );
233
+ callbacks.onSessionIdChange?.(sessionId);
234
+ },
235
+ onSubagentTaskStopRequested: (subagentId) => {
236
+ this.backgroundTaskManager.stopTask(subagentId);
237
+ },
238
+ },
239
+ workdir: this.workdir,
240
+ logger: this.logger,
241
+ memoryRuleManager: this.memoryRuleManager,
242
+ });
243
+
244
+ // Resolve taskListId once during construction to ensure stability
245
+ const resolvedTaskListId =
246
+ this.configurationService.getEnvironmentVars().WAVE_TASK_LIST_ID ||
247
+ process.env.WAVE_TASK_LIST_ID ||
248
+ this.messageManager.getRootSessionId();
249
+
250
+ this.taskManager = new TaskManager(resolvedTaskListId);
251
+ this.taskManager.on("tasksChange", async () => {
252
+ const tasks = await this.taskManager.listTasks();
253
+ this.options.callbacks?.onSessionTasksChange?.(tasks);
254
+ });
255
+
256
+ // Initialize BackgroundTaskManager
211
257
  this.backgroundTaskManager = new BackgroundTaskManager({
212
258
  callbacks: {
213
259
  ...callbacks,
@@ -243,20 +289,7 @@ export class Agent {
243
289
  workdir: this.workdir,
244
290
  });
245
291
 
246
- // Initialize memory rule manager
247
- this.memoryRuleManager = new MemoryRuleManager({
248
- workdir: this.workdir,
249
- });
250
-
251
- // Initialize MessageManager
252
- this.messageManager = new MessageManager({
253
- callbacks,
254
- workdir: this.workdir,
255
- logger: this.logger,
256
- memoryRuleManager: this.memoryRuleManager,
257
- });
258
-
259
- // Initialize ReversionManager
292
+ // ReversionManager depends on MessageManager
260
293
  this.reversionManager = new ReversionManager(
261
294
  new ReversionService(this.messageManager.getTranscriptPath()),
262
295
  );
@@ -312,6 +345,7 @@ export class Agent {
312
345
  reversionManager: this.reversionManager,
313
346
  permissionMode: options.permissionMode, // Let PermissionManager handle defaultMode resolution
314
347
  canUseToolCallback: canUseToolWithNotification,
348
+ taskManager: this.taskManager,
315
349
  backgroundTaskManager: this.backgroundTaskManager,
316
350
  foregroundTaskManager: this.foregroundTaskManager,
317
351
  }); // Initialize tool registry with permission support
@@ -339,6 +373,8 @@ export class Agent {
339
373
  callbacks.onSubagentAssistantReasoningUpdated,
340
374
  onSubagentToolBlockUpdated: callbacks.onSubagentToolBlockUpdated,
341
375
  onSubagentMessagesChange: callbacks.onSubagentMessagesChange,
376
+ onSubagentLatestTotalTokensChange:
377
+ callbacks.onSubagentLatestTotalTokensChange,
342
378
  }, // Pass subagent callbacks for forwarding
343
379
  logger: this.logger,
344
380
  getGatewayConfig: () => this.getGatewayConfig(),
@@ -348,6 +384,7 @@ export class Agent {
348
384
  hookManager: this.hookManager,
349
385
  onUsageAdded: (usage) => this.addUsage(usage),
350
386
  backgroundTaskManager: this.backgroundTaskManager,
387
+ taskManager: this.taskManager,
351
388
  memoryRuleManager: this.memoryRuleManager,
352
389
  });
353
390
 
@@ -355,6 +392,7 @@ export class Agent {
355
392
  this.aiManager = new AIManager({
356
393
  messageManager: this.messageManager,
357
394
  toolManager: this.toolManager,
395
+ taskManager: this.taskManager,
358
396
  logger: this.logger,
359
397
  backgroundTaskManager: this.backgroundTaskManager,
360
398
  hookManager: this.hookManager,
@@ -381,6 +419,7 @@ export class Agent {
381
419
  messageManager: this.messageManager,
382
420
  aiManager: this.aiManager,
383
421
  backgroundTaskManager: this.backgroundTaskManager,
422
+ taskManager: this.taskManager,
384
423
  workdir: this.workdir,
385
424
  logger: this.logger,
386
425
  });
@@ -455,10 +494,6 @@ export class Agent {
455
494
  return this.messageManager.getlatestTotalTokens();
456
495
  }
457
496
 
458
- public get userInputHistory(): string[] {
459
- return this.messageManager.getUserInputHistory();
460
- }
461
-
462
497
  /** Get working directory */
463
498
  public get workingDirectory(): string {
464
499
  return this.workdir;
@@ -780,8 +815,18 @@ export class Agent {
780
815
  // After main session is restored, restore any associated subagent sessions
781
816
  await this.restoreSubagentSessions(sessionToRestore?.messages || []);
782
817
 
783
- if (sessionToRestore)
818
+ if (sessionToRestore) {
784
819
  this.messageManager.initializeFromSession(sessionToRestore);
820
+
821
+ // Update task manager with the root session ID to ensure continuity across compressions
822
+ this.taskManager.setTaskListId(
823
+ sessionToRestore.rootSessionId || sessionToRestore.id,
824
+ );
825
+
826
+ // After session is initialized, load tasks for the session
827
+ const tasks = await this.taskManager.listTasks();
828
+ this.options.callbacks?.onSessionTasksChange?.(tasks);
829
+ }
785
830
  }
786
831
  }
787
832
 
@@ -904,6 +949,13 @@ export class Agent {
904
949
 
905
950
  // 6. Initialize session state last
906
951
  this.messageManager.initializeFromSession(sessionData);
952
+
953
+ // Update task manager with the root session ID to ensure continuity across compressions
954
+ this.taskManager.setTaskListId(sessionData.rootSessionId || sessionData.id);
955
+
956
+ // 7. Load tasks for the restored session
957
+ const tasks = await this.taskManager.listTasks();
958
+ this.options.callbacks?.onSessionTasksChange?.(tasks);
907
959
  }
908
960
 
909
961
  public abortAIMessage(): void {
@@ -912,12 +964,9 @@ export class Agent {
912
964
 
913
965
  /** Execute bash command */
914
966
  public async executeBashCommand(command: string): Promise<void> {
915
- // Add user message to history (but not displayed in UI)
916
- this.addToInputHistory(`!${command}`);
917
967
  await this.bashManager?.executeCommand(command);
918
968
  }
919
969
 
920
- /** Clear messages and input history */
921
970
  public clearMessages(): void {
922
971
  this.messageManager.clearMessages();
923
972
  }
@@ -929,11 +978,6 @@ export class Agent {
929
978
  this.abortSlashCommand();
930
979
  }
931
980
 
932
- /** Add to input history */
933
- private addToInputHistory(input: string): void {
934
- this.messageManager.addToInputHistory(input);
935
- }
936
-
937
981
  /** Interrupt bash command execution */
938
982
  public abortBashCommand(): void {
939
983
  this.bashManager?.abortCommand();
@@ -964,12 +1008,6 @@ export class Agent {
964
1008
  public async backgroundCurrentTask(): Promise<void> {
965
1009
  await this.foregroundTaskManager.backgroundCurrentTask();
966
1010
  this.options.callbacks?.onBackgroundCurrentTask?.();
967
-
968
- // If there was no foreground task (e.g. a tool that doesn't register one),
969
- // or even if there was, we should stop the AI recursion loop.
970
- if (!this.foregroundTaskManager.hasActiveTasks()) {
971
- this.aiManager.abortRecursion();
972
- }
973
1011
  }
974
1012
 
975
1013
  /** Destroy managers, clean up resources */
@@ -1061,8 +1099,6 @@ export class Agent {
1061
1099
  // Execute valid slash command
1062
1100
  await this.slashCommandManager.executeCommand(commandId, args);
1063
1101
 
1064
- // Add slash command to history
1065
- this.addToInputHistory(command);
1066
1102
  return;
1067
1103
  }
1068
1104
 
@@ -1071,9 +1107,6 @@ export class Agent {
1071
1107
  }
1072
1108
 
1073
1109
  // Handle normal AI message
1074
- // Add user message to history
1075
- this.addToInputHistory(content);
1076
-
1077
1110
  // Add user message first, will automatically sync to UI
1078
1111
  this.messageManager.addUserMessage({
1079
1112
  content,
@@ -1130,67 +1163,6 @@ export class Agent {
1130
1163
  }
1131
1164
  }
1132
1165
 
1133
- /** Save memory to project or user memory file */
1134
- public async saveMemory(
1135
- message: string,
1136
- type: "project" | "user",
1137
- ): Promise<void> {
1138
- try {
1139
- // Ensure the message starts with # for memory functions
1140
- const formattedMessage = message.startsWith("#")
1141
- ? message
1142
- : `#${message}`;
1143
-
1144
- if (type === "project") {
1145
- await memory.addMemory(formattedMessage, this.workdir);
1146
- // Update internal state after successful save
1147
- this._projectMemoryContent = await memory.readMemoryFile(this.workdir);
1148
- } else {
1149
- await memory.addUserMemory(formattedMessage);
1150
- // Update internal state after successful save
1151
- this._userMemoryContent = await memory.getUserMemoryContent();
1152
- }
1153
-
1154
- // Add successful MemoryBlock to the last assistant message
1155
- const memoryText = message.substring(1).trim();
1156
- const typeLabel = type === "project" ? "Project Memory" : "User Memory";
1157
- const storagePath = "AGENTS.md";
1158
-
1159
- const messages = this.messageManager.getMessages();
1160
- const lastMessage = messages[messages.length - 1];
1161
- if (lastMessage && lastMessage.role === "assistant") {
1162
- lastMessage.blocks.push({
1163
- type: "memory",
1164
- content: `${typeLabel}: ${memoryText}`,
1165
- isSuccess: true,
1166
- memoryType: type,
1167
- storagePath,
1168
- });
1169
- this.messageManager.setMessages(messages);
1170
- }
1171
- } catch (error) {
1172
- // Add failed MemoryBlock to the last assistant message
1173
- const memoryText = message.substring(1).trim();
1174
- const typeLabel = type === "project" ? "Project Memory" : "User Memory";
1175
- const storagePath = "AGENTS.md";
1176
- const errorMessage =
1177
- error instanceof Error ? error.message : String(error);
1178
-
1179
- const messages = this.messageManager.getMessages();
1180
- const lastMessage = messages[messages.length - 1];
1181
- if (lastMessage && lastMessage.role === "assistant") {
1182
- lastMessage.blocks.push({
1183
- type: "memory",
1184
- content: `${typeLabel}: ${memoryText} - Error: ${errorMessage}`,
1185
- isSuccess: false,
1186
- memoryType: type,
1187
- storagePath,
1188
- });
1189
- this.messageManager.setMessages(messages);
1190
- }
1191
- }
1192
- }
1193
-
1194
1166
  // ========== MCP Management Methods ==========
1195
1167
 
1196
1168
  /** Get all MCP server status */
@@ -1270,6 +1242,16 @@ export class Agent {
1270
1242
  await this.messageManager.truncateHistory(index, this.reversionManager);
1271
1243
  }
1272
1244
 
1245
+ /**
1246
+ * Get the full message thread including parent sessions
1247
+ */
1248
+ public async getFullMessageThread(): Promise<{
1249
+ messages: Message[];
1250
+ sessionIds: string[];
1251
+ }> {
1252
+ return this.messageManager.getFullMessageThread();
1253
+ }
1254
+
1273
1255
  /**
1274
1256
  * Get the current plan file path (for testing and UI)
1275
1257
  */
@@ -1338,7 +1320,7 @@ export class Agent {
1338
1320
  private handlePlanModeTransition(mode: PermissionMode): void {
1339
1321
  if (mode === "plan") {
1340
1322
  this.planManager
1341
- .getOrGeneratePlanFilePath()
1323
+ .getOrGeneratePlanFilePath(this.messageManager.getRootSessionId())
1342
1324
  .then(({ path }) => {
1343
1325
  this.logger?.debug("Plan file path generated", { path });
1344
1326
  this.permissionManager.setPlanFilePath(path);
@@ -1350,4 +1332,11 @@ export class Agent {
1350
1332
  this.permissionManager.setPlanFilePath(undefined);
1351
1333
  }
1352
1334
  }
1335
+
1336
+ /**
1337
+ * Get the current task list ID
1338
+ */
1339
+ public get taskListId(): string {
1340
+ return this.taskManager.getTaskListId();
1341
+ }
1353
1342
  }