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
@@ -12,15 +12,13 @@ import {
12
12
  } from "../utils/commandArgumentParser.js";
13
13
  import { Container } from "../utils/container.js";
14
14
  import {
15
- BashCommandResult,
16
15
  parseBashCommands,
17
16
  replaceBashCommandsWithOutput,
17
+ executeBashCommands,
18
18
  } from "../utils/markdownParser.js";
19
- import { exec } from "child_process";
20
- import { promisify } from "util";
21
19
  import { INIT_PROMPT } from "../prompts/index.js";
22
-
23
- const execAsync = promisify(exec);
20
+ import type { SkillManager } from "./skillManager.js";
21
+ import type { SkillMetadata } from "../types/skills.js";
24
22
 
25
23
  import { logger } from "../utils/globalLogger.js";
26
24
 
@@ -31,6 +29,7 @@ export interface SlashCommandManagerOptions {
31
29
  export class SlashCommandManager {
32
30
  private commands = new Map<string, SlashCommand>();
33
31
  private customCommands = new Map<string, CustomSlashCommand>();
32
+ private skillCommandIds = new Set<string>();
34
33
  private workdir: string;
35
34
 
36
35
  constructor(
@@ -61,25 +60,11 @@ export class SlashCommandManager {
61
60
  return this.container.get<TaskManager>("TaskManager")!;
62
61
  }
63
62
 
64
- private initializeBuiltinCommands(): void {
65
- // Register built-in clear command
66
- this.registerCommand({
67
- id: "clear",
68
- name: "clear",
69
- description: "Clear the chat session and terminal",
70
- handler: () => {
71
- // Clear chat messages
72
- this.messageManager.clearMessages();
73
-
74
- // Reset task list if WAVE_TASK_LIST_ID is not set
75
- if (!process.env.WAVE_TASK_LIST_ID) {
76
- const newTaskListId = this.messageManager.getRootSessionId();
77
- this.taskManager.setTaskListId(newTaskListId);
78
- this.taskManager.emit("tasksChange", newTaskListId);
79
- }
80
- },
81
- });
63
+ private get skillManager(): SkillManager {
64
+ return this.container.get<SkillManager>("SkillManager")!;
65
+ }
82
66
 
67
+ private initializeBuiltinCommands(): void {
83
68
  // Register built-in init command
84
69
  this.registerCommand({
85
70
  id: "init",
@@ -132,15 +117,10 @@ export class SlashCommandManager {
132
117
  }
133
118
 
134
119
  if (args) {
135
- if (hasParameterPlaceholders(processedContent)) {
136
- processedContent = substituteCommandParameters(
137
- processedContent,
138
- args,
139
- );
140
- } else {
141
- // If no placeholders, append arguments to the content
142
- processedContent = `${processedContent.trim()} ${args}`;
143
- }
120
+ processedContent = substituteCommandParameters(
121
+ processedContent,
122
+ args,
123
+ );
144
124
  }
145
125
 
146
126
  await this.executeCustomCommandInMainAgent(
@@ -159,6 +139,66 @@ export class SlashCommandManager {
159
139
  }
160
140
  }
161
141
 
142
+ /**
143
+ * Register skills as slash commands
144
+ */
145
+ public registerSkillCommands(skills: SkillMetadata[]): void {
146
+ // Clear existing skill commands
147
+ for (const commandId of this.skillCommandIds) {
148
+ this.unregisterCommand(commandId);
149
+ }
150
+ this.skillCommandIds.clear();
151
+
152
+ for (const skill of skills) {
153
+ if (skill.userInvocable === false) {
154
+ continue;
155
+ }
156
+ const commandId = skill.name;
157
+ this.skillCommandIds.add(commandId);
158
+
159
+ this.registerCommand({
160
+ id: commandId,
161
+ name: skill.name,
162
+ description: `Skill: ${skill.description}`,
163
+ handler: async (args?: string) => {
164
+ try {
165
+ const result = await this.skillManager.executeSkill({
166
+ skill_name: skill.name,
167
+ args,
168
+ });
169
+
170
+ // Add user message with skill content
171
+ const originalInput = args
172
+ ? `/${skill.name} ${args}`
173
+ : `/${skill.name}`;
174
+ this.messageManager.addUserMessage({
175
+ content: originalInput,
176
+ customCommandContent: result.content,
177
+ });
178
+
179
+ // Trigger AI response
180
+ await this.aiManager.sendAIMessage({
181
+ model: skill.model,
182
+ allowedRules: result.allowedTools,
183
+ });
184
+ } catch (error) {
185
+ logger?.error(
186
+ `Failed to execute skill command '${skill.name}':`,
187
+ error,
188
+ );
189
+ this.messageManager.addErrorBlock(
190
+ `Failed to execute skill command '${skill.name}': ${
191
+ error instanceof Error ? error.message : String(error)
192
+ }`,
193
+ );
194
+ }
195
+ },
196
+ });
197
+ }
198
+
199
+ logger?.debug(`Registered ${skills.length} skill commands`);
200
+ }
201
+
162
202
  /**
163
203
  * Register commands from a plugin with namespacing
164
204
  */
@@ -195,15 +235,10 @@ export class SlashCommandManager {
195
235
  }
196
236
 
197
237
  if (args) {
198
- if (hasParameterPlaceholders(processedContent)) {
199
- processedContent = substituteCommandParameters(
200
- processedContent,
201
- args,
202
- );
203
- } else {
204
- // If no placeholders, append arguments to the content
205
- processedContent = `${processedContent.trim()} ${args}`;
206
- }
238
+ processedContent = substituteCommandParameters(
239
+ processedContent,
240
+ args,
241
+ );
207
242
  }
208
243
 
209
244
  await this.executeCustomCommandInMainAgent(
@@ -343,40 +378,15 @@ export class SlashCommandManager {
343
378
  const { commands, processedContent } = parseBashCommands(content);
344
379
 
345
380
  // Execute bash commands if any
346
- const bashResults: BashCommandResult[] = [];
347
- for (const command of commands) {
348
- try {
349
- const { stdout, stderr } = await execAsync(command, {
350
- cwd: this.workdir,
351
- timeout: 30000, // 30 second timeout
352
- });
353
- bashResults.push({
354
- command,
355
- output: stdout || stderr || "",
356
- exitCode: 0,
357
- });
358
- } catch (error) {
359
- const execError = error as {
360
- stdout?: string;
361
- stderr?: string;
362
- message?: string;
363
- code?: number;
364
- };
365
- bashResults.push({
366
- command,
367
- output:
368
- execError.stdout || execError.stderr || execError.message || "",
369
- exitCode: execError.code || 1,
370
- });
371
- }
381
+ let finalContent = processedContent;
382
+ if (commands.length > 0) {
383
+ const bashResults = await executeBashCommands(commands, this.workdir);
384
+ finalContent = replaceBashCommandsWithOutput(
385
+ processedContent,
386
+ bashResults,
387
+ );
372
388
  }
373
389
 
374
- // Replace bash command placeholders with their outputs
375
- const finalContent =
376
- bashResults.length > 0
377
- ? replaceBashCommandsWithOutput(processedContent, bashResults)
378
- : processedContent;
379
-
380
390
  // Add custom command message to show the command being executed
381
391
  const originalInput = args
382
392
  ? `/${commandName} ${args}`
@@ -14,12 +14,14 @@ import {
14
14
  createAbortPromise,
15
15
  } from "../utils/abortUtils.js";
16
16
  import { BackgroundTaskManager } from "./backgroundTaskManager.js";
17
+ import { logger } from "../utils/globalLogger.js";
17
18
  import {
18
19
  UserMessageParams,
19
20
  type AgentToolBlockUpdateParams,
20
21
  } from "../utils/messageOperations.js";
21
22
 
22
23
  import { Container } from "../utils/container.js";
24
+ import type { PermissionManager } from "./permissionManager.js";
23
25
 
24
26
  export interface SubagentManagerCallbacks {
25
27
  // Granular subagent message callbacks (015-subagent-message-callbacks)
@@ -67,8 +69,10 @@ export interface SubagentInstance {
67
69
  lastTools: string[]; // Track last two tool names
68
70
  subagentType: string; // Store the subagent type for hook context
69
71
  description: string; // Store the AI-generated description
72
+ allowedTools?: string[]; // Optional permission rules (e.g. git:*)
70
73
  backgroundTaskId?: string; // ID of the background task if transitioned
71
74
  onUpdate?: () => void; // Optional callback for real-time updates
75
+ model?: string; // Optional model override
72
76
  }
73
77
 
74
78
  export interface SubagentManagerOptions {
@@ -159,6 +163,8 @@ export class SubagentManager {
159
163
  description: string;
160
164
  prompt: string;
161
165
  subagent_type: string;
166
+ allowedTools?: string[];
167
+ model?: string;
162
168
  },
163
169
  runInBackground?: boolean,
164
170
  onUpdate?: () => void,
@@ -176,6 +182,31 @@ export class SubagentManager {
176
182
  // Create a child container for the subagent to isolate its managers
177
183
  const subagentContainer = this.container.createChild();
178
184
 
185
+ // Create isolated PermissionManager for the subagent
186
+ const { PermissionManager } = await import("./permissionManager.js");
187
+ const parentPermissionManager =
188
+ this.container.get<PermissionManager>("PermissionManager");
189
+ const subagentPermissionManager = new PermissionManager(subagentContainer, {
190
+ workdir: this.workdir,
191
+ configuredDefaultMode:
192
+ parentPermissionManager?.getConfiguredDefaultMode(),
193
+ allowedRules: parentPermissionManager?.getAllowedRules(),
194
+ deniedRules: parentPermissionManager?.getDeniedRules(),
195
+ additionalDirectories:
196
+ parentPermissionManager?.getAdditionalDirectories(),
197
+ planFilePath: parentPermissionManager?.getPlanFilePath(),
198
+ });
199
+ subagentContainer.register("PermissionManager", subagentPermissionManager);
200
+
201
+ // Add temporary permission rules if provided
202
+ if (parameters.allowedTools) {
203
+ logger.debug(
204
+ `Adding ${parameters.allowedTools.length} temporary permission rules to subagent ${subagentId}`,
205
+ { rules: parameters.allowedTools },
206
+ );
207
+ subagentPermissionManager.addTemporaryRules(parameters.allowedTools);
208
+ }
209
+
179
210
  // Create isolated MessageManager for the subagent
180
211
  const subagentCallbacks = this.createSubagentCallbacks(subagentId);
181
212
 
@@ -187,8 +218,13 @@ export class SubagentManager {
187
218
  });
188
219
  subagentContainer.register("MessageManager", messageManager);
189
220
 
190
- // Use the parent tool manager directly - tool restrictions will be handled by allowedTools parameter
191
- const toolManager = parentToolManager;
221
+ // Create isolated ToolManager for the subagent to ensure it uses the subagent's PermissionManager
222
+ const toolManager = new ToolManager({
223
+ container: subagentContainer,
224
+ tools: configuration.tools,
225
+ });
226
+ toolManager.initializeBuiltInTools();
227
+ subagentContainer.register("ToolManager", toolManager);
192
228
 
193
229
  // Create isolated AIManager for the subagent
194
230
  const aiManager = new AIManager(subagentContainer, {
@@ -201,9 +237,12 @@ export class SubagentManager {
201
237
  const parentModelConfig = this.getModelConfig();
202
238
  let modelToUse: string;
203
239
 
204
- if (!configuration.model || configuration.model === "inherit") {
205
- // Use parent's agentModel for "inherit" or undefined
206
- modelToUse = parentModelConfig.agentModel;
240
+ if (parameters.model) {
241
+ // Use model override from parameters if provided
242
+ modelToUse = parameters.model;
243
+ } else if (!configuration.model || configuration.model === "inherit") {
244
+ // Use parent's model for "inherit" or undefined
245
+ modelToUse = parentModelConfig.model;
207
246
  } else if (configuration.model === "fastModel") {
208
247
  // Use parent's fastModel for special "fastModel" value
209
248
  modelToUse = parentModelConfig.fastModel;
@@ -214,7 +253,7 @@ export class SubagentManager {
214
253
 
215
254
  return {
216
255
  ...parentModelConfig,
217
- agentModel: modelToUse,
256
+ model: modelToUse,
218
257
  };
219
258
  },
220
259
  getMaxInputTokens: this.getMaxInputTokens,
@@ -237,6 +276,8 @@ export class SubagentManager {
237
276
  lastTools: [], // Initialize lastTools
238
277
  subagentType: parameters.subagent_type, // Store the subagent type
239
278
  description: parameters.description, // Store the AI-generated description
279
+ allowedTools: parameters.allowedTools, // Store optional permission rules
280
+ model: parameters.model, // Store optional model override
240
281
  onUpdate,
241
282
  };
242
283
 
@@ -392,23 +433,26 @@ export class SubagentManager {
392
433
  // Add the user's prompt as a message
393
434
  instance.messageManager.addUserMessage({ content: prompt });
394
435
 
395
- // Create allowed tools list - always exclude Task tool to prevent subagent recursion
396
- let allowedTools = instance.configuration.tools;
436
+ // Create enabled tools list - always exclude Task tool to prevent subagent recursion
437
+ // Use instance.configuration.tools if provided, otherwise fallback to all tools
438
+ let enabledTools = instance.configuration.tools;
397
439
 
398
440
  // Always filter out the Task tool to prevent subagents from creating sub-subagents
399
- if (allowedTools) {
400
- allowedTools = allowedTools.filter((tool) => tool !== "Task");
441
+ if (enabledTools) {
442
+ enabledTools = enabledTools.filter((tool) => tool !== "Task");
401
443
  } else {
402
444
  // If no tools specified, get all tools except Task
403
445
  const allTools = instance.toolManager.list().map((tool) => tool.name);
404
- allowedTools = allTools.filter((tool) => tool !== "Task");
446
+ enabledTools = allTools.filter((tool) => tool !== "Task");
405
447
  }
406
448
 
407
449
  // Execute the AI request with tool restrictions
408
450
  // The AIManager will handle abort signals through its own abort controllers
409
451
  // Resolve model name for sendAIMessage
410
452
  let resolvedModel: string | undefined;
411
- if (
453
+ if (instance.model) {
454
+ resolvedModel = instance.model;
455
+ } else if (
412
456
  instance.configuration.model &&
413
457
  instance.configuration.model !== "inherit"
414
458
  ) {
@@ -424,7 +468,7 @@ export class SubagentManager {
424
468
  // For "inherit" or undefined, resolvedModel remains undefined (uses AIManager default)
425
469
 
426
470
  const executeAI = instance.aiManager.sendAIMessage({
427
- tools: allowedTools,
471
+ tools: enabledTools,
428
472
  model: resolvedModel,
429
473
  });
430
474
 
@@ -37,6 +37,9 @@ import { Container } from "../utils/container.js";
37
37
 
38
38
  import { logger } from "../utils/globalLogger.js";
39
39
 
40
+ import type { SubagentConfiguration } from "../utils/subagentParser.js";
41
+ import type { SkillMetadata } from "../types/skills.js";
42
+
40
43
  export interface ToolManagerOptions {
41
44
  container: Container;
42
45
  /** Optional list of tool names to enable */
@@ -244,7 +247,11 @@ class ToolManager {
244
247
  return [...builtInTools, ...mcpTools];
245
248
  }
246
249
 
247
- getToolsConfig(): ChatCompletionFunctionTool[] {
250
+ getToolsConfig(options?: {
251
+ availableSubagents?: SubagentConfiguration[];
252
+ availableSkills?: SkillMetadata[];
253
+ workdir?: string;
254
+ }): ChatCompletionFunctionTool[] {
248
255
  const effectivePermissionMode = this.getPermissionMode();
249
256
  const builtInToolsConfig = Array.from(this.toolsRegistry.values())
250
257
  .filter((tool) => {
@@ -258,7 +265,20 @@ class ToolManager {
258
265
  }
259
266
  return true;
260
267
  })
261
- .map((tool) => tool.config);
268
+ .map((tool) => {
269
+ // Create a copy of the tool config to avoid modifying the original
270
+ const config = {
271
+ ...tool.config,
272
+ function: {
273
+ ...tool.config.function,
274
+ },
275
+ };
276
+ // Override description with prompt if available
277
+ if (tool.prompt) {
278
+ config.function.description = tool.prompt(options);
279
+ }
280
+ return config;
281
+ });
262
282
  const mcpToolsConfig = this.mcpManager.getMcpToolsConfig();
263
283
  return [...builtInToolsConfig, ...mcpToolsConfig];
264
284
  }
@@ -288,9 +288,6 @@ Any promises made to the user
288
288
  Be concise but complete—err on the side of including information that would prevent duplicate work or repeated mistakes. Write in a way that enables immediate resumption of the task.
289
289
  Wrap your summary in <summary></summary> tags.`;
290
290
 
291
- import type { SubagentConfiguration } from "../utils/subagentParser.js";
292
- import type { SkillMetadata } from "../types/skills.js";
293
-
294
291
  export function buildSystemPrompt(
295
292
  basePrompt: string | undefined,
296
293
  tools: ToolPlugin[],
@@ -303,8 +300,6 @@ export function buildSystemPrompt(
303
300
  planFilePath: string;
304
301
  planExists: boolean;
305
302
  };
306
- availableSubagents?: SubagentConfiguration[];
307
- availableSkills?: SkillMetadata[];
308
303
  } = {},
309
304
  ): string {
310
305
  let prompt = basePrompt || DEFAULT_SYSTEM_PROMPT;
@@ -312,16 +307,6 @@ export function buildSystemPrompt(
312
307
  prompt += `\n\n${TOOL_POLICY}`;
313
308
  }
314
309
 
315
- for (const tool of tools) {
316
- if (tool.prompt) {
317
- prompt += tool.prompt({
318
- availableSubagents: options.availableSubagents,
319
- availableSkills: options.availableSkills,
320
- workdir: options.workdir,
321
- });
322
- }
323
- }
324
-
325
310
  if (options.language) {
326
311
  prompt += `\n\n# Language\nAlways respond in ${options.language}. Technical terms (e.g., code, tool names, file paths) should remain in their original language or English where appropriate.`;
327
312
  }
@@ -132,9 +132,9 @@ function getModelConfig(
132
132
  };
133
133
 
134
134
  // Configuration rules for specific models
135
- if (modelName.includes("gpt-5-codex")) {
136
- // gpt-5-codex model sets temperature to undefined
137
- config.temperature = undefined;
135
+ if (modelName.includes("gpt-5")) {
136
+ // gpt-5 models should not have temperature field
137
+ delete config.temperature;
138
138
  }
139
139
 
140
140
  return config;
@@ -203,7 +203,7 @@ export async function callAgent(
203
203
  // Apply global 1 QPS rate limit
204
204
  if (
205
205
  process.env.NODE_ENV !== "test" ||
206
- modelConfig.agentModel === "rate-limit-test"
206
+ modelConfig.model === "rate-limit-test"
207
207
  ) {
208
208
  await acquireSlot(abortSignal);
209
209
  }
@@ -239,7 +239,7 @@ export async function callAgent(
239
239
  openaiMessages = [systemMessage, ...messages];
240
240
 
241
241
  // Apply cache control for Claude models
242
- const currentModel = model || modelConfig.agentModel;
242
+ const currentModel = model || modelConfig.model;
243
243
  const resolvedMaxTokens = options.maxTokens ?? modelConfig.maxTokens;
244
244
 
245
245
  processedTools = tools;
@@ -257,7 +257,7 @@ export async function callAgent(
257
257
  }
258
258
 
259
259
  // Get model configuration - use injected modelConfig with optional override
260
- const openaiModelConfig = getModelConfig(model || modelConfig.agentModel, {
260
+ const openaiModelConfig = getModelConfig(model || modelConfig.model, {
261
261
  temperature: 0,
262
262
  max_tokens: resolvedMaxTokens,
263
263
  });
@@ -421,7 +421,7 @@ export async function callAgent(
421
421
  const debugData: DebugData = {
422
422
  originalMessages: messages,
423
423
  timestamp: new Date().toISOString(),
424
- model: model || modelConfig.agentModel,
424
+ model: model || modelConfig.model,
425
425
  workdir,
426
426
  sessionId: options.sessionId,
427
427
  gatewayConfig: {
@@ -760,7 +760,7 @@ export async function compressMessages(
760
760
  // Apply global 1 QPS rate limit
761
761
  if (
762
762
  process.env.NODE_ENV !== "test" ||
763
- modelConfig.agentModel === "rate-limit-test"
763
+ modelConfig.model === "rate-limit-test"
764
764
  ) {
765
765
  await acquireSlot(abortSignal);
766
766
  }
@@ -775,13 +775,10 @@ export async function compressMessages(
775
775
  });
776
776
 
777
777
  // Get model configuration - use injected agent model
778
- const openaiModelConfig = getModelConfig(
779
- options.model || modelConfig.agentModel,
780
- {
781
- temperature: 0.1,
782
- max_tokens: 2048,
783
- },
784
- );
778
+ const openaiModelConfig = getModelConfig(options.model || modelConfig.model, {
779
+ temperature: 0.1,
780
+ max_tokens: 2048,
781
+ });
785
782
 
786
783
  try {
787
784
  const response = await openai.chat.completions.create(
@@ -444,13 +444,13 @@ export class ConfigurationService {
444
444
  /**
445
445
  * Resolves model configuration with fallbacks
446
446
  * Resolution priority: options > env (from settings.json) > process.env > default
447
- * @param agentModel - Agent model from constructor (optional)
447
+ * @param model - Agent model from constructor (optional)
448
448
  * @param fastModel - Fast model from constructor (optional)
449
449
  * @param maxTokens - Max output tokens from constructor (optional)
450
450
  * @returns Resolved model configuration with defaults
451
451
  */
452
452
  resolveModelConfig(
453
- agentModel?: string,
453
+ model?: string,
454
454
  fastModel?: string,
455
455
  maxTokens?: number,
456
456
  permissionMode?: PermissionMode,
@@ -460,7 +460,7 @@ export class ConfigurationService {
460
460
  const DEFAULT_FAST_MODEL = "gemini-2.5-flash";
461
461
 
462
462
  // Resolve agent model: constructor > env (settings.json) > process.env > default
463
- let resolvedAgentModel = agentModel || this.env.WAVE_MODEL;
463
+ let resolvedAgentModel = model || this.env.WAVE_MODEL;
464
464
 
465
465
  if (!resolvedAgentModel && this.currentConfiguration?.env?.WAVE_MODEL) {
466
466
  resolvedAgentModel = this.currentConfiguration.env.WAVE_MODEL;
@@ -481,7 +481,7 @@ export class ConfigurationService {
481
481
  const resolvedMaxTokens = this.resolveMaxOutputTokens(maxTokens);
482
482
 
483
483
  return {
484
- agentModel: resolvedAgentModel,
484
+ model: resolvedAgentModel,
485
485
  fastModel: resolvedFastModel,
486
486
  maxTokens: resolvedMaxTokens,
487
487
  permissionMode,
@@ -83,6 +83,13 @@ async function buildHookJsonInput(
83
83
  }
84
84
  }
85
85
 
86
+ // Add name field for WorktreeCreate events
87
+ if (context.event === "WorktreeCreate") {
88
+ if (context.worktreeName !== undefined) {
89
+ jsonInput.name = context.worktreeName;
90
+ }
91
+ }
92
+
86
93
  return jsonInput;
87
94
  }
88
95