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
package/src/index.ts CHANGED
@@ -4,14 +4,17 @@ export * from "./services/memory.js";
4
4
  export * from "./services/session.js";
5
5
  export * from "./services/hook.js";
6
6
  export * from "./services/jsonlHandler.js";
7
+ export * from "./services/configurationService.js"; // New configuration management service
7
8
 
8
9
  // Export main agent
9
10
  export * from "./agent.js";
10
11
 
11
12
  // Export all utilities
12
13
  export * from "./utils/bashHistory.js";
14
+ export * from "./utils/bashParser.js";
13
15
  export * from "./utils/convertMessagesForAPI.js";
14
16
  export * from "./utils/fileFilter.js";
17
+ export * from "./utils/fileSearch.js";
15
18
  export * from "./utils/globalLogger.js";
16
19
  export * from "./utils/mcpUtils.js";
17
20
  export * from "./utils/messageOperations.js";
@@ -1,4 +1,8 @@
1
- import { callAgent, compressMessages } from "../services/aiService.js";
1
+ import {
2
+ callAgent,
3
+ compressMessages,
4
+ type CallAgentOptions,
5
+ } from "../services/aiService.js";
2
6
  import { getMessagesToCompress } from "../utils/messageOperations.js";
3
7
  import { convertMessagesForAPI } from "../utils/convertMessagesForAPI.js";
4
8
  import { calculateComprehensiveTotalTokens } from "../utils/tokenCalculation.js";
@@ -32,10 +36,13 @@ export interface AIManagerOptions {
32
36
  workdir: string;
33
37
  systemPrompt?: string;
34
38
  subagentType?: string; // Optional subagent type for hook context
35
- // Resolved configuration
36
- gatewayConfig: GatewayConfig;
37
- modelConfig: ModelConfig;
38
- tokenLimit: number;
39
+ /**Whether to use streaming mode for AI responses - defaults to true */
40
+ stream?: boolean;
41
+ // Dynamic configuration getters
42
+ getGatewayConfig: () => GatewayConfig;
43
+ getModelConfig: () => ModelConfig;
44
+ getTokenLimit: () => number;
45
+ getEnvironmentVars?: () => Record<string, string>; // Get configuration environment variables for hooks
39
46
  }
40
47
 
41
48
  export class AIManager {
@@ -50,11 +57,13 @@ export class AIManager {
50
57
  private workdir: string;
51
58
  private systemPrompt?: string;
52
59
  private subagentType?: string; // Store subagent type for hook context
60
+ private stream: boolean; // Streaming mode flag
53
61
 
54
- // Configuration properties
55
- private gatewayConfig: GatewayConfig;
56
- private modelConfig: ModelConfig;
57
- private tokenLimit: number;
62
+ // Configuration properties (replaced with getter function storage)
63
+ private getGatewayConfigFn: () => GatewayConfig;
64
+ private getModelConfigFn: () => ModelConfig;
65
+ private getTokenLimitFn: () => number;
66
+ private getEnvironmentVarsFn?: () => Record<string, string>;
58
67
 
59
68
  constructor(options: AIManagerOptions) {
60
69
  this.messageManager = options.messageManager;
@@ -65,84 +74,31 @@ export class AIManager {
65
74
  this.workdir = options.workdir;
66
75
  this.systemPrompt = options.systemPrompt;
67
76
  this.subagentType = options.subagentType; // Store subagent type
77
+ this.stream = options.stream ?? true; // Default to true if not specified
68
78
  this.callbacks = options.callbacks ?? {};
69
79
 
70
- // Store resolved configuration
71
- this.gatewayConfig = options.gatewayConfig;
72
- this.modelConfig = options.modelConfig;
73
- this.tokenLimit = options.tokenLimit;
80
+ // Store configuration getter functions for dynamic resolution
81
+ this.getGatewayConfigFn = options.getGatewayConfig;
82
+ this.getModelConfigFn = options.getModelConfig;
83
+ this.getTokenLimitFn = options.getTokenLimit;
84
+ this.getEnvironmentVarsFn = options.getEnvironmentVars;
74
85
  }
75
86
 
76
- private isCompressing: boolean = false;
77
- private callbacks: AIManagerCallbacks;
78
-
79
- /**
80
- * Update gateway configuration at runtime for live config reload
81
- * @param newConfig - New gateway configuration
82
- */
83
- updateGatewayConfig(newConfig: GatewayConfig): void {
84
- this.logger?.info(
85
- `Live Config: Updating AIManager gateway config - baseURL: ${newConfig.baseURL}`,
86
- );
87
- this.gatewayConfig = newConfig;
87
+ // Getter methods for accessing dynamic configuration
88
+ public getGatewayConfig(): GatewayConfig {
89
+ return this.getGatewayConfigFn();
88
90
  }
89
91
 
90
- /**
91
- * Update model configuration at runtime for live config reload
92
- * @param newConfig - New model configuration
93
- */
94
- updateModelConfig(newConfig: ModelConfig): void {
95
- this.logger?.info(
96
- `Live Config: Updating AIManager model config - agent: ${newConfig.agentModel}, fast: ${newConfig.fastModel}`,
97
- );
98
- this.modelConfig = newConfig;
99
- }
100
-
101
- /**
102
- * Update token limit at runtime for live config reload
103
- * @param newLimit - New token limit
104
- */
105
- updateTokenLimit(newLimit: number): void {
106
- this.logger?.info(
107
- `Live Config: Updating AIManager token limit: ${newLimit}`,
108
- );
109
- this.tokenLimit = newLimit;
92
+ public getModelConfig(): ModelConfig {
93
+ return this.getModelConfigFn();
110
94
  }
111
95
 
112
- /**
113
- * Update all configurations at once for live config reload
114
- * @param newGatewayConfig - New gateway configuration
115
- * @param newModelConfig - New model configuration
116
- * @param newTokenLimit - New token limit
117
- */
118
- updateConfiguration(
119
- newGatewayConfig: GatewayConfig,
120
- newModelConfig: ModelConfig,
121
- newTokenLimit: number,
122
- ): void {
123
- this.logger?.info("Live Config: Updating all AIManager configuration");
124
- this.gatewayConfig = newGatewayConfig;
125
- this.modelConfig = newModelConfig;
126
- this.tokenLimit = newTokenLimit;
127
- this.logger?.info(
128
- `Live Config: Configuration updated - model: ${newModelConfig.agentModel}, tokenLimit: ${newTokenLimit}`,
129
- );
96
+ public getTokenLimit(): number {
97
+ return this.getTokenLimitFn();
130
98
  }
131
99
 
132
- /**
133
- * Get current configuration for debugging
134
- */
135
- getCurrentConfiguration(): {
136
- gatewayConfig: GatewayConfig;
137
- modelConfig: ModelConfig;
138
- tokenLimit: number;
139
- } {
140
- return {
141
- gatewayConfig: { ...this.gatewayConfig },
142
- modelConfig: { ...this.modelConfig },
143
- tokenLimit: this.tokenLimit,
144
- };
145
- }
100
+ private isCompressing: boolean = false;
101
+ private callbacks: AIManagerCallbacks;
146
102
 
147
103
  /**
148
104
  * Get filtered tool configuration
@@ -222,10 +178,10 @@ export class AIManager {
222
178
  usage.total_tokens +
223
179
  (usage.cache_read_input_tokens || 0) +
224
180
  (usage.cache_creation_input_tokens || 0) >
225
- this.tokenLimit
181
+ this.getTokenLimit()
226
182
  ) {
227
183
  this.logger?.debug(
228
- `Token usage exceeded ${this.tokenLimit}, compressing messages...`,
184
+ `Token usage exceeded ${this.getTokenLimit()}, compressing messages...`,
229
185
  );
230
186
 
231
187
  // Check if messages need compression
@@ -244,8 +200,8 @@ export class AIManager {
244
200
  this.setIsCompressing(true);
245
201
  try {
246
202
  const compressionResult = await compressMessages({
247
- gatewayConfig: this.gatewayConfig,
248
- modelConfig: this.modelConfig,
203
+ gatewayConfig: this.getGatewayConfig(),
204
+ modelConfig: this.getModelConfig(),
249
205
  messages: recentChatMessages,
250
206
  abortSignal: abortController.signal,
251
207
  });
@@ -257,7 +213,7 @@ export class AIManager {
257
213
  prompt_tokens: compressionResult.usage.prompt_tokens,
258
214
  completion_tokens: compressionResult.usage.completion_tokens,
259
215
  total_tokens: compressionResult.usage.total_tokens,
260
- model: this.modelConfig.fastModel,
216
+ model: this.getModelConfig().fastModel,
261
217
  operation_type: "compress",
262
218
  };
263
219
  }
@@ -348,13 +304,15 @@ export class AIManager {
348
304
  this.workdir,
349
305
  );
350
306
 
351
- // Add assistant message first (for streaming updates)
352
- this.messageManager.addAssistantMessage();
307
+ // Track if assistant message has been created
308
+ let assistantMessageCreated = false;
309
+
310
+ this.logger?.debug("modelConfig in sendAIMessage", this.getModelConfig());
353
311
 
354
- // Call AI service with streaming callbacks
355
- const result = await callAgent({
356
- gatewayConfig: this.gatewayConfig,
357
- modelConfig: this.modelConfig,
312
+ // Call AI service with streaming callbacks if enabled
313
+ const callAgentOptions: CallAgentOptions = {
314
+ gatewayConfig: this.getGatewayConfig(),
315
+ modelConfig: this.getModelConfig(),
358
316
  messages: recentMessages,
359
317
  sessionId: this.messageManager.getSessionId(),
360
318
  abortSignal: abortController.signal,
@@ -363,14 +321,27 @@ export class AIManager {
363
321
  tools: this.getFilteredToolsConfig(allowedTools), // Pass filtered tool configuration
364
322
  model: model, // Use passed model
365
323
  systemPrompt: this.systemPrompt, // Pass custom system prompt
366
- // Streaming callbacks
367
- onContentUpdate: (content: string) => {
324
+ };
325
+
326
+ // Add streaming callbacks only if streaming is enabled
327
+ if (this.stream) {
328
+ callAgentOptions.onContentUpdate = (content: string) => {
329
+ // Create assistant message on first chunk if not already created
330
+ if (!assistantMessageCreated) {
331
+ this.messageManager.addAssistantMessage();
332
+ assistantMessageCreated = true;
333
+ }
368
334
  this.messageManager.updateCurrentMessageContent(content);
369
- },
370
- onToolUpdate: (toolCall) => {
335
+ };
336
+ callAgentOptions.onToolUpdate = (toolCall) => {
337
+ // Create assistant message on first tool update if not already created
338
+ if (!assistantMessageCreated) {
339
+ this.messageManager.addAssistantMessage();
340
+ assistantMessageCreated = true;
341
+ }
342
+
371
343
  // Use parametersChunk as compact param for better performance
372
344
  // No need to extract params or generate compact params during streaming
373
- this.logger?.debug("Tool streaming update:", toolCall);
374
345
 
375
346
  // Update tool block with streaming parameters using parametersChunk as compact param
376
347
  this.messageManager.updateToolBlock({
@@ -381,8 +352,30 @@ export class AIManager {
381
352
  compactParams: toolCall.parameters?.split("\n").pop()?.slice(-30),
382
353
  stage: toolCall.stage || "streaming", // Default to streaming if stage not provided
383
354
  });
384
- },
385
- });
355
+ };
356
+ callAgentOptions.onReasoningUpdate = (reasoning: string) => {
357
+ // Create assistant message on first reasoning update if not already created
358
+ if (!assistantMessageCreated) {
359
+ this.messageManager.addAssistantMessage();
360
+ assistantMessageCreated = true;
361
+ }
362
+ this.messageManager.updateCurrentMessageReasoning(reasoning);
363
+ };
364
+ }
365
+
366
+ const result = await callAgent(callAgentOptions);
367
+ const createdByStreaming = assistantMessageCreated;
368
+
369
+ // For non-streaming mode, create assistant message after callAgent returns
370
+ // Also create if streaming mode but no streaming callbacks were called (e.g., when content comes directly in result)
371
+ if (
372
+ !this.stream ||
373
+ (!assistantMessageCreated &&
374
+ (result.content || result.tool_calls || result.reasoning_content))
375
+ ) {
376
+ this.messageManager.addAssistantMessage();
377
+ assistantMessageCreated = true;
378
+ }
386
379
 
387
380
  // Log finish reason and response headers if available
388
381
  if (result.finish_reason) {
@@ -397,12 +390,24 @@ export class AIManager {
397
390
  this.logger?.debug("AI response headers:", result.response_headers);
398
391
  }
399
392
 
400
- if (result.metadata && Object.keys(result.metadata).length > 0) {
401
- this.messageManager.mergeAssistantMetadata(result.metadata);
393
+ if (
394
+ result.additionalFields &&
395
+ Object.keys(result.additionalFields).length > 0
396
+ ) {
397
+ this.messageManager.mergeAssistantAdditionalFields(
398
+ result.additionalFields,
399
+ );
400
+ }
401
+
402
+ // Handle result reasoning content from non-streaming mode
403
+ if (result.reasoning_content && !createdByStreaming) {
404
+ this.messageManager.updateCurrentMessageReasoning(
405
+ result.reasoning_content,
406
+ );
402
407
  }
403
408
 
404
409
  // Handle result content from non-streaming mode
405
- if (result.content) {
410
+ if (result.content && !createdByStreaming) {
406
411
  this.messageManager.updateCurrentMessageContent(result.content);
407
412
  }
408
413
 
@@ -413,7 +418,7 @@ export class AIManager {
413
418
  prompt_tokens: result.usage.prompt_tokens,
414
419
  completion_tokens: result.usage.completion_tokens,
415
420
  total_tokens: result.usage.total_tokens,
416
- model: model || this.modelConfig.agentModel,
421
+ model: model || this.getModelConfig().agentModel,
417
422
  operation_type: "agent",
418
423
  // Preserve cache fields if present
419
424
  ...(result.usage.cache_read_input_tokens !== undefined && {
@@ -557,18 +562,6 @@ export class AIManager {
557
562
  shortResult: toolResult.shortResult,
558
563
  });
559
564
 
560
- // If tool returns diff information, add diff block
561
- if (
562
- toolResult.success &&
563
- toolResult.diffResult &&
564
- toolResult.filePath
565
- ) {
566
- this.messageManager.addDiffBlock(
567
- toolResult.filePath,
568
- toolResult.diffResult,
569
- );
570
- }
571
-
572
565
  // Execute PostToolUse hooks after successful tool completion
573
566
  await this.executePostToolUseHooks(
574
567
  toolId,
@@ -682,6 +675,7 @@ export class AIManager {
682
675
  cwd: this.workdir,
683
676
  subagentType: this.subagentType, // Include subagent type in hook context
684
677
  // Stop hooks don't need toolName, toolInput, toolResponse, or userPrompt
678
+ env: this.getEnvironmentVarsFn?.() || {}, // Include configuration environment variables
685
679
  };
686
680
 
687
681
  const results = await this.hookManager.executeHooks(hookName, context);
@@ -752,6 +746,7 @@ export class AIManager {
752
746
  cwd: this.workdir,
753
747
  toolInput,
754
748
  subagentType: this.subagentType, // Include subagent type in hook context
749
+ env: this.getEnvironmentVarsFn?.() || {}, // Include configuration environment variables
755
750
  };
756
751
 
757
752
  const results = await this.hookManager.executeHooks(
@@ -817,6 +812,7 @@ export class AIManager {
817
812
  toolInput,
818
813
  toolResponse,
819
814
  subagentType: this.subagentType, // Include subagent type in hook context
815
+ env: this.getEnvironmentVarsFn?.() || {}, // Include configuration environment variables
820
816
  };
821
817
 
822
818
  const results = await this.hookManager.executeHooks(
@@ -1,5 +1,6 @@
1
1
  import { spawn } from "child_process";
2
2
  import { logger } from "../utils/globalLogger.js";
3
+ import { stripAnsiColors } from "../utils/stringUtils.js";
3
4
  import type { BackgroundShell } from "../types/index.js";
4
5
 
5
6
  export interface BackgroundBashManagerCallbacks {
@@ -63,12 +64,12 @@ export class BackgroundBashManager {
63
64
  }
64
65
 
65
66
  child.stdout?.on("data", (data) => {
66
- shell.stdout += data.toString();
67
+ shell.stdout += stripAnsiColors(data.toString());
67
68
  this.notifyShellsChange();
68
69
  });
69
70
 
70
71
  child.stderr?.on("data", (data) => {
71
- shell.stderr += data.toString();
72
+ shell.stderr += stripAnsiColors(data.toString());
72
73
  this.notifyShellsChange();
73
74
  });
74
75
 
@@ -87,7 +88,7 @@ export class BackgroundBashManager {
87
88
  clearTimeout(timeoutHandle);
88
89
  }
89
90
  shell.status = "completed";
90
- shell.stderr += `\nProcess error: ${error.message}`;
91
+ shell.stderr += `\nProcess error: ${stripAnsiColors(error.message)}`;
91
92
  shell.exitCode = 1;
92
93
  shell.runtime = Date.now() - startTime;
93
94
  this.notifyShellsChange();
@@ -19,18 +19,13 @@ import {
19
19
  isValidHookEventConfig,
20
20
  } from "../types/hooks.js";
21
21
  import { HookMatcher } from "../utils/hookMatcher.js";
22
- import {
23
- executeCommand,
24
- isCommandSafe,
25
- loadMergedWaveConfig,
26
- } from "../services/hook.js";
22
+ import { executeCommand, isCommandSafe } from "../services/hook.js";
27
23
  import type { Logger } from "../types/index.js";
28
24
  import { MessageSource } from "../types/index.js";
29
25
  import type { MessageManager } from "./messageManager.js";
30
26
 
31
27
  export class HookManager {
32
28
  private configuration: PartialHookConfiguration | undefined;
33
- private environmentVars: Record<string, string> | undefined;
34
29
  private readonly matcher: HookMatcher;
35
30
  private readonly logger?: Logger;
36
31
  private readonly workdir: string;
@@ -78,49 +73,41 @@ export class HookManager {
78
73
  }
79
74
 
80
75
  /**
81
- * Load configuration from filesystem settings
82
- * Automatically loads and merges user and project Wave configuration (hooks + environment)
76
+ * Load hooks configuration from a pre-loaded WaveConfiguration
77
+ * Configuration loading is now handled by ConfigurationService
83
78
  */
84
- loadConfigurationFromSettings(): void {
79
+ loadConfigurationFromWaveConfig(waveConfig: WaveConfiguration | null): void {
85
80
  try {
86
- this.logger?.debug(`[HookManager] Loading configuration...`);
87
- const mergedWaveConfig = loadMergedWaveConfig(this.workdir);
88
81
  this.logger?.debug(
89
- `[HookManager] Merged config result:`,
90
- mergedWaveConfig,
82
+ `[HookManager] Loading hooks configuration from pre-loaded config...`,
91
83
  );
92
84
 
93
- this.configuration = mergedWaveConfig?.hooks || undefined;
94
- this.environmentVars = mergedWaveConfig?.env || undefined;
85
+ this.configuration = waveConfig?.hooks || undefined;
95
86
 
96
87
  // Validate the loaded configuration if it exists
97
- if (mergedWaveConfig?.hooks) {
98
- const validation = this.validatePartialConfiguration(
99
- mergedWaveConfig.hooks,
100
- );
88
+ if (waveConfig?.hooks) {
89
+ const validation = this.validatePartialConfiguration(waveConfig.hooks);
101
90
  if (!validation.valid) {
102
91
  throw new HookConfigurationError(
103
- "filesystem settings",
92
+ "provided configuration",
104
93
  validation.errors,
105
94
  );
106
95
  }
107
96
  }
108
97
 
109
98
  this.logger?.debug(
110
- `[HookManager] Configuration loaded successfully with ${Object.keys(mergedWaveConfig?.hooks || {}).length} event types and ${Object.keys(this.environmentVars || {}).length} environment variables`,
99
+ `[HookManager] Hooks configuration loaded successfully with ${Object.keys(waveConfig?.hooks || {}).length} event types`,
111
100
  );
112
101
  } catch (error) {
113
102
  // If loading fails, start with undefined configuration (no hooks)
114
103
  this.configuration = undefined;
115
- this.environmentVars = undefined;
116
104
 
117
- // Re-throw configuration errors, but handle file system errors gracefully
105
+ // Re-throw configuration errors, but handle other errors gracefully
118
106
  if (error instanceof HookConfigurationError) {
119
107
  throw error;
120
108
  } else {
121
109
  this.logger?.warn(
122
- "Failed to load hooks configuration from settings:",
123
- error,
110
+ `[HookManager] Failed to load configuration, continuing with no hooks: ${(error as Error).message}`,
124
111
  );
125
112
  }
126
113
  }
@@ -207,7 +194,6 @@ export class HookManager {
207
194
  hookCommand.command,
208
195
  context,
209
196
  undefined,
210
- this.environmentVars,
211
197
  );
212
198
  results.push(result);
213
199
 
@@ -379,6 +365,19 @@ export class HookManager {
379
365
  });
380
366
  return { shouldBlock: true, errorMessage };
381
367
 
368
+ case "Notification":
369
+ // For notification hooks with exit code 2, only show stderr in error block
370
+ messageManager.addErrorBlock(errorMessage);
371
+ return { shouldBlock: false };
372
+
373
+ case "SubagentStop":
374
+ // Similar to Stop, show error and allow blocking
375
+ messageManager.addUserMessage({
376
+ content: errorMessage,
377
+ source: MessageSource.HOOK,
378
+ });
379
+ return { shouldBlock: true, errorMessage };
380
+
382
381
  default:
383
382
  return { shouldBlock: false };
384
383
  }
@@ -528,16 +527,6 @@ export class HookManager {
528
527
  return JSON.parse(JSON.stringify(this.configuration));
529
528
  }
530
529
 
531
- /**
532
- * Get current environment variables
533
- */
534
- getEnvironmentVars(): Record<string, string> | undefined {
535
- if (!this.environmentVars) return undefined;
536
-
537
- // Deep clone to prevent external modification
538
- return JSON.parse(JSON.stringify(this.environmentVars));
539
- }
540
-
541
530
  /**
542
531
  * Clear current configuration
543
532
  */
@@ -585,7 +574,10 @@ export class HookManager {
585
574
 
586
575
  // Validate non-tool events don't have unexpected tool names
587
576
  if (
588
- (event === "UserPromptSubmit" || event === "Stop") &&
577
+ (event === "UserPromptSubmit" ||
578
+ event === "Stop" ||
579
+ event === "Notification" ||
580
+ event === "SubagentStop") &&
589
581
  context.toolName !== undefined
590
582
  ) {
591
583
  this.logger?.warn(
@@ -657,7 +649,12 @@ export class HookManager {
657
649
  toolName?: string,
658
650
  ): boolean {
659
651
  // For events that don't use matchers, config always applies
660
- if (event === "UserPromptSubmit" || event === "Stop") {
652
+ if (
653
+ event === "UserPromptSubmit" ||
654
+ event === "Stop" ||
655
+ event === "Notification" ||
656
+ event === "SubagentStop"
657
+ ) {
661
658
  return true;
662
659
  }
663
660
 
@@ -703,7 +700,13 @@ export class HookManager {
703
700
  }
704
701
 
705
702
  // Validate that non-tool events don't have matchers
706
- if ((event === "UserPromptSubmit" || event === "Stop") && config.matcher) {
703
+ if (
704
+ (event === "UserPromptSubmit" ||
705
+ event === "Stop" ||
706
+ event === "Notification" ||
707
+ event === "SubagentStop") &&
708
+ config.matcher
709
+ ) {
707
710
  errors.push(`${prefix}: Event ${event} should not have a matcher`);
708
711
  }
709
712
 
@@ -739,6 +742,7 @@ export class HookManager {
739
742
  UserPromptSubmit: 0,
740
743
  Stop: 0,
741
744
  SubagentStop: 0,
745
+ Notification: 0,
742
746
  },
743
747
  };
744
748
  }
@@ -749,6 +753,7 @@ export class HookManager {
749
753
  UserPromptSubmit: 0,
750
754
  Stop: 0,
751
755
  SubagentStop: 0,
756
+ Notification: 0,
752
757
  };
753
758
 
754
759
  let totalConfigs = 0;