wave-agent-sdk 0.7.2 → 0.8.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 (174) hide show
  1. package/dist/agent.d.ts +9 -79
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +85 -302
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +2 -1
  7. package/dist/managers/aiManager.d.ts.map +1 -1
  8. package/dist/managers/aiManager.js +20 -13
  9. package/dist/managers/backgroundTaskManager.d.ts +1 -1
  10. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundTaskManager.js +1 -1
  12. package/dist/managers/{bashManager.d.ts → bangManager.d.ts} +4 -4
  13. package/dist/managers/{bashManager.d.ts.map → bangManager.d.ts.map} +1 -1
  14. package/dist/managers/{bashManager.js → bangManager.js} +5 -6
  15. package/dist/managers/hookManager.d.ts.map +1 -1
  16. package/dist/managers/hookManager.js +12 -3
  17. package/dist/managers/messageManager.d.ts +18 -6
  18. package/dist/managers/messageManager.d.ts.map +1 -1
  19. package/dist/managers/messageManager.js +42 -20
  20. package/dist/managers/permissionManager.d.ts +22 -1
  21. package/dist/managers/permissionManager.d.ts.map +1 -1
  22. package/dist/managers/permissionManager.js +106 -85
  23. package/dist/managers/planManager.d.ts +6 -0
  24. package/dist/managers/planManager.d.ts.map +1 -1
  25. package/dist/managers/planManager.js +21 -0
  26. package/dist/managers/skillManager.d.ts +7 -2
  27. package/dist/managers/skillManager.d.ts.map +1 -1
  28. package/dist/managers/skillManager.js +30 -10
  29. package/dist/managers/slashCommandManager.d.ts +7 -0
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +59 -59
  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 +47 -13
  35. package/dist/managers/toolManager.d.ts +7 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +15 -2
  38. package/dist/prompts/index.d.ts +0 -4
  39. package/dist/prompts/index.d.ts.map +1 -1
  40. package/dist/prompts/index.js +0 -9
  41. package/dist/services/aiService.d.ts.map +1 -1
  42. package/dist/services/aiService.js +9 -9
  43. package/dist/services/configurationService.d.ts +2 -2
  44. package/dist/services/configurationService.d.ts.map +1 -1
  45. package/dist/services/configurationService.js +4 -4
  46. package/dist/services/hook.d.ts.map +1 -1
  47. package/dist/services/hook.js +6 -0
  48. package/dist/services/initializationService.d.ts +44 -0
  49. package/dist/services/initializationService.d.ts.map +1 -0
  50. package/dist/services/initializationService.js +170 -0
  51. package/dist/services/interactionService.d.ts +29 -0
  52. package/dist/services/interactionService.d.ts.map +1 -0
  53. package/dist/services/interactionService.js +97 -0
  54. package/dist/services/session.js +1 -1
  55. package/dist/services/taskManager.d.ts +5 -0
  56. package/dist/services/taskManager.d.ts.map +1 -1
  57. package/dist/services/taskManager.js +16 -2
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +7 -18
  60. package/dist/tools/editTool.js +1 -1
  61. package/dist/tools/exitPlanMode.js +1 -1
  62. package/dist/tools/globTool.d.ts.map +1 -1
  63. package/dist/tools/globTool.js +12 -2
  64. package/dist/tools/lspTool.d.ts +2 -0
  65. package/dist/tools/lspTool.d.ts.map +1 -1
  66. package/dist/tools/lspTool.js +144 -52
  67. package/dist/tools/skillTool.d.ts.map +1 -1
  68. package/dist/tools/skillTool.js +97 -2
  69. package/dist/tools/taskManagementTools.d.ts.map +1 -1
  70. package/dist/tools/taskManagementTools.js +23 -2
  71. package/dist/tools/taskTool.d.ts.map +1 -1
  72. package/dist/tools/taskTool.js +9 -15
  73. package/dist/tools/types.d.ts +1 -2
  74. package/dist/tools/types.d.ts.map +1 -1
  75. package/dist/tools/writeTool.js +1 -1
  76. package/dist/types/agent.d.ts +64 -0
  77. package/dist/types/agent.d.ts.map +1 -0
  78. package/dist/types/agent.js +1 -0
  79. package/dist/types/commands.d.ts +0 -4
  80. package/dist/types/commands.d.ts.map +1 -1
  81. package/dist/types/config.d.ts +1 -1
  82. package/dist/types/config.d.ts.map +1 -1
  83. package/dist/types/hooks.d.ts +3 -1
  84. package/dist/types/hooks.d.ts.map +1 -1
  85. package/dist/types/hooks.js +1 -0
  86. package/dist/types/index.d.ts +1 -0
  87. package/dist/types/index.d.ts.map +1 -1
  88. package/dist/types/index.js +1 -0
  89. package/dist/types/messaging.d.ts +3 -3
  90. package/dist/types/messaging.d.ts.map +1 -1
  91. package/dist/types/skills.d.ts +13 -0
  92. package/dist/types/skills.d.ts.map +1 -1
  93. package/dist/utils/commandArgumentParser.d.ts.map +1 -1
  94. package/dist/utils/commandArgumentParser.js +7 -0
  95. package/dist/utils/commandPathResolver.d.ts +3 -36
  96. package/dist/utils/commandPathResolver.d.ts.map +1 -1
  97. package/dist/utils/commandPathResolver.js +16 -93
  98. package/dist/utils/configValidator.d.ts +2 -2
  99. package/dist/utils/configValidator.d.ts.map +1 -1
  100. package/dist/utils/configValidator.js +4 -6
  101. package/dist/utils/containerSetup.d.ts +3 -4
  102. package/dist/utils/containerSetup.d.ts.map +1 -1
  103. package/dist/utils/containerSetup.js +14 -9
  104. package/dist/utils/customCommands.d.ts +2 -3
  105. package/dist/utils/customCommands.d.ts.map +1 -1
  106. package/dist/utils/customCommands.js +20 -60
  107. package/dist/utils/gitUtils.d.ts +25 -0
  108. package/dist/utils/gitUtils.d.ts.map +1 -1
  109. package/dist/utils/gitUtils.js +75 -0
  110. package/dist/utils/markdownParser.d.ts +4 -0
  111. package/dist/utils/markdownParser.d.ts.map +1 -1
  112. package/dist/utils/markdownParser.js +33 -0
  113. package/dist/utils/messageOperations.d.ts +16 -7
  114. package/dist/utils/messageOperations.d.ts.map +1 -1
  115. package/dist/utils/messageOperations.js +45 -20
  116. package/dist/utils/nameGenerator.d.ts +1 -1
  117. package/dist/utils/nameGenerator.d.ts.map +1 -1
  118. package/dist/utils/nameGenerator.js +10 -6
  119. package/dist/utils/skillParser.d.ts.map +1 -1
  120. package/dist/utils/skillParser.js +48 -0
  121. package/package.json +1 -1
  122. package/src/agent.ts +103 -458
  123. package/src/index.ts +2 -2
  124. package/src/managers/aiManager.ts +23 -17
  125. package/src/managers/backgroundTaskManager.ts +2 -2
  126. package/src/managers/{bashManager.ts → bangManager.ts} +11 -8
  127. package/src/managers/hookManager.ts +13 -3
  128. package/src/managers/messageManager.ts +55 -26
  129. package/src/managers/permissionManager.ts +121 -98
  130. package/src/managers/planManager.ts +26 -0
  131. package/src/managers/skillManager.ts +51 -14
  132. package/src/managers/slashCommandManager.ts +83 -73
  133. package/src/managers/subagentManager.ts +57 -13
  134. package/src/managers/toolManager.ts +22 -2
  135. package/src/prompts/index.ts +0 -15
  136. package/src/services/aiService.ts +12 -15
  137. package/src/services/configurationService.ts +4 -4
  138. package/src/services/hook.ts +7 -0
  139. package/src/services/initializationService.ts +291 -0
  140. package/src/services/interactionService.ts +171 -0
  141. package/src/services/session.ts +1 -1
  142. package/src/services/taskManager.ts +18 -2
  143. package/src/tools/bashTool.ts +8 -18
  144. package/src/tools/editTool.ts +1 -1
  145. package/src/tools/exitPlanMode.ts +1 -1
  146. package/src/tools/globTool.ts +15 -2
  147. package/src/tools/lsTool.ts +1 -1
  148. package/src/tools/lspTool.ts +184 -52
  149. package/src/tools/skillTool.ts +127 -2
  150. package/src/tools/taskManagementTools.ts +32 -2
  151. package/src/tools/taskTool.ts +13 -15
  152. package/src/tools/types.ts +1 -2
  153. package/src/tools/writeTool.ts +1 -1
  154. package/src/types/agent.ts +83 -0
  155. package/src/types/commands.ts +0 -6
  156. package/src/types/config.ts +1 -1
  157. package/src/types/hooks.ts +5 -1
  158. package/src/types/index.ts +1 -0
  159. package/src/types/messaging.ts +3 -3
  160. package/src/types/skills.ts +13 -0
  161. package/src/utils/commandArgumentParser.ts +8 -0
  162. package/src/utils/commandPathResolver.ts +14 -117
  163. package/src/utils/configValidator.ts +5 -9
  164. package/src/utils/containerSetup.ts +17 -14
  165. package/src/utils/customCommands.ts +20 -83
  166. package/src/utils/gitUtils.ts +75 -0
  167. package/src/utils/markdownParser.ts +47 -0
  168. package/src/utils/messageOperations.ts +58 -28
  169. package/src/utils/nameGenerator.ts +10 -6
  170. package/src/utils/skillParser.ts +52 -0
  171. package/dist/managers/backgroundBashManager.d.ts +0 -27
  172. package/dist/managers/backgroundBashManager.d.ts.map +0 -1
  173. package/dist/managers/backgroundBashManager.js +0 -169
  174. package/src/managers/backgroundBashManager.ts +0 -206
package/dist/agent.js CHANGED
@@ -1,11 +1,8 @@
1
1
  import { LspManager } from "./managers/lspManager.js";
2
2
  import { configValidator } from "./utils/configValidator.js";
3
- import { loadSessionFromJsonl, handleSessionRestoration, } from "./services/session.js";
4
- import { setGlobalLogger } from "./utils/globalLogger.js";
3
+ import { InitializationService } from "./services/initializationService.js";
4
+ import { InteractionService } from "./services/interactionService.js";
5
5
  import { ConfigurationService } from "./services/configurationService.js";
6
- import * as fs from "fs/promises";
7
- import path from "path";
8
- import os from "os";
9
6
  import { setupAgentContainer } from "./utils/containerSetup.js";
10
7
  export class Agent {
11
8
  // Dynamic configuration getter methods
@@ -13,7 +10,7 @@ export class Agent {
13
10
  return this.configurationService.resolveGatewayConfig(this.options.apiKey, this.options.baseURL, this.options.defaultHeaders, this.options.fetchOptions, this.options.fetch);
14
11
  }
15
12
  getModelConfig() {
16
- return this.configurationService.resolveModelConfig(this.options.agentModel, this.options.fastModel, this.options.maxTokens, this.getPermissionMode());
13
+ return this.configurationService.resolveModelConfig(this.options.model, this.options.fastModel, this.options.maxTokens, this.getPermissionMode());
17
14
  }
18
15
  getMaxInputTokens() {
19
16
  return this.configurationService.resolveMaxInputTokens(this.options.maxInputTokens);
@@ -31,8 +28,7 @@ export class Agent {
31
28
  * @param options - Configuration options for the Agent instance
32
29
  */
33
30
  constructor(options) {
34
- this.bashManager = null;
35
- this._usages = []; // Usage tracking array
31
+ this.bangManager = null;
36
32
  // Memory content storage
37
33
  this._projectMemoryContent = "";
38
34
  this._userMemoryContent = "";
@@ -52,26 +48,23 @@ export class Agent {
52
48
  configurationService: this.configurationService,
53
49
  systemPrompt: this.systemPrompt,
54
50
  stream: this.stream,
55
- onSessionIdChange: () => {
56
- this.taskManager.setTaskListId(this.messageManager.getRootSessionId());
57
- },
58
- onSessionTasksChange: (tasks) => {
59
- this.options.callbacks?.onSessionTasksChange?.(tasks);
60
- },
61
51
  onTasksChange: (tasks) => {
62
52
  this.options.callbacks?.onTasksChange?.(tasks);
63
53
  },
54
+ onBackgroundTasksChange: (tasks) => {
55
+ this.options.callbacks?.onBackgroundTasksChange?.(tasks);
56
+ },
64
57
  onPermissionModeChange: (mode) => {
65
58
  this.options.callbacks?.onPermissionModeChange?.(mode);
66
59
  },
67
60
  handlePlanModeTransition: (mode) => {
68
- this.handlePlanModeTransition(mode);
61
+ this.planManager.handlePlanModeTransition(mode);
69
62
  },
70
63
  setPermissionMode: (mode) => {
71
64
  this.setPermissionMode(mode);
72
65
  },
73
66
  addPermissionRule: (rule) => this.addPermissionRule(rule),
74
- addUsage: (usage) => this.addUsage(usage),
67
+ addUsage: (usage) => this.messageManager.addUsage(usage),
75
68
  getGatewayConfig: () => this.getGatewayConfig(),
76
69
  getModelConfig: () => this.getModelConfig(),
77
70
  getMaxInputTokens: () => this.getMaxInputTokens(),
@@ -96,7 +89,7 @@ export class Agent {
96
89
  this.aiManager = this.container.get("AIManager");
97
90
  this.slashCommandManager = this.container.get("SlashCommandManager");
98
91
  this.pluginManager = this.container.get("PluginManager");
99
- this.bashManager = this.container.get("BashManager");
92
+ this.bangManager = this.container.get("BangManager");
100
93
  // Set initial permission mode if provided
101
94
  if (options.permissionMode) {
102
95
  this.setPermissionMode(options.permissionMode);
@@ -110,33 +103,11 @@ export class Agent {
110
103
  return this.messageManager.getMessages();
111
104
  }
112
105
  get usages() {
113
- return [...this._usages]; // Return copy to prevent external modification
106
+ return this.messageManager.getUsages();
114
107
  }
115
108
  get sessionFilePath() {
116
109
  return this.messageManager.getTranscriptPath();
117
110
  }
118
- /**
119
- * Rebuild usage array from messages containing usage metadata
120
- * Called during session restoration to reconstruct usage tracking
121
- */
122
- rebuildUsageFromMessages(messages) {
123
- this._usages = [];
124
- messages.forEach((message) => {
125
- if (message.role === "assistant" && message.usage) {
126
- this._usages.push(message.usage);
127
- }
128
- });
129
- // Trigger callback after rebuilding usage array
130
- this.messageManager.triggerUsageChange();
131
- }
132
- /**
133
- * Add usage data to the tracking array and trigger callbacks
134
- * @param usage Usage data from AI operations
135
- */
136
- addUsage(usage) {
137
- this._usages.push(usage);
138
- this.messageManager.triggerUsageChange();
139
- }
140
111
  get latestTotalTokens() {
141
112
  return this.messageManager.getlatestTotalTokens();
142
113
  }
@@ -166,7 +137,7 @@ export class Agent {
166
137
  }
167
138
  /** Get bash command execution status */
168
139
  get isCommandRunning() {
169
- return this.bashManager?.isCommandRunning ?? false;
140
+ return this.bangManager?.isCommandRunning ?? false;
170
141
  }
171
142
  /** Get background bash shell output */
172
143
  getBackgroundShellOutput(id, filter) {
@@ -247,171 +218,62 @@ export class Agent {
247
218
  // Validate resolved configuration
248
219
  configValidator.validateGatewayConfig(gatewayConfig);
249
220
  configValidator.validateMaxInputTokens(maxInputTokens);
250
- configValidator.validateModelConfig(modelConfig.agentModel, modelConfig.fastModel);
221
+ configValidator.validateModelConfig(modelConfig.model, modelConfig.fastModel);
251
222
  }
252
223
  /** Private initialization method, handles async initialization logic */
253
224
  async initialize(options) {
254
- // Initialize managers first
255
- try {
256
- // Initialize SkillManager
257
- await this.skillManager.initialize();
258
- // Initialize SubagentManager (load and cache configurations)
259
- await this.subagentManager.initialize();
260
- // Register managers in container for tool access
261
- this.container.register("SubagentManager", this.subagentManager);
262
- this.container.register("SkillManager", this.skillManager);
263
- // Initialize built-in tools
264
- this.toolManager.initializeBuiltInTools();
265
- // Initialize plugins
266
- await this.pluginManager.loadPlugins(this.options.plugins || []);
267
- }
268
- catch (error) {
269
- this.logger?.error("Failed to initialize managers and tools:", error);
270
- // Don't throw error to prevent app startup failure
271
- }
272
- // Initialize MCP servers with auto-connect
273
- try {
274
- await this.mcpManager.initialize(this.workdir, true);
275
- if (this.lspManager instanceof LspManager) {
276
- await this.lspManager.initialize(this.workdir);
277
- }
278
- }
279
- catch (error) {
280
- this.logger?.error("Failed to initialize MCP servers:", error);
281
- // Don't throw error to prevent app startup failure
282
- }
283
- // Initialize hooks configuration
284
- try {
285
- // Load hooks configuration using ConfigurationService
286
- this.logger?.debug("Loading hooks configuration...");
287
- const configResult = await this.configurationService.loadMergedConfiguration(this.workdir);
288
- this.hookManager.loadConfigurationFromWaveConfig(configResult.configuration);
289
- // Update plugin manager with enabled plugins configuration
290
- if (configResult.configuration?.enabledPlugins) {
291
- this.pluginManager.updateEnabledPlugins(configResult.configuration.enabledPlugins);
292
- }
293
- this.logger?.debug("Hooks system initialized successfully");
294
- }
295
- catch (error) {
296
- this.logger?.error("Failed to initialize hooks system:", error);
297
- // Don't throw error to prevent app startup failure
298
- }
299
- // Resolve and validate configuration after loading settings.json
300
- this.resolveAndValidateConfig();
301
- // Set global logger for SDK-wide access before discovering rules
302
- setGlobalLogger(this.logger || null);
303
- // Discover modular memory rules
304
- try {
305
- await this.memoryRuleManager.discoverRules();
306
- }
307
- catch (error) {
308
- this.logger?.error("Failed to discover memory rules:", error);
309
- }
310
- // Initialize live configuration reload
311
- try {
312
- this.logger?.debug("Initializing live configuration reload...");
313
- await this.liveConfigManager.initialize();
314
- this.logger?.debug("Live configuration reload initialized successfully");
315
- }
316
- catch (error) {
317
- this.logger?.error("Failed to initialize live configuration reload:", error);
318
- // Don't throw error to prevent app startup failure - continue without live reload
319
- }
320
- // Load memory files during initialization
321
- try {
322
- this.logger?.debug("Loading memory files...");
323
- // Load project memory from AGENTS.md (bypass memory store for direct file access)
324
- try {
325
- const projectMemoryPath = path.join(this.workdir, "AGENTS.md");
326
- this._projectMemoryContent = await fs.readFile(projectMemoryPath, "utf-8");
327
- this.logger?.debug("Project memory loaded successfully");
328
- }
329
- catch (error) {
330
- this._projectMemoryContent = "";
331
- this.logger?.debug("Project memory file not found or unreadable, using empty content:", error instanceof Error ? error.message : String(error));
332
- }
333
- // Load user memory (bypass memory store for direct file access)
334
- try {
335
- const userMemoryPath = path.join(os.homedir(), ".wave", "AGENTS.md");
336
- this._userMemoryContent = await fs.readFile(userMemoryPath, "utf-8");
337
- this.logger?.debug("User memory loaded successfully");
338
- }
339
- catch (error) {
340
- this._userMemoryContent = "";
341
- this.logger?.debug("User memory file not found or unreadable, using empty content:", error instanceof Error ? error.message : String(error));
342
- }
343
- this.logger?.debug("Memory initialization completed");
344
- }
345
- catch (error) {
346
- // Ensure memory is always initialized even if loading fails
347
- this._projectMemoryContent = "";
348
- this._userMemoryContent = "";
349
- this.logger?.error("Failed to load memory files:", error);
350
- // Don't throw error to prevent app startup failure
351
- }
352
- // Handle session restoration or set provided messages
353
- if (options?.messages) {
354
- // If messages are provided, use them directly (useful for testing)
355
- this.messageManager.setMessages(options.messages);
356
- // Rebuild usage array from restored messages
357
- this.rebuildUsageFromMessages(options.messages);
358
- }
359
- else {
360
- // Otherwise, handle session restoration
361
- const sessionToRestore = await handleSessionRestoration(options?.restoreSessionId, options?.continueLastSession, this.messageManager.getWorkdir());
362
- // Rebuild usage array from restored messages
363
- this.rebuildUsageFromMessages(sessionToRestore?.messages || []);
364
- if (sessionToRestore) {
365
- this.messageManager.initializeFromSession(sessionToRestore);
366
- // Update task manager with the root session ID to ensure continuity across compressions
367
- this.taskManager.setTaskListId(sessionToRestore.rootSessionId || sessionToRestore.id);
368
- // After session is initialized, load tasks for the session
369
- const tasks = await this.taskManager.listTasks();
370
- this.options.callbacks?.onSessionTasksChange?.(tasks);
371
- }
372
- }
225
+ await InitializationService.initialize({
226
+ skillManager: this.skillManager,
227
+ subagentManager: this.subagentManager,
228
+ container: this.container,
229
+ toolManager: this.toolManager,
230
+ pluginManager: this.pluginManager,
231
+ options: this.options,
232
+ slashCommandManager: this.slashCommandManager,
233
+ logger: this.logger,
234
+ mcpManager: this.mcpManager,
235
+ workdir: this.workdir,
236
+ lspManager: this.lspManager,
237
+ configurationService: this.configurationService,
238
+ hookManager: this.hookManager,
239
+ messageManager: this.messageManager,
240
+ memoryRuleManager: this.memoryRuleManager,
241
+ liveConfigManager: this.liveConfigManager,
242
+ taskManager: this.taskManager,
243
+ setProjectMemory: (content) => {
244
+ this._projectMemoryContent = content;
245
+ },
246
+ setUserMemory: (content) => {
247
+ this._userMemoryContent = content;
248
+ },
249
+ resolveAndValidateConfig: () => this.resolveAndValidateConfig(),
250
+ }, options);
373
251
  }
374
252
  /**
375
253
  * Restore a session by ID, switching to the target session without destroying the Agent instance
376
254
  * @param sessionId - The ID of the session to restore
377
255
  */
378
256
  async restoreSession(sessionId) {
379
- // 1. Validation
380
- if (!sessionId || sessionId === this.sessionId) {
381
- return; // No-op if session ID is invalid or already current
382
- }
383
- // 2. Auto-save current session
384
- try {
385
- await this.messageManager.saveSession();
386
- }
387
- catch (error) {
388
- this.logger?.warn("Failed to save current session before restore:", error);
389
- // Continue with restoration even if save fails
390
- }
391
- // 3. Load target session
392
- const sessionData = await loadSessionFromJsonl(sessionId, this.messageManager.getWorkdir());
393
- if (!sessionData) {
394
- throw new Error(`Session not found: ${sessionId}`);
395
- }
396
- // 4. Clean current state
397
- this.abortMessage(); // Abort any running operations
398
- this.subagentManager.cleanup(); // Clean up active subagents
399
- // 5. Rebuild usage (in correct order)
400
- this.rebuildUsageFromMessages(sessionData.messages);
401
- // 6. Initialize session state last
402
- this.messageManager.initializeFromSession(sessionData);
403
- // Update task manager with the root session ID to ensure continuity across compressions
404
- this.taskManager.setTaskListId(sessionData.rootSessionId || sessionData.id);
405
- // 7. Load tasks for the restored session
406
- const tasks = await this.taskManager.listTasks();
407
- this.options.callbacks?.onSessionTasksChange?.(tasks);
257
+ await InteractionService.restoreSession({
258
+ messageManager: this.messageManager,
259
+ slashCommandManager: this.slashCommandManager,
260
+ hookManager: this.hookManager,
261
+ workdir: this.workdir,
262
+ configurationService: this.configurationService,
263
+ logger: this.logger,
264
+ aiManager: this.aiManager,
265
+ subagentManager: this.subagentManager,
266
+ taskManager: this.taskManager,
267
+ options: this.options,
268
+ abortMessage: () => this.abortMessage(),
269
+ }, sessionId);
408
270
  }
409
271
  abortAIMessage() {
410
272
  this.aiManager.abortAIMessage();
411
273
  }
412
274
  /** Execute bash command */
413
275
  async executeBashCommand(command) {
414
- await this.bashManager?.executeCommand(command);
276
+ await this.bangManager?.executeCommand(command);
415
277
  }
416
278
  clearMessages() {
417
279
  this.messageManager.clearMessages();
@@ -424,7 +286,7 @@ export class Agent {
424
286
  }
425
287
  /** Interrupt bash command execution */
426
288
  abortBashCommand() {
427
- this.bashManager?.abortCommand();
289
+ this.bangManager?.abortCommand();
428
290
  }
429
291
  /** Interrupt slash command execution */
430
292
  abortSlashCommand() {
@@ -514,65 +376,19 @@ export class Agent {
514
376
  * ```
515
377
  */
516
378
  async sendMessage(content, images) {
517
- try {
518
- // Handle slash command - check if it's a slash command (starts with /)
519
- if (content.startsWith("/")) {
520
- const command = content.trim();
521
- if (!command || command === "/")
522
- return;
523
- // Parse and validate slash command
524
- const { isValid, commandId, args } = this.slashCommandManager.parseAndValidateSlashCommand(command);
525
- if (isValid && commandId !== undefined) {
526
- // Execute valid slash command
527
- await this.slashCommandManager.executeCommand(commandId, args);
528
- return;
529
- }
530
- // If command doesn't exist, continue as normal message processing
531
- // Don't add to history, let normal message processing logic below handle it
532
- }
533
- // Handle normal AI message
534
- // Add user message first, will automatically sync to UI
535
- this.messageManager.addUserMessage({
536
- content,
537
- images: images?.map((img) => ({
538
- path: img.path,
539
- mimeType: img.mimeType,
540
- })),
541
- });
542
- // Execute UserPromptSubmit hooks after adding the user message
543
- if (this.hookManager) {
544
- try {
545
- const hookResults = await this.hookManager.executeHooks("UserPromptSubmit", {
546
- event: "UserPromptSubmit",
547
- projectDir: this.workdir,
548
- timestamp: new Date(),
549
- // UserPromptSubmit doesn't need toolName
550
- sessionId: this.sessionId,
551
- transcriptPath: this.messageManager.getTranscriptPath(),
552
- cwd: this.workdir,
553
- userPrompt: content,
554
- env: this.configurationService.getEnvironmentVars(), // Include configuration environment variables
555
- });
556
- // Process hook results and determine if we should continue
557
- const processResult = this.hookManager.processHookResults("UserPromptSubmit", hookResults, this.messageManager);
558
- // If hook processing indicates we should block (exit code 2), stop here
559
- if (processResult.shouldBlock) {
560
- this.logger?.info("UserPromptSubmit hook blocked prompt processing with error:", processResult.errorMessage);
561
- return; // Don't send to AI
562
- }
563
- }
564
- catch (error) {
565
- this.logger?.warn("UserPromptSubmit hooks execution failed:", error);
566
- // Continue processing even if hooks fail
567
- }
568
- }
569
- // Send AI message
570
- await this.aiManager.sendAIMessage();
571
- }
572
- catch (error) {
573
- console.error("Failed to add user message:", error);
574
- // Loading state will be automatically updated by the useEffect that watches messages
575
- }
379
+ await InteractionService.sendMessage({
380
+ messageManager: this.messageManager,
381
+ slashCommandManager: this.slashCommandManager,
382
+ hookManager: this.hookManager,
383
+ workdir: this.workdir,
384
+ configurationService: this.configurationService,
385
+ logger: this.logger,
386
+ aiManager: this.aiManager,
387
+ subagentManager: this.subagentManager,
388
+ taskManager: this.taskManager,
389
+ options: this.options,
390
+ abortMessage: () => this.abortMessage(),
391
+ }, content, images);
576
392
  }
577
393
  // ========== MCP Management Methods ==========
578
394
  /** Get all MCP server status */
@@ -597,8 +413,10 @@ export class Agent {
597
413
  return this.slashCommandManager.hasCommand(commandId);
598
414
  }
599
415
  /** Reload custom commands */
600
- reloadCustomCommands() {
416
+ async reloadCustomCommands() {
417
+ await this.skillManager.initialize();
601
418
  this.slashCommandManager.reloadCustomCommands();
419
+ this.slashCommandManager.registerSkillCommands(this.skillManager.getAvailableSkills());
602
420
  }
603
421
  /** Get custom command details */
604
422
  getCustomCommand(commandId) {
@@ -627,7 +445,7 @@ export class Agent {
627
445
  setPermissionMode(mode) {
628
446
  this.logger?.debug("Setting permission mode", { mode });
629
447
  this.toolManager.setPermissionMode(mode);
630
- this.handlePlanModeTransition(mode);
448
+ this.planManager.handlePlanModeTransition(mode);
631
449
  this.options.callbacks?.onPermissionModeChange?.(mode);
632
450
  }
633
451
  /**
@@ -637,7 +455,9 @@ export class Agent {
637
455
  async truncateHistory(index) {
638
456
  await this.messageManager.truncateHistory(index, this.reversionManager);
639
457
  // After truncating history, the task list might have changed, so refresh it.
640
- await this.taskManager.refreshTasks();
458
+ // We explicitly load tasks and trigger the callback to ensure UI updates immediately and in order.
459
+ const tasks = await this.taskManager.listTasks();
460
+ this.options.callbacks?.onTasksChange?.(tasks);
641
461
  }
642
462
  /**
643
463
  * Get the full message thread including parent sessions
@@ -652,9 +472,18 @@ export class Agent {
652
472
  return this.permissionManager.getPlanFilePath();
653
473
  }
654
474
  /**
655
- * Get all currently allowed rules (for testing and UI)
475
+ * Get all currently allowed rules (user-defined and default)
656
476
  */
657
477
  getAllowedRules() {
478
+ return [
479
+ ...this.permissionManager.getAllowedRules(),
480
+ ...this.permissionManager.getDefaultAllowedRules(),
481
+ ];
482
+ }
483
+ /**
484
+ * Get only user-defined allowed rules
485
+ */
486
+ getUserAllowedRules() {
658
487
  return this.permissionManager.getAllowedRules();
659
488
  }
660
489
  /**
@@ -668,53 +497,7 @@ export class Agent {
668
497
  * @param rule - The rule to add (e.g., "Bash(ls)")
669
498
  */
670
499
  async addPermissionRule(rule) {
671
- // 1. Expand rule if it's a Bash command
672
- let rulesToAdd = [rule];
673
- const bashMatch = rule.match(/^Bash\((.*)\)$/);
674
- if (bashMatch) {
675
- const command = bashMatch[1];
676
- rulesToAdd = this.permissionManager.expandBashRule(command, this.workdir);
677
- }
678
- for (const ruleToAdd of rulesToAdd) {
679
- // 2. Update PermissionManager state
680
- const currentRules = this.permissionManager.getAllowedRules();
681
- if (!currentRules.includes(ruleToAdd)) {
682
- this.permissionManager.updateAllowedRules([...currentRules, ruleToAdd]);
683
- // 3. Persist to settings.local.json
684
- try {
685
- await this.configurationService.addAllowedRule(this.workdir, ruleToAdd);
686
- this.logger?.debug("Persistent permission rule added", {
687
- rule: ruleToAdd,
688
- });
689
- }
690
- catch (error) {
691
- this.logger?.error("Failed to persist permission rule", {
692
- rule: ruleToAdd,
693
- error: error instanceof Error ? error.message : String(error),
694
- });
695
- }
696
- }
697
- }
698
- }
699
- /**
700
- * Handle plan mode transition, generating or clearing plan file path
701
- * @param mode - The current effective permission mode
702
- */
703
- handlePlanModeTransition(mode) {
704
- if (mode === "plan") {
705
- this.planManager
706
- .getOrGeneratePlanFilePath(this.messageManager.getRootSessionId())
707
- .then(({ path }) => {
708
- this.logger?.debug("Plan file path generated", { path });
709
- this.permissionManager.setPlanFilePath(path);
710
- })
711
- .catch((error) => {
712
- this.logger?.error("Failed to generate plan file path", error);
713
- });
714
- }
715
- else {
716
- this.permissionManager.setPlanFilePath(undefined);
717
- }
500
+ await this.permissionManager.addPermissionRule(rule);
718
501
  }
719
502
  /**
720
503
  * Get the current task list ID
package/dist/index.d.ts CHANGED
@@ -15,5 +15,7 @@ export * from "./utils/stringUtils.js";
15
15
  export * from "./utils/customCommands.js";
16
16
  export * from "./utils/hookMatcher.js";
17
17
  export * from "./utils/tokenCalculation.js";
18
+ export * from "./utils/gitUtils.js";
19
+ export * from "./utils/nameGenerator.js";
18
20
  export * from "./types/index.js";
19
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;AAGlC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AAGjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAG5C,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;AAGlC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AAGjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kCAAkC,CAAC;AACjD,cAAc,uBAAuB,CAAC;AACtC,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,iBAAiB,CAAC;AAChC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -19,5 +19,6 @@ export * from "./utils/stringUtils.js";
19
19
  export * from "./utils/customCommands.js";
20
20
  export * from "./utils/hookMatcher.js";
21
21
  export * from "./utils/tokenCalculation.js";
22
- // Export types
22
+ export * from "./utils/gitUtils.js";
23
+ export * from "./utils/nameGenerator.js";
23
24
  export * from "./types/index.js";
@@ -1 +1 @@
1
- {"version":3,"file":"aiManager.d.ts","sourceRoot":"","sources":["../../src/managers/aiManager.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAY3E,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIlD,MAAM,WAAW,kBAAkB;IACjC,wBAAwB,CAAC,EAAE,CAAC,aAAa,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5D,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,gBAAgB,EAAE,MAAM,aAAa,CAAC;IACtC,cAAc,EAAE,MAAM,WAAW,CAAC;IAClC,iBAAiB,EAAE,MAAM,MAAM,CAAC;IAChC,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACtC,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnD;AAED,qBAAa,SAAS;IAkBlB,OAAO,CAAC,SAAS;IAjBZ,SAAS,EAAE,OAAO,CAAS;IAClC,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,mBAAmB,CAAgC;IAC3D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAU;IAGxB,OAAO,CAAC,kBAAkB,CAAsB;IAChD,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,mBAAmB,CAAe;IAC1C,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,oBAAoB,CAAC,CAA+B;gBAIlD,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,gBAAgB;IAgB3B,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,WAAW,GAItB;IAED,OAAO,KAAK,qBAAqB,GAEhC;IAED,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,gBAAgB,GAM3B;IAED,OAAO,KAAK,iBAAiB,GAE5B;IAGM,gBAAgB,IAAI,aAAa;IAIjC,cAAc,IAAI,WAAW;IAI7B,iBAAiB,IAAI,MAAM;IAI3B,WAAW,IAAI,MAAM,GAAG,SAAS;IAIxC,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,SAAS,CAAqB;IAEtC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAYvB,YAAY,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAItC,cAAc,IAAI,IAAI;IAuB7B,OAAO,CAAC,qBAAqB;YAsBf,8BAA8B;IA6ErC,gBAAgB,IAAI,OAAO;IAI3B,gBAAgB,CAAC,aAAa,EAAE,OAAO,GAAG,IAAI;IAOrD,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,KAAK,YAAY,GAEvB;IAEY,aAAa,CACxB,OAAO,GAAE;QACP,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,oEAAoE;QACpE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,iEAAiE;QACjE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;KACf,GACL,OAAO,CAAC,IAAI,CAAC;IAugBhB;;;;OAIG;YACW,gBAAgB;IAiE9B;;;OAGG;YACW,sBAAsB;IA6DpC;;OAEG;YACW,uBAAuB;CAwDtC"}
1
+ {"version":3,"file":"aiManager.d.ts","sourceRoot":"","sources":["../../src/managers/aiManager.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAY3E,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAIlD,MAAM,WAAW,kBAAkB;IACjC,wBAAwB,CAAC,EAAE,CAAC,aAAa,EAAE,OAAO,KAAK,IAAI,CAAC;IAC5D,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACvC;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,gBAAgB,EAAE,MAAM,aAAa,CAAC;IACtC,cAAc,EAAE,MAAM,WAAW,CAAC;IAClC,iBAAiB,EAAE,MAAM,MAAM,CAAC;IAChC,WAAW,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACtC,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnD;AAED,qBAAa,SAAS;IAkBlB,OAAO,CAAC,SAAS;IAjBZ,SAAS,EAAE,OAAO,CAAS;IAClC,OAAO,CAAC,eAAe,CAAgC;IACvD,OAAO,CAAC,mBAAmB,CAAgC;IAC3D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAU;IAGxB,OAAO,CAAC,kBAAkB,CAAsB;IAChD,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,mBAAmB,CAAe;IAC1C,OAAO,CAAC,aAAa,CAA2B;IAChD,OAAO,CAAC,oBAAoB,CAAC,CAA+B;gBAIlD,SAAS,EAAE,SAAS,EAC5B,OAAO,EAAE,gBAAgB;IAgB3B,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,cAAc,GAEzB;IAED,OAAO,KAAK,WAAW,GAItB;IAED,OAAO,KAAK,qBAAqB,GAEhC;IAED,OAAO,KAAK,WAAW,GAEtB;IAED,OAAO,KAAK,gBAAgB,GAM3B;IAED,OAAO,KAAK,iBAAiB,GAE5B;IAGM,gBAAgB,IAAI,aAAa;IAIjC,cAAc,IAAI,WAAW;IAI7B,iBAAiB,IAAI,MAAM;IAI3B,WAAW,IAAI,MAAM,GAAG,SAAS;IAIxC,OAAO,CAAC,aAAa,CAAkB;IACvC,OAAO,CAAC,SAAS,CAAqB;IAEtC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAsBvB,YAAY,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAItC,cAAc,IAAI,IAAI;IAuB7B,OAAO,CAAC,qBAAqB;YAsBf,8BAA8B;IA6ErC,gBAAgB,IAAI,OAAO;IAI3B,gBAAgB,CAAC,aAAa,EAAE,OAAO,GAAG,IAAI;IAOrD,OAAO,KAAK,eAAe,GAE1B;IAED,OAAO,KAAK,YAAY,GAEvB;IAEY,aAAa,CACxB,OAAO,GAAE;QACP,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,oEAAoE;QACpE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,iEAAiE;QACjE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,CAAC;KACf,GACL,OAAO,CAAC,IAAI,CAAC;IAmgBhB;;;;OAIG;YACW,gBAAgB;IAiE9B;;;OAGG;YACW,sBAAsB;IA6DpC;;OAEG;YACW,uBAAuB;CAwDtC"}
@@ -62,7 +62,16 @@ export class AIManager {
62
62
  * Get filtered tool configuration based on tools list
63
63
  */
64
64
  getFilteredToolsConfig(tools) {
65
- const allTools = this.toolManager.getToolsConfig();
65
+ // Get available subagents and skills for dynamic prompts
66
+ const availableSubagents = this.subagentManager?.getConfigurations();
67
+ const availableSkills = this.skillManager
68
+ ?.getAvailableSkills()
69
+ .filter((skill) => !skill.disableModelInvocation);
70
+ const allTools = this.toolManager.getToolsConfig({
71
+ availableSubagents,
72
+ availableSkills,
73
+ workdir: this.workdir,
74
+ });
66
75
  // If no tools specified, return all tools
67
76
  if (!tools || tools.length === 0) {
68
77
  return allTools;
@@ -149,7 +158,7 @@ export class AIManager {
149
158
  prompt_tokens: compressionResult.usage.prompt_tokens,
150
159
  completion_tokens: compressionResult.usage.completion_tokens,
151
160
  total_tokens: compressionResult.usage.total_tokens,
152
- model: model || this.getModelConfig().agentModel,
161
+ model: model || this.getModelConfig().model,
153
162
  operation_type: "compress",
154
163
  };
155
164
  }
@@ -246,9 +255,6 @@ export class AIManager {
246
255
  planModeOptions = { planFilePath, planExists };
247
256
  }
248
257
  }
249
- // Get available subagents and skills for dynamic prompts
250
- const availableSubagents = this.subagentManager?.getConfigurations();
251
- const availableSkills = this.skillManager?.getAvailableSkills();
252
258
  // Call AI service with streaming callbacks if enabled
253
259
  const callAgentOptions = {
254
260
  gatewayConfig: this.getGatewayConfig(),
@@ -265,8 +271,6 @@ export class AIManager {
265
271
  language: this.getLanguage(),
266
272
  isSubagent: !!this.subagentType,
267
273
  planMode: planModeOptions,
268
- availableSubagents,
269
- availableSkills,
270
274
  }), // Pass custom system prompt
271
275
  maxTokens: maxTokens, // Pass max tokens override
272
276
  };
@@ -347,7 +351,7 @@ export class AIManager {
347
351
  prompt_tokens: result.usage.prompt_tokens,
348
352
  completion_tokens: result.usage.completion_tokens,
349
353
  total_tokens: result.usage.total_tokens,
350
- model: model || this.getModelConfig().agentModel,
354
+ model: model || this.getModelConfig().model,
351
355
  operation_type: "agent",
352
356
  // Preserve cache fields if present
353
357
  ...(result.usage.cache_read_input_tokens !== undefined && {
@@ -383,9 +387,6 @@ export class AIManager {
383
387
  }
384
388
  }
385
389
  }
386
- if (result.finish_reason === "length" && toolCalls.length === 0) {
387
- this.messageManager.addErrorBlock("AI response was truncated due to length limit. Please try to reduce the complexity of your request or split it into smaller parts.");
388
- }
389
390
  if (toolCalls.length > 0) {
390
391
  // Execute all tools in parallel using Promise.all
391
392
  const toolExecutionPromises = toolCalls.map(async (functionToolCall) => {
@@ -503,8 +504,8 @@ export class AIManager {
503
504
  }
504
505
  // Handle token statistics and message compression
505
506
  await this.handleTokenUsageAndCompression(result.usage, abortController, model);
506
- // Check if there are tool operations, if so automatically initiate next AI service call
507
- if (toolCalls.length > 0) {
507
+ // Check if there are tool operations or response was truncated, if so automatically initiate next AI service call
508
+ if (toolCalls.length > 0 || result.finish_reason === "length") {
508
509
  // Record committed snapshots to message history
509
510
  if (this.reversionManager) {
510
511
  const snapshots = this.reversionManager.getAndClearCommittedSnapshots();
@@ -523,6 +524,12 @@ export class AIManager {
523
524
  logger?.info("Some tools were manually backgrounded, stopping recursion.");
524
525
  }
525
526
  else if (!isCurrentlyAborted) {
527
+ // If response was truncated and no tools were called, add a continuation message
528
+ if (result.finish_reason === "length" && toolCalls.length === 0) {
529
+ this.messageManager.addUserMessage({
530
+ content: "Your response was cut off because it exceeded the output token limit. Please break your work into smaller pieces. Continue from where you left off.",
531
+ });
532
+ }
526
533
  // Recursively call AI service, increment recursion depth, and pass same configuration
527
534
  await this.sendAIMessage({
528
535
  recursionDepth: recursionDepth + 1,
@@ -2,7 +2,7 @@ import { type ChildProcess } from "child_process";
2
2
  import { BackgroundTask } from "../types/processes.js";
3
3
  import { Container } from "../utils/container.js";
4
4
  export interface BackgroundTaskManagerCallbacks {
5
- onTasksChange?: (tasks: BackgroundTask[]) => void;
5
+ onBackgroundTasksChange?: (tasks: BackgroundTask[]) => void;
6
6
  }
7
7
  export interface BackgroundTaskManagerOptions {
8
8
  callbacks?: BackgroundTaskManagerCallbacks;