wave-agent-sdk 0.0.8 → 0.0.11

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 (236) hide show
  1. package/dist/agent.d.ts +92 -23
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +351 -137
  4. package/dist/index.d.ts +3 -0
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +3 -0
  7. package/dist/managers/aiManager.d.ts +14 -36
  8. package/dist/managers/aiManager.d.ts.map +1 -1
  9. package/dist/managers/aiManager.js +74 -77
  10. package/dist/managers/backgroundBashManager.d.ts.map +1 -1
  11. package/dist/managers/backgroundBashManager.js +4 -3
  12. package/dist/managers/hookManager.d.ts +3 -8
  13. package/dist/managers/hookManager.d.ts.map +1 -1
  14. package/dist/managers/hookManager.js +39 -29
  15. package/dist/managers/liveConfigManager.d.ts +55 -18
  16. package/dist/managers/liveConfigManager.d.ts.map +1 -1
  17. package/dist/managers/liveConfigManager.js +372 -90
  18. package/dist/managers/lspManager.d.ts +43 -0
  19. package/dist/managers/lspManager.d.ts.map +1 -0
  20. package/dist/managers/lspManager.js +326 -0
  21. package/dist/managers/messageManager.d.ts +8 -16
  22. package/dist/managers/messageManager.d.ts.map +1 -1
  23. package/dist/managers/messageManager.js +52 -74
  24. package/dist/managers/permissionManager.d.ts +75 -0
  25. package/dist/managers/permissionManager.d.ts.map +1 -0
  26. package/dist/managers/permissionManager.js +368 -0
  27. package/dist/managers/skillManager.d.ts +1 -0
  28. package/dist/managers/skillManager.d.ts.map +1 -1
  29. package/dist/managers/skillManager.js +2 -1
  30. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  31. package/dist/managers/slashCommandManager.js +0 -1
  32. package/dist/managers/subagentManager.d.ts +8 -23
  33. package/dist/managers/subagentManager.d.ts.map +1 -1
  34. package/dist/managers/subagentManager.js +97 -117
  35. package/dist/managers/toolManager.d.ts +38 -1
  36. package/dist/managers/toolManager.d.ts.map +1 -1
  37. package/dist/managers/toolManager.js +66 -2
  38. package/dist/services/aiService.d.ts +3 -1
  39. package/dist/services/aiService.d.ts.map +1 -1
  40. package/dist/services/aiService.js +123 -30
  41. package/dist/services/configurationService.d.ts +116 -0
  42. package/dist/services/configurationService.d.ts.map +1 -0
  43. package/dist/services/configurationService.js +585 -0
  44. package/dist/services/fileWatcher.d.ts.map +1 -1
  45. package/dist/services/fileWatcher.js +5 -6
  46. package/dist/services/hook.d.ts +7 -124
  47. package/dist/services/hook.d.ts.map +1 -1
  48. package/dist/services/hook.js +46 -458
  49. package/dist/services/jsonlHandler.d.ts +24 -15
  50. package/dist/services/jsonlHandler.d.ts.map +1 -1
  51. package/dist/services/jsonlHandler.js +67 -88
  52. package/dist/services/memory.d.ts +0 -9
  53. package/dist/services/memory.d.ts.map +1 -1
  54. package/dist/services/memory.js +2 -49
  55. package/dist/services/session.d.ts +82 -33
  56. package/dist/services/session.d.ts.map +1 -1
  57. package/dist/services/session.js +275 -181
  58. package/dist/tools/bashTool.d.ts.map +1 -1
  59. package/dist/tools/bashTool.js +109 -11
  60. package/dist/tools/deleteFileTool.d.ts.map +1 -1
  61. package/dist/tools/deleteFileTool.js +25 -0
  62. package/dist/tools/editTool.d.ts.map +1 -1
  63. package/dist/tools/editTool.js +30 -6
  64. package/dist/tools/lspTool.d.ts +6 -0
  65. package/dist/tools/lspTool.d.ts.map +1 -0
  66. package/dist/tools/lspTool.js +589 -0
  67. package/dist/tools/multiEditTool.d.ts.map +1 -1
  68. package/dist/tools/multiEditTool.js +26 -7
  69. package/dist/tools/readTool.d.ts.map +1 -1
  70. package/dist/tools/readTool.js +111 -2
  71. package/dist/tools/skillTool.js +2 -2
  72. package/dist/tools/todoWriteTool.d.ts.map +1 -1
  73. package/dist/tools/todoWriteTool.js +23 -0
  74. package/dist/tools/types.d.ts +11 -8
  75. package/dist/tools/types.d.ts.map +1 -1
  76. package/dist/tools/writeTool.d.ts.map +1 -1
  77. package/dist/tools/writeTool.js +25 -9
  78. package/dist/types/commands.d.ts +0 -1
  79. package/dist/types/commands.d.ts.map +1 -1
  80. package/dist/types/config.d.ts +4 -0
  81. package/dist/types/config.d.ts.map +1 -1
  82. package/dist/types/configuration.d.ts +69 -0
  83. package/dist/types/configuration.d.ts.map +1 -0
  84. package/dist/types/configuration.js +8 -0
  85. package/dist/types/core.d.ts +10 -0
  86. package/dist/types/core.d.ts.map +1 -1
  87. package/dist/types/environment.d.ts +41 -0
  88. package/dist/types/environment.d.ts.map +1 -1
  89. package/dist/types/fileSearch.d.ts +5 -0
  90. package/dist/types/fileSearch.d.ts.map +1 -0
  91. package/dist/types/fileSearch.js +1 -0
  92. package/dist/types/hooks.d.ts +11 -2
  93. package/dist/types/hooks.d.ts.map +1 -1
  94. package/dist/types/hooks.js +1 -7
  95. package/dist/types/index.d.ts +5 -0
  96. package/dist/types/index.d.ts.map +1 -1
  97. package/dist/types/index.js +5 -0
  98. package/dist/types/lsp.d.ts +90 -0
  99. package/dist/types/lsp.d.ts.map +1 -0
  100. package/dist/types/lsp.js +4 -0
  101. package/dist/types/messaging.d.ts +6 -11
  102. package/dist/types/messaging.d.ts.map +1 -1
  103. package/dist/types/permissions.d.ts +39 -0
  104. package/dist/types/permissions.d.ts.map +1 -0
  105. package/dist/types/permissions.js +12 -0
  106. package/dist/types/session.d.ts +1 -6
  107. package/dist/types/session.d.ts.map +1 -1
  108. package/dist/types/skills.d.ts +1 -0
  109. package/dist/types/skills.d.ts.map +1 -1
  110. package/dist/types/tools.d.ts +35 -0
  111. package/dist/types/tools.d.ts.map +1 -0
  112. package/dist/types/tools.js +4 -0
  113. package/dist/utils/abortUtils.d.ts +34 -0
  114. package/dist/utils/abortUtils.d.ts.map +1 -0
  115. package/dist/utils/abortUtils.js +92 -0
  116. package/dist/utils/bashHistory.d.ts +4 -0
  117. package/dist/utils/bashHistory.d.ts.map +1 -1
  118. package/dist/utils/bashHistory.js +21 -4
  119. package/dist/utils/bashParser.d.ts +24 -0
  120. package/dist/utils/bashParser.d.ts.map +1 -0
  121. package/dist/utils/bashParser.js +413 -0
  122. package/dist/utils/builtinSubagents.d.ts +7 -0
  123. package/dist/utils/builtinSubagents.d.ts.map +1 -0
  124. package/dist/utils/builtinSubagents.js +65 -0
  125. package/dist/utils/cacheControlUtils.d.ts +8 -33
  126. package/dist/utils/cacheControlUtils.d.ts.map +1 -1
  127. package/dist/utils/cacheControlUtils.js +83 -126
  128. package/dist/utils/constants.d.ts +0 -12
  129. package/dist/utils/constants.d.ts.map +1 -1
  130. package/dist/utils/constants.js +1 -13
  131. package/dist/utils/convertMessagesForAPI.d.ts +2 -1
  132. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  133. package/dist/utils/convertMessagesForAPI.js +33 -14
  134. package/dist/utils/fileSearch.d.ts +14 -0
  135. package/dist/utils/fileSearch.d.ts.map +1 -0
  136. package/dist/utils/fileSearch.js +88 -0
  137. package/dist/utils/fileUtils.d.ts +14 -2
  138. package/dist/utils/fileUtils.d.ts.map +1 -1
  139. package/dist/utils/fileUtils.js +101 -17
  140. package/dist/utils/globalLogger.d.ts +0 -14
  141. package/dist/utils/globalLogger.d.ts.map +1 -1
  142. package/dist/utils/globalLogger.js +0 -16
  143. package/dist/utils/markdownParser.d.ts.map +1 -1
  144. package/dist/utils/markdownParser.js +1 -17
  145. package/dist/utils/messageOperations.d.ts +1 -11
  146. package/dist/utils/messageOperations.d.ts.map +1 -1
  147. package/dist/utils/messageOperations.js +7 -24
  148. package/dist/utils/pathEncoder.d.ts +4 -0
  149. package/dist/utils/pathEncoder.d.ts.map +1 -1
  150. package/dist/utils/pathEncoder.js +16 -9
  151. package/dist/utils/pathSafety.d.ts +10 -0
  152. package/dist/utils/pathSafety.d.ts.map +1 -0
  153. package/dist/utils/pathSafety.js +23 -0
  154. package/dist/utils/subagentParser.d.ts +2 -2
  155. package/dist/utils/subagentParser.d.ts.map +1 -1
  156. package/dist/utils/subagentParser.js +10 -7
  157. package/package.json +9 -9
  158. package/src/agent.ts +475 -216
  159. package/src/index.ts +3 -0
  160. package/src/managers/aiManager.ts +107 -111
  161. package/src/managers/backgroundBashManager.ts +4 -3
  162. package/src/managers/hookManager.ts +44 -39
  163. package/src/managers/liveConfigManager.ts +524 -138
  164. package/src/managers/lspManager.ts +434 -0
  165. package/src/managers/messageManager.ts +73 -103
  166. package/src/managers/permissionManager.ts +480 -0
  167. package/src/managers/skillManager.ts +3 -1
  168. package/src/managers/slashCommandManager.ts +1 -2
  169. package/src/managers/subagentManager.ts +116 -159
  170. package/src/managers/toolManager.ts +95 -3
  171. package/src/services/aiService.ts +207 -26
  172. package/src/services/configurationService.ts +762 -0
  173. package/src/services/fileWatcher.ts +5 -6
  174. package/src/services/hook.ts +50 -631
  175. package/src/services/jsonlHandler.ts +84 -100
  176. package/src/services/memory.ts +2 -59
  177. package/src/services/session.ts +338 -213
  178. package/src/tools/bashTool.ts +126 -13
  179. package/src/tools/deleteFileTool.ts +36 -0
  180. package/src/tools/editTool.ts +41 -7
  181. package/src/tools/lspTool.ts +760 -0
  182. package/src/tools/multiEditTool.ts +37 -8
  183. package/src/tools/readTool.ts +125 -2
  184. package/src/tools/skillTool.ts +2 -2
  185. package/src/tools/todoWriteTool.ts +33 -1
  186. package/src/tools/types.ts +15 -9
  187. package/src/tools/writeTool.ts +36 -10
  188. package/src/types/commands.ts +0 -1
  189. package/src/types/config.ts +5 -0
  190. package/src/types/configuration.ts +73 -0
  191. package/src/types/core.ts +11 -0
  192. package/src/types/environment.ts +44 -0
  193. package/src/types/fileSearch.ts +4 -0
  194. package/src/types/hooks.ts +14 -11
  195. package/src/types/index.ts +5 -0
  196. package/src/types/lsp.ts +96 -0
  197. package/src/types/messaging.ts +8 -13
  198. package/src/types/permissions.ts +52 -0
  199. package/src/types/session.ts +3 -8
  200. package/src/types/skills.ts +1 -0
  201. package/src/types/tools.ts +38 -0
  202. package/src/utils/abortUtils.ts +118 -0
  203. package/src/utils/bashHistory.ts +28 -4
  204. package/src/utils/bashParser.ts +444 -0
  205. package/src/utils/builtinSubagents.ts +71 -0
  206. package/src/utils/cacheControlUtils.ts +106 -171
  207. package/src/utils/constants.ts +1 -16
  208. package/src/utils/convertMessagesForAPI.ts +38 -14
  209. package/src/utils/fileSearch.ts +107 -0
  210. package/src/utils/fileUtils.ts +114 -19
  211. package/src/utils/globalLogger.ts +0 -17
  212. package/src/utils/markdownParser.ts +1 -19
  213. package/src/utils/messageOperations.ts +7 -35
  214. package/src/utils/pathEncoder.ts +24 -9
  215. package/src/utils/pathSafety.ts +26 -0
  216. package/src/utils/subagentParser.ts +11 -8
  217. package/dist/constants/events.d.ts +0 -28
  218. package/dist/constants/events.d.ts.map +0 -1
  219. package/dist/constants/events.js +0 -27
  220. package/dist/services/configurationWatcher.d.ts +0 -120
  221. package/dist/services/configurationWatcher.d.ts.map +0 -1
  222. package/dist/services/configurationWatcher.js +0 -439
  223. package/dist/services/memoryStore.d.ts +0 -81
  224. package/dist/services/memoryStore.d.ts.map +0 -1
  225. package/dist/services/memoryStore.js +0 -200
  226. package/dist/types/memoryStore.d.ts +0 -82
  227. package/dist/types/memoryStore.d.ts.map +0 -1
  228. package/dist/types/memoryStore.js +0 -7
  229. package/dist/utils/configResolver.d.ts +0 -65
  230. package/dist/utils/configResolver.d.ts.map +0 -1
  231. package/dist/utils/configResolver.js +0 -210
  232. package/src/constants/events.ts +0 -38
  233. package/src/services/configurationWatcher.ts +0 -622
  234. package/src/services/memoryStore.ts +0 -279
  235. package/src/types/memoryStore.ts +0 -94
  236. package/src/utils/configResolver.ts +0 -302
@@ -16,6 +16,10 @@ import {
16
16
  UserMessageParams,
17
17
  type AgentToolBlockUpdateParams,
18
18
  } from "../utils/messageOperations.js";
19
+ import {
20
+ addConsolidatedAbortListener,
21
+ createAbortPromise,
22
+ } from "../utils/abortUtils.js";
19
23
 
20
24
  export interface SubagentManagerCallbacks {
21
25
  // Granular subagent message callbacks (015-subagent-message-callbacks)
@@ -32,6 +36,12 @@ export interface SubagentManagerCallbacks {
32
36
  chunk: string,
33
37
  accumulated: string,
34
38
  ) => void;
39
+ /** Triggered during subagent reasoning streaming updates */
40
+ onSubagentAssistantReasoningUpdated?: (
41
+ subagentId: string,
42
+ chunk: string,
43
+ accumulated: string,
44
+ ) => void;
35
45
  /** Triggered when subagent tool block is updated */
36
46
  onSubagentToolBlockUpdated?: (
37
47
  subagentId: string,
@@ -58,9 +68,9 @@ export interface SubagentManagerOptions {
58
68
  parentMessageManager: MessageManager;
59
69
  callbacks?: SubagentManagerCallbacks; // Use SubagentManagerCallbacks instead of parentCallbacks
60
70
  logger?: Logger;
61
- gatewayConfig: GatewayConfig;
62
- modelConfig: ModelConfig;
63
- tokenLimit: number;
71
+ getGatewayConfig: () => GatewayConfig;
72
+ getModelConfig: () => ModelConfig;
73
+ getTokenLimit: () => number;
64
74
  hookManager?: HookManager;
65
75
  onUsageAdded?: (usage: Usage) => void;
66
76
  }
@@ -74,9 +84,9 @@ export class SubagentManager {
74
84
  private parentMessageManager: MessageManager;
75
85
  private callbacks?: SubagentManagerCallbacks; // Use SubagentManagerCallbacks instead of parentCallbacks
76
86
  private logger?: Logger;
77
- private gatewayConfig: GatewayConfig;
78
- private modelConfig: ModelConfig;
79
- private tokenLimit: number;
87
+ private getGatewayConfig: () => GatewayConfig;
88
+ private getModelConfig: () => ModelConfig;
89
+ private getTokenLimit: () => number;
80
90
  private hookManager?: HookManager;
81
91
  private onUsageAdded?: (usage: Usage) => void;
82
92
 
@@ -86,9 +96,9 @@ export class SubagentManager {
86
96
  this.parentMessageManager = options.parentMessageManager;
87
97
  this.callbacks = options.callbacks; // Store SubagentManagerCallbacks
88
98
  this.logger = options.logger;
89
- this.gatewayConfig = options.gatewayConfig;
90
- this.modelConfig = options.modelConfig;
91
- this.tokenLimit = options.tokenLimit;
99
+ this.getGatewayConfig = options.getGatewayConfig;
100
+ this.getModelConfig = options.getModelConfig;
101
+ this.getTokenLimit = options.getTokenLimit;
92
102
  this.hookManager = options.hookManager;
93
103
  this.onUsageAdded = options.onUsageAdded;
94
104
  }
@@ -146,12 +156,7 @@ export class SubagentManager {
146
156
  subagent_type: string;
147
157
  },
148
158
  ): Promise<SubagentInstance> {
149
- if (
150
- !this.parentToolManager ||
151
- !this.gatewayConfig ||
152
- !this.modelConfig ||
153
- !this.tokenLimit
154
- ) {
159
+ if (!this.parentToolManager) {
155
160
  throw new Error(
156
161
  "SubagentManager not properly initialized - call initialize() first",
157
162
  );
@@ -167,19 +172,12 @@ export class SubagentManager {
167
172
  workdir: this.workdir,
168
173
  logger: this.logger,
169
174
  sessionType: "subagent",
170
- parentSessionId: this.parentMessageManager.getSessionId(),
171
175
  subagentType: parameters.subagent_type,
172
176
  });
173
177
 
174
178
  // Use the parent tool manager directly - tool restrictions will be handled by allowedTools parameter
175
179
  const toolManager = this.parentToolManager;
176
180
 
177
- // Determine model to use
178
- const modelToUse =
179
- configuration.model && configuration.model !== "inherit"
180
- ? configuration.model
181
- : this.modelConfig.agentModel;
182
-
183
181
  // Create isolated AIManager for the subagent
184
182
  const aiManager = new AIManager({
185
183
  messageManager,
@@ -189,12 +187,29 @@ export class SubagentManager {
189
187
  systemPrompt: configuration.systemPrompt,
190
188
  subagentType: parameters.subagent_type, // Pass subagent type for hook context
191
189
  hookManager: this.hookManager,
192
- gatewayConfig: this.gatewayConfig,
193
- modelConfig: {
194
- ...this.modelConfig,
195
- agentModel: modelToUse,
190
+ getGatewayConfig: this.getGatewayConfig,
191
+ getModelConfig: () => {
192
+ // Determine model dynamically each time
193
+ const parentModelConfig = this.getModelConfig();
194
+ let modelToUse: string;
195
+
196
+ if (!configuration.model || configuration.model === "inherit") {
197
+ // Use parent's agentModel for "inherit" or undefined
198
+ modelToUse = parentModelConfig.agentModel;
199
+ } else if (configuration.model === "fastModel") {
200
+ // Use parent's fastModel for special "fastModel" value
201
+ modelToUse = parentModelConfig.fastModel;
202
+ } else {
203
+ // Use specific model name
204
+ modelToUse = configuration.model;
205
+ }
206
+
207
+ return {
208
+ ...parentModelConfig,
209
+ agentModel: modelToUse,
210
+ };
196
211
  },
197
- tokenLimit: this.tokenLimit,
212
+ getTokenLimit: this.getTokenLimit,
198
213
  callbacks: {
199
214
  onUsageAdded: this.onUsageAdded,
200
215
  },
@@ -249,14 +264,22 @@ export class SubagentManager {
249
264
  status: "active",
250
265
  });
251
266
 
252
- // Set up abort handler
267
+ // Set up consolidated abort handler to prevent listener accumulation
268
+ let abortCleanup: (() => void) | undefined;
253
269
  if (abortSignal) {
254
- abortSignal.addEventListener("abort", () => {
255
- this.updateInstanceStatus(instance.subagentId, "aborted");
256
- this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
257
- status: "aborted",
258
- });
259
- });
270
+ abortCleanup = addConsolidatedAbortListener(abortSignal, [
271
+ () => {
272
+ // Update status to aborted
273
+ this.updateInstanceStatus(instance.subagentId, "aborted");
274
+ this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
275
+ status: "aborted",
276
+ });
277
+ },
278
+ () => {
279
+ // Abort the AI execution
280
+ instance.aiManager.abortAIMessage();
281
+ },
282
+ ]);
260
283
  }
261
284
 
262
285
  // Add the user's prompt as a message
@@ -276,32 +299,43 @@ export class SubagentManager {
276
299
 
277
300
  // Execute the AI request with tool restrictions
278
301
  // The AIManager will handle abort signals through its own abort controllers
279
- // We need to abort the AI execution if the external abort signal is triggered
302
+ // Resolve model name for sendAIMessage
303
+ let resolvedModel: string | undefined;
304
+ if (
305
+ instance.configuration.model &&
306
+ instance.configuration.model !== "inherit"
307
+ ) {
308
+ if (instance.configuration.model === "fastModel") {
309
+ // Use parent's fastModel for special "fastModel" value
310
+ const parentModelConfig = this.getModelConfig();
311
+ resolvedModel = parentModelConfig.fastModel;
312
+ } else {
313
+ // Use specific model name
314
+ resolvedModel = instance.configuration.model;
315
+ }
316
+ }
317
+ // For "inherit" or undefined, resolvedModel remains undefined (uses AIManager default)
318
+
280
319
  const executeAI = instance.aiManager.sendAIMessage({
281
320
  allowedTools,
282
- model:
283
- instance.configuration.model !== "inherit"
284
- ? instance.configuration.model
285
- : undefined,
321
+ model: resolvedModel,
286
322
  });
287
323
 
288
- // If we have an abort signal, race against it
289
- if (abortSignal) {
290
- await Promise.race([
291
- executeAI,
292
- new Promise<never>((_, reject) => {
293
- if (abortSignal.aborted) {
294
- reject(new Error("Task was aborted"));
295
- }
296
- abortSignal.addEventListener("abort", () => {
297
- // Abort the AI execution
298
- instance.aiManager.abortAIMessage();
299
- reject(new Error("Task was aborted"));
300
- });
301
- }),
302
- ]);
303
- } else {
304
- await executeAI;
324
+ try {
325
+ // If we have an abort signal, race against it using utilities to prevent listener accumulation
326
+ if (abortSignal) {
327
+ await Promise.race([
328
+ executeAI,
329
+ createAbortPromise(abortSignal, "Task was aborted"),
330
+ ]);
331
+ } else {
332
+ await executeAI;
333
+ }
334
+ } finally {
335
+ // Clean up abort listeners to prevent memory leaks
336
+ if (abortCleanup) {
337
+ abortCleanup();
338
+ }
305
339
  }
306
340
 
307
341
  // Get the latest messages to extract the response
@@ -422,7 +456,6 @@ export class SubagentManager {
422
456
  workdir: this.workdir,
423
457
  logger: this.logger,
424
458
  sessionType: "subagent",
425
- parentSessionId: this.parentMessageManager.getSessionId(),
426
459
  subagentType: configuration.name, // Use configuration name for restored sessions
427
460
  });
428
461
 
@@ -430,10 +463,16 @@ export class SubagentManager {
430
463
  const toolManager = this.parentToolManager;
431
464
 
432
465
  // Determine model to use
433
- const modelToUse =
434
- configuration.model && configuration.model !== "inherit"
435
- ? configuration.model
436
- : this.modelConfig.agentModel;
466
+ let modelToUse: string;
467
+ const parentModelConfig = this.getModelConfig();
468
+
469
+ if (!configuration.model || configuration.model === "inherit") {
470
+ modelToUse = parentModelConfig.agentModel;
471
+ } else if (configuration.model === "fastModel") {
472
+ modelToUse = parentModelConfig.fastModel;
473
+ } else {
474
+ modelToUse = configuration.model;
475
+ }
437
476
 
438
477
  // Create AIManager for the restored subagent
439
478
  const aiManager = new AIManager({
@@ -444,12 +483,12 @@ export class SubagentManager {
444
483
  systemPrompt: configuration.systemPrompt,
445
484
  subagentType: configuration.name, // Use configuration name as subagent type for restored instances
446
485
  hookManager: this.hookManager,
447
- gatewayConfig: this.gatewayConfig,
448
- modelConfig: {
449
- ...this.modelConfig,
486
+ getGatewayConfig: this.getGatewayConfig,
487
+ getModelConfig: () => ({
488
+ ...parentModelConfig,
450
489
  agentModel: modelToUse,
451
- },
452
- tokenLimit: this.tokenLimit,
490
+ }),
491
+ getTokenLimit: this.getTokenLimit,
453
492
  callbacks: {
454
493
  onUsageAdded: this.onUsageAdded,
455
494
  },
@@ -471,19 +510,7 @@ export class SubagentManager {
471
510
  // This ensures the callback can find the instance
472
511
  this.instances.set(subagentId, instance);
473
512
 
474
- // Now restore the session data including sessionId, which will trigger the callback chain
475
- const sessionDataObj = {
476
- id: sessionData.id,
477
- messages: sessionData.messages,
478
- version: "1.0.0",
479
- metadata: {
480
- workdir: this.workdir,
481
- startedAt: new Date().toISOString(),
482
- lastActiveAt: new Date().toISOString(),
483
- latestTotalTokens: 0,
484
- },
485
- };
486
- messageManager.initializeFromSession(sessionDataObj);
513
+ messageManager.initializeFromSession(sessionData);
487
514
  } catch (error) {
488
515
  this.logger?.warn(
489
516
  `Failed to restore subagent session ${subagentId}:`,
@@ -524,6 +551,16 @@ export class SubagentManager {
524
551
  );
525
552
  }
526
553
  },
554
+ onAssistantReasoningUpdated: (chunk: string, accumulated: string) => {
555
+ // Forward assistant reasoning updates to parent via SubagentManager callbacks
556
+ if (this.callbacks?.onSubagentAssistantReasoningUpdated) {
557
+ this.callbacks.onSubagentAssistantReasoningUpdated(
558
+ subagentId,
559
+ chunk,
560
+ accumulated,
561
+ );
562
+ }
563
+ },
527
564
 
528
565
  onToolBlockUpdated: (params: AgentToolBlockUpdateParams) => {
529
566
  // Forward tool block updates to parent via SubagentManager callbacks
@@ -552,84 +589,4 @@ export class SubagentManager {
552
589
  },
553
590
  };
554
591
  }
555
-
556
- /**
557
- * Update configuration for SubagentManager and all active subagents
558
- * This method updates configuration for live config reload support
559
- * @param newGatewayConfig - New gateway configuration
560
- * @param newModelConfig - New model configuration
561
- * @param newTokenLimit - New token limit
562
- */
563
- updateConfiguration(
564
- newGatewayConfig: GatewayConfig,
565
- newModelConfig: ModelConfig,
566
- newTokenLimit: number,
567
- ): void {
568
- this.logger?.info("Live Config: Updating SubagentManager configuration");
569
-
570
- // Update stored configuration
571
- this.gatewayConfig = newGatewayConfig;
572
- this.modelConfig = newModelConfig;
573
- this.tokenLimit = newTokenLimit;
574
-
575
- // Update all active subagent AIManager instances
576
- let updatedCount = 0;
577
- for (const [subagentId, instance] of this.instances.entries()) {
578
- if (instance.status === "active" || instance.status === "initializing") {
579
- try {
580
- // For subagents, we need to preserve their model if it was explicitly set
581
- const subagentModelConfig = {
582
- ...newModelConfig,
583
- // If subagent has its own model configured, preserve it
584
- agentModel:
585
- instance.configuration.model &&
586
- instance.configuration.model !== "inherit"
587
- ? instance.configuration.model
588
- : newModelConfig.agentModel,
589
- };
590
-
591
- instance.aiManager.updateConfiguration(
592
- newGatewayConfig,
593
- subagentModelConfig,
594
- newTokenLimit,
595
- );
596
- updatedCount++;
597
-
598
- this.logger?.debug(
599
- `Live Config: Updated configuration for subagent ${subagentId}`,
600
- );
601
- } catch (error) {
602
- this.logger?.error(
603
- `Live Config: Failed to update configuration for subagent ${subagentId}: ${(error as Error).message}`,
604
- );
605
- }
606
- }
607
- }
608
-
609
- this.logger?.info(
610
- `Live Config: SubagentManager configuration updated - ${updatedCount} active subagents updated`,
611
- );
612
- }
613
-
614
- /**
615
- * Get current configuration for debugging
616
- */
617
- getCurrentConfiguration(): {
618
- gatewayConfig: GatewayConfig;
619
- modelConfig: ModelConfig;
620
- tokenLimit: number;
621
- activeSubagents: number;
622
- } {
623
- const activeSubagents = Array.from(this.instances.values()).filter(
624
- (instance) =>
625
- instance.status === "active" || instance.status === "initializing",
626
- ).length;
627
-
628
- return {
629
- gatewayConfig: { ...this.gatewayConfig },
630
- modelConfig: { ...this.modelConfig },
631
- tokenLimit: this.tokenLimit,
632
- activeSubagents,
633
- };
634
- }
635
592
  }
@@ -10,30 +10,56 @@ import { grepTool } from "../tools/grepTool.js";
10
10
  import { lsTool } from "../tools/lsTool.js";
11
11
  import { readTool } from "../tools/readTool.js";
12
12
  import { todoWriteTool } from "../tools/todoWriteTool.js";
13
+ import { lspTool } from "../tools/lspTool.js";
13
14
  import { createTaskTool } from "../tools/taskTool.js";
14
15
  import { createSkillTool } from "../tools/skillTool.js";
15
16
  import { McpManager } from "./mcpManager.js";
17
+ import { PermissionManager } from "./permissionManager.js";
16
18
  import { ChatCompletionFunctionTool } from "openai/resources.js";
17
- import type { Logger } from "../types/index.js";
19
+ import type {
20
+ Logger,
21
+ PermissionMode,
22
+ PermissionCallback,
23
+ ILspManager,
24
+ } from "../types/index.js";
18
25
  import type { SubagentManager } from "./subagentManager.js";
19
26
  import type { SkillManager } from "./skillManager.js";
20
27
 
21
28
  export interface ToolManagerOptions {
22
29
  mcpManager: McpManager;
30
+ lspManager?: ILspManager;
23
31
  logger?: Logger;
32
+ /** Optional permission manager for handling tool permission checks */
33
+ permissionManager?: PermissionManager;
34
+ /** Permission mode for tool execution (defaults to "default") */
35
+ permissionMode?: PermissionMode;
36
+ /** Custom permission callback for tool usage */
37
+ canUseToolCallback?: PermissionCallback;
24
38
  }
25
39
 
26
40
  /**
27
41
  * Tool Manager
42
+ *
43
+ * Manages tool registration and execution with optional permission system integration.
44
+ * Supports both built-in tools and MCP (Model Context Protocol) tools.
28
45
  */
29
46
  class ToolManager {
30
47
  private tools = new Map<string, ToolPlugin>();
31
48
  private mcpManager: McpManager;
49
+ private lspManager?: ILspManager;
32
50
  private logger?: Logger;
51
+ private permissionManager?: PermissionManager;
52
+ private permissionMode?: PermissionMode;
53
+ private canUseToolCallback?: PermissionCallback;
33
54
 
34
55
  constructor(options: ToolManagerOptions) {
35
56
  this.mcpManager = options.mcpManager;
57
+ this.lspManager = options.lspManager;
36
58
  this.logger = options.logger;
59
+ this.permissionManager = options.permissionManager;
60
+ // Store CLI permission mode, let PermissionManager resolve effective mode
61
+ this.permissionMode = options.permissionMode;
62
+ this.canUseToolCallback = options.canUseToolCallback;
37
63
  }
38
64
 
39
65
  /**
@@ -83,6 +109,7 @@ class ToolManager {
83
109
  lsTool,
84
110
  readTool,
85
111
  todoWriteTool,
112
+ lspTool,
86
113
  ];
87
114
 
88
115
  for (const tool of builtInTools) {
@@ -101,22 +128,66 @@ class ToolManager {
101
128
  }
102
129
  }
103
130
 
131
+ /**
132
+ * Execute a tool by name with the provided arguments and context
133
+ *
134
+ * Enhances the context with permission-related fields before execution:
135
+ * - permissionMode: The current permission mode (default or bypassPermissions)
136
+ * - canUseToolCallback: Custom permission callback if provided
137
+ * - permissionManager: The PermissionManager instance for permission checks
138
+ *
139
+ * @param name - Name of the tool to execute
140
+ * @param args - Arguments to pass to the tool
141
+ * @param context - Execution context for the tool
142
+ * @returns Promise resolving to the tool execution result
143
+ */
104
144
  async execute(
105
145
  name: string,
106
146
  args: Record<string, unknown>,
107
147
  context: ToolContext,
108
148
  ): Promise<ToolResult> {
149
+ // Resolve effective permission mode (CLI override > configuration > default)
150
+ const effectivePermissionMode = this.permissionManager
151
+ ? this.permissionManager.getCurrentEffectiveMode(this.permissionMode)
152
+ : this.permissionMode || "default";
153
+
154
+ // Enhance context with permission-related fields
155
+ const enhancedContext: ToolContext = {
156
+ ...context,
157
+ permissionMode: effectivePermissionMode,
158
+ canUseToolCallback: this.canUseToolCallback,
159
+ permissionManager: this.permissionManager,
160
+ mcpManager: this.mcpManager,
161
+ lspManager: this.lspManager,
162
+ };
163
+
164
+ this.logger?.debug("Executing tool with enhanced context", {
165
+ toolName: name,
166
+ cliPermissionMode: this.permissionMode,
167
+ effectivePermissionMode,
168
+ hasPermissionManager: !!this.permissionManager,
169
+ hasPermissionCallback: !!this.canUseToolCallback,
170
+ });
171
+
109
172
  // Check if it's an MCP tool first
110
173
  if (this.mcpManager.isMcpTool(name)) {
111
- return this.mcpManager.executeMcpToolByRegistry(name, args, context);
174
+ return this.mcpManager.executeMcpToolByRegistry(
175
+ name,
176
+ args,
177
+ enhancedContext,
178
+ );
112
179
  }
113
180
 
114
181
  // Check built-in tools
115
182
  const plugin = this.tools.get(name);
116
183
  if (plugin) {
117
184
  try {
118
- return await plugin.execute(args, context);
185
+ return await plugin.execute(args, enhancedContext);
119
186
  } catch (error) {
187
+ this.logger?.error("Tool execution failed", {
188
+ toolName: name,
189
+ error: error instanceof Error ? error.message : String(error),
190
+ });
120
191
  return {
121
192
  success: false,
122
193
  content: "",
@@ -125,6 +196,7 @@ class ToolManager {
125
196
  }
126
197
  }
127
198
 
199
+ this.logger?.warn("Tool not found", { toolName: name });
128
200
  return {
129
201
  success: false,
130
202
  content: "",
@@ -145,6 +217,26 @@ class ToolManager {
145
217
  const mcpToolsConfig = this.mcpManager.getMcpToolsConfig();
146
218
  return [...builtInToolsConfig, ...mcpToolsConfig];
147
219
  }
220
+
221
+ /**
222
+ * Get the current permission mode
223
+ */
224
+ public getPermissionMode(): PermissionMode {
225
+ if (this.permissionManager) {
226
+ return this.permissionManager.getCurrentEffectiveMode(
227
+ this.permissionMode,
228
+ );
229
+ }
230
+ return this.permissionMode || "default";
231
+ }
232
+
233
+ /**
234
+ * Set the permission mode
235
+ * @param mode - The new permission mode
236
+ */
237
+ public setPermissionMode(mode: PermissionMode): void {
238
+ this.permissionMode = mode;
239
+ }
148
240
  }
149
241
 
150
242
  // Export tool registry class and types