wave-agent-sdk 0.0.1 → 0.0.3
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.
- package/dist/agent.d.ts +37 -3
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +82 -5
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/managers/aiManager.d.ts +7 -1
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +11 -5
- package/dist/managers/messageManager.d.ts +8 -0
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +26 -2
- package/dist/managers/skillManager.d.ts +4 -5
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +6 -82
- package/dist/managers/subagentManager.d.ts +96 -0
- package/dist/managers/subagentManager.d.ts.map +1 -0
- package/dist/managers/subagentManager.js +261 -0
- package/dist/managers/toolManager.d.ts +33 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +43 -5
- package/dist/services/aiService.d.ts +5 -0
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +58 -28
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +4 -0
- package/dist/tools/grepTool.d.ts.map +1 -1
- package/dist/tools/grepTool.js +8 -6
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +36 -6
- package/dist/tools/skillTool.d.ts +8 -0
- package/dist/tools/skillTool.d.ts.map +1 -0
- package/dist/tools/skillTool.js +72 -0
- package/dist/tools/taskTool.d.ts +8 -0
- package/dist/tools/taskTool.d.ts.map +1 -0
- package/dist/tools/taskTool.js +109 -0
- package/dist/tools/todoWriteTool.d.ts +6 -0
- package/dist/tools/todoWriteTool.d.ts.map +1 -0
- package/dist/tools/todoWriteTool.js +203 -0
- package/dist/types.d.ts +65 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +16 -0
- package/dist/utils/configResolver.d.ts +38 -0
- package/dist/utils/configResolver.d.ts.map +1 -0
- package/dist/utils/configResolver.js +106 -0
- package/dist/utils/configValidator.d.ts +36 -0
- package/dist/utils/configValidator.d.ts.map +1 -0
- package/dist/utils/configValidator.js +78 -0
- package/dist/utils/constants.d.ts +10 -0
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +10 -0
- package/dist/utils/fileFormat.d.ts +17 -0
- package/dist/utils/fileFormat.d.ts.map +1 -0
- package/dist/utils/fileFormat.js +35 -0
- package/dist/utils/messageOperations.d.ts +18 -0
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +43 -0
- package/dist/utils/subagentParser.d.ts +19 -0
- package/dist/utils/subagentParser.d.ts.map +1 -0
- package/dist/utils/subagentParser.js +159 -0
- package/package.json +11 -15
- package/src/agent.ts +130 -9
- package/src/index.ts +0 -1
- package/src/managers/aiManager.ts +22 -10
- package/src/managers/messageManager.ts +55 -1
- package/src/managers/skillManager.ts +7 -96
- package/src/managers/subagentManager.ts +368 -0
- package/src/managers/toolManager.ts +50 -5
- package/src/services/aiService.ts +92 -36
- package/src/services/session.ts +5 -0
- package/src/tools/grepTool.ts +9 -6
- package/src/tools/readTool.ts +40 -6
- package/src/tools/skillTool.ts +82 -0
- package/src/tools/taskTool.ts +128 -0
- package/src/tools/todoWriteTool.ts +232 -0
- package/src/types.ts +85 -1
- package/src/utils/configResolver.ts +142 -0
- package/src/utils/configValidator.ts +133 -0
- package/src/utils/constants.ts +10 -0
- package/src/utils/fileFormat.ts +40 -0
- package/src/utils/messageOperations.ts +80 -0
- package/src/utils/subagentParser.ts +223 -0
|
@@ -11,7 +11,6 @@ import type {
|
|
|
11
11
|
SkillInvocationContext,
|
|
12
12
|
Logger,
|
|
13
13
|
} from "../types.js";
|
|
14
|
-
import type { ToolPlugin, ToolResult } from "../tools/types.js";
|
|
15
14
|
import { parseSkillFile, formatSkillError } from "../utils/skillParser.js";
|
|
16
15
|
|
|
17
16
|
/**
|
|
@@ -76,6 +75,13 @@ export class SkillManager {
|
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Check if the skill manager is initialized
|
|
80
|
+
*/
|
|
81
|
+
isInitialized(): boolean {
|
|
82
|
+
return this.initialized;
|
|
83
|
+
}
|
|
84
|
+
|
|
79
85
|
/**
|
|
80
86
|
* Get all available skills metadata
|
|
81
87
|
*/
|
|
@@ -233,101 +239,6 @@ export class SkillManager {
|
|
|
233
239
|
return directories;
|
|
234
240
|
}
|
|
235
241
|
|
|
236
|
-
/**
|
|
237
|
-
* Create a tool plugin for registering with ToolManager
|
|
238
|
-
*/
|
|
239
|
-
createTool(): ToolPlugin {
|
|
240
|
-
// Initialize skill manager asynchronously
|
|
241
|
-
let initializationPromise: Promise<void> | null = null;
|
|
242
|
-
|
|
243
|
-
const ensureInitialized = async (): Promise<void> => {
|
|
244
|
-
if (!initializationPromise) {
|
|
245
|
-
initializationPromise = this.initialize();
|
|
246
|
-
}
|
|
247
|
-
await initializationPromise;
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
const getToolDescription = (): string => {
|
|
251
|
-
if (!this.initialized) {
|
|
252
|
-
return "Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific. Skills will be loaded during initialization.";
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
const availableSkills = this.getAvailableSkills();
|
|
256
|
-
|
|
257
|
-
if (availableSkills.length === 0) {
|
|
258
|
-
return "Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific. No skills are currently available.";
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
const skillList = availableSkills
|
|
262
|
-
.map(
|
|
263
|
-
(skill) =>
|
|
264
|
-
`• **${skill.name}** (${skill.type}): ${skill.description}`,
|
|
265
|
-
)
|
|
266
|
-
.join("\n");
|
|
267
|
-
|
|
268
|
-
return `Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific.\n\nAvailable skills:\n${skillList}`;
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
return {
|
|
272
|
-
name: "skill",
|
|
273
|
-
config: {
|
|
274
|
-
type: "function",
|
|
275
|
-
function: {
|
|
276
|
-
name: "skill",
|
|
277
|
-
description: getToolDescription(),
|
|
278
|
-
parameters: {
|
|
279
|
-
type: "object",
|
|
280
|
-
properties: {
|
|
281
|
-
skill_name: {
|
|
282
|
-
type: "string",
|
|
283
|
-
description: "Name of the skill to invoke",
|
|
284
|
-
enum: this.initialized
|
|
285
|
-
? this.getAvailableSkills().map((skill) => skill.name)
|
|
286
|
-
: [],
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
required: ["skill_name"],
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
},
|
|
293
|
-
execute: async (args: Record<string, unknown>): Promise<ToolResult> => {
|
|
294
|
-
try {
|
|
295
|
-
// Ensure skill manager is initialized
|
|
296
|
-
await ensureInitialized();
|
|
297
|
-
|
|
298
|
-
// Validate arguments
|
|
299
|
-
const skillName = args.skill_name as string;
|
|
300
|
-
if (!skillName || typeof skillName !== "string") {
|
|
301
|
-
return {
|
|
302
|
-
success: false,
|
|
303
|
-
content: "",
|
|
304
|
-
error: "skill_name parameter is required and must be a string",
|
|
305
|
-
};
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
// Execute the skill
|
|
309
|
-
const result = await this.executeSkill({ skill_name: skillName });
|
|
310
|
-
|
|
311
|
-
return {
|
|
312
|
-
success: true,
|
|
313
|
-
content: result.content,
|
|
314
|
-
shortResult: `Invoked skill: ${skillName}`,
|
|
315
|
-
};
|
|
316
|
-
} catch (error) {
|
|
317
|
-
return {
|
|
318
|
-
success: false,
|
|
319
|
-
content: "",
|
|
320
|
-
error: error instanceof Error ? error.message : String(error),
|
|
321
|
-
};
|
|
322
|
-
}
|
|
323
|
-
},
|
|
324
|
-
formatCompactParams: (params: Record<string, unknown>) => {
|
|
325
|
-
const skillName = params.skill_name as string;
|
|
326
|
-
return skillName || "unknown-skill";
|
|
327
|
-
},
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
|
|
331
242
|
/**
|
|
332
243
|
* Execute a skill by name
|
|
333
244
|
*/
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
import { randomUUID } from "crypto";
|
|
2
|
+
import type { SubagentConfiguration } from "../utils/subagentParser.js";
|
|
3
|
+
import type { Message, Logger, GatewayConfig, ModelConfig } from "../types.js";
|
|
4
|
+
import { AIManager } from "./aiManager.js";
|
|
5
|
+
import {
|
|
6
|
+
MessageManager,
|
|
7
|
+
type MessageManagerCallbacks,
|
|
8
|
+
} from "./messageManager.js";
|
|
9
|
+
import { ToolManager } from "./toolManager.js";
|
|
10
|
+
|
|
11
|
+
export interface SubagentInstance {
|
|
12
|
+
subagentId: string;
|
|
13
|
+
configuration: SubagentConfiguration;
|
|
14
|
+
aiManager: AIManager;
|
|
15
|
+
messageManager: MessageManager;
|
|
16
|
+
toolManager: ToolManager;
|
|
17
|
+
status: "initializing" | "active" | "completed" | "error" | "aborted";
|
|
18
|
+
taskDescription: string;
|
|
19
|
+
messages: Message[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface SubagentManagerOptions {
|
|
23
|
+
workdir: string;
|
|
24
|
+
parentToolManager: ToolManager;
|
|
25
|
+
parentMessageManager: MessageManager;
|
|
26
|
+
logger?: Logger;
|
|
27
|
+
gatewayConfig: GatewayConfig;
|
|
28
|
+
modelConfig: ModelConfig;
|
|
29
|
+
tokenLimit: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class SubagentManager {
|
|
33
|
+
private instances = new Map<string, SubagentInstance>();
|
|
34
|
+
private cachedConfigurations: SubagentConfiguration[] | null = null;
|
|
35
|
+
|
|
36
|
+
private workdir: string;
|
|
37
|
+
private parentToolManager: ToolManager;
|
|
38
|
+
private parentMessageManager: MessageManager;
|
|
39
|
+
private logger?: Logger;
|
|
40
|
+
private gatewayConfig: GatewayConfig;
|
|
41
|
+
private modelConfig: ModelConfig;
|
|
42
|
+
private tokenLimit: number;
|
|
43
|
+
|
|
44
|
+
constructor(options: SubagentManagerOptions) {
|
|
45
|
+
this.workdir = options.workdir;
|
|
46
|
+
this.parentToolManager = options.parentToolManager;
|
|
47
|
+
this.parentMessageManager = options.parentMessageManager;
|
|
48
|
+
this.logger = options.logger;
|
|
49
|
+
this.gatewayConfig = options.gatewayConfig;
|
|
50
|
+
this.modelConfig = options.modelConfig;
|
|
51
|
+
this.tokenLimit = options.tokenLimit;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Initialize the SubagentManager by loading and caching configurations
|
|
56
|
+
*/
|
|
57
|
+
async initialize(): Promise<void> {
|
|
58
|
+
await this.loadConfigurations();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Load all available subagent configurations and cache them
|
|
63
|
+
*/
|
|
64
|
+
async loadConfigurations(): Promise<SubagentConfiguration[]> {
|
|
65
|
+
if (this.cachedConfigurations === null) {
|
|
66
|
+
const { loadSubagentConfigurations } = await import(
|
|
67
|
+
"../utils/subagentParser.js"
|
|
68
|
+
);
|
|
69
|
+
this.cachedConfigurations = await loadSubagentConfigurations(
|
|
70
|
+
this.workdir,
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
return this.cachedConfigurations;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get cached configurations synchronously (must call loadConfigurations first)
|
|
78
|
+
*/
|
|
79
|
+
getConfigurations(): SubagentConfiguration[] {
|
|
80
|
+
if (this.cachedConfigurations === null) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"SubagentManager not initialized. Call loadConfigurations() first.",
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
return this.cachedConfigurations;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Find subagent by exact name match
|
|
90
|
+
*/
|
|
91
|
+
async findSubagent(name: string) {
|
|
92
|
+
const { findSubagentByName } = await import("../utils/subagentParser.js");
|
|
93
|
+
return findSubagentByName(name, this.workdir);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Create a new subagent instance with isolated managers
|
|
98
|
+
*/
|
|
99
|
+
async createInstance(
|
|
100
|
+
configuration: SubagentConfiguration,
|
|
101
|
+
taskDescription: string,
|
|
102
|
+
): Promise<SubagentInstance> {
|
|
103
|
+
if (
|
|
104
|
+
!this.parentToolManager ||
|
|
105
|
+
!this.gatewayConfig ||
|
|
106
|
+
!this.modelConfig ||
|
|
107
|
+
!this.tokenLimit
|
|
108
|
+
) {
|
|
109
|
+
throw new Error(
|
|
110
|
+
"SubagentManager not properly initialized - call initialize() first",
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const subagentId = randomUUID();
|
|
115
|
+
|
|
116
|
+
// Create isolated MessageManager for the subagent
|
|
117
|
+
const subagentCallbacks: MessageManagerCallbacks = {
|
|
118
|
+
// These callbacks will be handled by the parent agent
|
|
119
|
+
onMessagesChange: (messages: Message[]) => {
|
|
120
|
+
const instance = this.instances.get(subagentId);
|
|
121
|
+
if (instance) {
|
|
122
|
+
instance.messages = messages;
|
|
123
|
+
// Update parent's subagent block with latest messages
|
|
124
|
+
this.parentMessageManager.updateSubagentBlock(subagentId, {
|
|
125
|
+
messages: messages,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
const messageManager = new MessageManager({
|
|
132
|
+
callbacks: subagentCallbacks,
|
|
133
|
+
workdir: this.workdir,
|
|
134
|
+
logger: this.logger,
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Use the parent tool manager directly - tool restrictions will be handled by allowedTools parameter
|
|
138
|
+
const toolManager = this.parentToolManager;
|
|
139
|
+
|
|
140
|
+
// Determine model to use
|
|
141
|
+
const modelToUse =
|
|
142
|
+
configuration.model && configuration.model !== "inherit"
|
|
143
|
+
? configuration.model
|
|
144
|
+
: this.modelConfig.agentModel;
|
|
145
|
+
|
|
146
|
+
// Create isolated AIManager for the subagent
|
|
147
|
+
const aiManager = new AIManager({
|
|
148
|
+
messageManager,
|
|
149
|
+
toolManager,
|
|
150
|
+
logger: this.logger,
|
|
151
|
+
workdir: this.workdir,
|
|
152
|
+
systemPrompt: configuration.systemPrompt,
|
|
153
|
+
gatewayConfig: this.gatewayConfig,
|
|
154
|
+
modelConfig: {
|
|
155
|
+
...this.modelConfig,
|
|
156
|
+
agentModel: modelToUse,
|
|
157
|
+
},
|
|
158
|
+
tokenLimit: this.tokenLimit,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
const instance: SubagentInstance = {
|
|
162
|
+
subagentId,
|
|
163
|
+
configuration,
|
|
164
|
+
aiManager,
|
|
165
|
+
messageManager,
|
|
166
|
+
toolManager,
|
|
167
|
+
status: "initializing",
|
|
168
|
+
taskDescription,
|
|
169
|
+
messages: [],
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
this.instances.set(subagentId, instance);
|
|
173
|
+
|
|
174
|
+
// Create subagent block in parent message manager
|
|
175
|
+
this.parentMessageManager.addSubagentBlock(
|
|
176
|
+
subagentId,
|
|
177
|
+
configuration.name,
|
|
178
|
+
"active",
|
|
179
|
+
[],
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return instance;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Execute task using subagent instance
|
|
187
|
+
*
|
|
188
|
+
* IMPORTANT: This method automatically filters out the Task tool from allowedTools
|
|
189
|
+
* to prevent subagents from spawning other subagents (infinite recursion protection)
|
|
190
|
+
*/
|
|
191
|
+
async executeTask(
|
|
192
|
+
instance: SubagentInstance,
|
|
193
|
+
prompt: string,
|
|
194
|
+
): Promise<string> {
|
|
195
|
+
try {
|
|
196
|
+
// Set status to active and update parent
|
|
197
|
+
this.updateInstanceStatus(instance.subagentId, "active");
|
|
198
|
+
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
199
|
+
status: "active",
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Add the user's prompt as a message
|
|
203
|
+
instance.messageManager.addUserMessage(prompt);
|
|
204
|
+
|
|
205
|
+
// Create allowed tools list - always exclude Task tool to prevent subagent recursion
|
|
206
|
+
let allowedTools = instance.configuration.tools;
|
|
207
|
+
|
|
208
|
+
// Always filter out the Task tool to prevent subagents from creating sub-subagents
|
|
209
|
+
if (allowedTools) {
|
|
210
|
+
allowedTools = allowedTools.filter((tool) => tool !== "Task");
|
|
211
|
+
} else {
|
|
212
|
+
// If no tools specified, get all tools except Task
|
|
213
|
+
const allTools = instance.toolManager.list().map((tool) => tool.name);
|
|
214
|
+
allowedTools = allTools.filter((tool) => tool !== "Task");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Execute the AI request with tool restrictions
|
|
218
|
+
await instance.aiManager.sendAIMessage({
|
|
219
|
+
allowedTools,
|
|
220
|
+
model:
|
|
221
|
+
instance.configuration.model !== "inherit"
|
|
222
|
+
? instance.configuration.model
|
|
223
|
+
: undefined,
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
// Get the latest messages to extract the response
|
|
227
|
+
const messages = instance.messageManager.getMessages();
|
|
228
|
+
const lastAssistantMessage = messages
|
|
229
|
+
.filter((msg) => msg.role === "assistant")
|
|
230
|
+
.pop();
|
|
231
|
+
|
|
232
|
+
if (!lastAssistantMessage) {
|
|
233
|
+
throw new Error("No response from subagent");
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Extract text content from the last assistant message
|
|
237
|
+
const textBlocks = lastAssistantMessage.blocks.filter(
|
|
238
|
+
(block) => block.type === "text",
|
|
239
|
+
);
|
|
240
|
+
const response = textBlocks.map((block) => block.content).join("\n");
|
|
241
|
+
|
|
242
|
+
// Update status to completed and update parent with final messages
|
|
243
|
+
this.updateInstanceStatus(instance.subagentId, "completed");
|
|
244
|
+
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
245
|
+
status: "completed",
|
|
246
|
+
messages: messages,
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
return response || "Task completed with no text response";
|
|
250
|
+
} catch (error) {
|
|
251
|
+
this.updateInstanceStatus(instance.subagentId, "error");
|
|
252
|
+
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
253
|
+
status: "error",
|
|
254
|
+
});
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Get instance by subagent ID
|
|
261
|
+
*/
|
|
262
|
+
getInstance(subagentId: string): SubagentInstance | null {
|
|
263
|
+
return this.instances.get(subagentId) || null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Update instance status
|
|
268
|
+
*/
|
|
269
|
+
updateInstanceStatus(
|
|
270
|
+
subagentId: string,
|
|
271
|
+
status: SubagentInstance["status"],
|
|
272
|
+
): void {
|
|
273
|
+
const instance = this.instances.get(subagentId);
|
|
274
|
+
if (instance) {
|
|
275
|
+
instance.status = status;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Add message to instance
|
|
281
|
+
*/
|
|
282
|
+
addMessageToInstance(subagentId: string, message: Message): void {
|
|
283
|
+
const instance = this.instances.get(subagentId);
|
|
284
|
+
if (instance) {
|
|
285
|
+
instance.messages.push(message);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Abort a running subagent instance
|
|
291
|
+
*/
|
|
292
|
+
abortInstance(subagentId: string): boolean {
|
|
293
|
+
const instance = this.instances.get(subagentId);
|
|
294
|
+
if (!instance) {
|
|
295
|
+
return false;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Only abort active or initializing instances
|
|
299
|
+
if (instance.status !== "active" && instance.status !== "initializing") {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
try {
|
|
304
|
+
// Abort the AI manager operations
|
|
305
|
+
instance.aiManager.abortAIMessage();
|
|
306
|
+
|
|
307
|
+
// Update status
|
|
308
|
+
this.updateInstanceStatus(subagentId, "aborted");
|
|
309
|
+
this.parentMessageManager.updateSubagentBlock(subagentId, {
|
|
310
|
+
status: "aborted",
|
|
311
|
+
messages: instance.messages,
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
this.logger?.info(`Aborted subagent instance: ${subagentId}`);
|
|
315
|
+
return true;
|
|
316
|
+
} catch (error) {
|
|
317
|
+
this.logger?.error(
|
|
318
|
+
`Failed to abort subagent instance ${subagentId}:`,
|
|
319
|
+
error,
|
|
320
|
+
);
|
|
321
|
+
return false;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Abort all active subagent instances
|
|
327
|
+
*/
|
|
328
|
+
abortAllInstances(): void {
|
|
329
|
+
const activeInstances = this.getActiveInstances();
|
|
330
|
+
for (const instance of activeInstances) {
|
|
331
|
+
this.abortInstance(instance.subagentId);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Clean up completed, errored, or aborted instances
|
|
337
|
+
*/
|
|
338
|
+
cleanupInstance(subagentId: string): void {
|
|
339
|
+
const instance = this.instances.get(subagentId);
|
|
340
|
+
if (
|
|
341
|
+
instance &&
|
|
342
|
+
(instance.status === "completed" ||
|
|
343
|
+
instance.status === "error" ||
|
|
344
|
+
instance.status === "aborted")
|
|
345
|
+
) {
|
|
346
|
+
this.instances.delete(subagentId);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/**
|
|
351
|
+
* Get all active instances
|
|
352
|
+
*/
|
|
353
|
+
getActiveInstances(): SubagentInstance[] {
|
|
354
|
+
return Array.from(this.instances.values()).filter(
|
|
355
|
+
(instance) =>
|
|
356
|
+
instance.status === "active" || instance.status === "initializing",
|
|
357
|
+
);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Clean up all instances (for session end)
|
|
362
|
+
*/
|
|
363
|
+
cleanup(): void {
|
|
364
|
+
// Abort all active instances before cleanup
|
|
365
|
+
this.abortAllInstances();
|
|
366
|
+
this.instances.clear();
|
|
367
|
+
}
|
|
368
|
+
}
|
|
@@ -9,10 +9,14 @@ import { globTool } from "../tools/globTool.js";
|
|
|
9
9
|
import { grepTool } from "../tools/grepTool.js";
|
|
10
10
|
import { lsTool } from "../tools/lsTool.js";
|
|
11
11
|
import { readTool } from "../tools/readTool.js";
|
|
12
|
-
import {
|
|
12
|
+
import { todoWriteTool } from "../tools/todoWriteTool.js";
|
|
13
|
+
import { createTaskTool } from "../tools/taskTool.js";
|
|
14
|
+
import { createSkillTool } from "../tools/skillTool.js";
|
|
13
15
|
import { McpManager } from "./mcpManager.js";
|
|
14
16
|
import { ChatCompletionFunctionTool } from "openai/resources.js";
|
|
15
17
|
import type { Logger } from "../types.js";
|
|
18
|
+
import type { SubagentManager } from "./subagentManager.js";
|
|
19
|
+
import type { SkillManager } from "./skillManager.js";
|
|
16
20
|
|
|
17
21
|
export interface ToolManagerOptions {
|
|
18
22
|
mcpManager: McpManager;
|
|
@@ -30,12 +34,42 @@ class ToolManager {
|
|
|
30
34
|
constructor(options: ToolManagerOptions) {
|
|
31
35
|
this.mcpManager = options.mcpManager;
|
|
32
36
|
this.logger = options.logger;
|
|
37
|
+
}
|
|
33
38
|
|
|
34
|
-
|
|
35
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Register a new tool
|
|
41
|
+
*/
|
|
42
|
+
public register(tool: ToolPlugin): void {
|
|
43
|
+
this.tools.set(tool.name, tool);
|
|
36
44
|
}
|
|
37
45
|
|
|
38
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Initialize built-in tools. Can be called with dependencies for tools that require them.
|
|
48
|
+
*
|
|
49
|
+
* This method can be called multiple times safely. When called without dependencies,
|
|
50
|
+
* it registers basic tools (Bash, Read, Write, TodoWrite, etc.). When called with
|
|
51
|
+
* dependencies, it also registers tools that require managers (Task, Skill).
|
|
52
|
+
*
|
|
53
|
+
* @param deps Optional dependencies for advanced tools
|
|
54
|
+
* @param deps.subagentManager SubagentManager instance for Task tool
|
|
55
|
+
* @param deps.skillManager SkillManager instance for Skill tool
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```typescript
|
|
59
|
+
* // Initialize basic tools only
|
|
60
|
+
* toolManager.initializeBuiltInTools();
|
|
61
|
+
*
|
|
62
|
+
* // Initialize all tools including those requiring dependencies
|
|
63
|
+
* toolManager.initializeBuiltInTools({
|
|
64
|
+
* subagentManager: mySubagentManager,
|
|
65
|
+
* skillManager: mySkillManager
|
|
66
|
+
* });
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
public initializeBuiltInTools(deps?: {
|
|
70
|
+
subagentManager?: SubagentManager;
|
|
71
|
+
skillManager?: SkillManager;
|
|
72
|
+
}): void {
|
|
39
73
|
const builtInTools = [
|
|
40
74
|
bashTool,
|
|
41
75
|
bashOutputTool,
|
|
@@ -48,12 +82,23 @@ class ToolManager {
|
|
|
48
82
|
grepTool,
|
|
49
83
|
lsTool,
|
|
50
84
|
readTool,
|
|
51
|
-
|
|
85
|
+
todoWriteTool,
|
|
52
86
|
];
|
|
53
87
|
|
|
54
88
|
for (const tool of builtInTools) {
|
|
55
89
|
this.tools.set(tool.name, tool);
|
|
56
90
|
}
|
|
91
|
+
|
|
92
|
+
// Register tools that require dependencies
|
|
93
|
+
if (deps?.subagentManager) {
|
|
94
|
+
const taskTool = createTaskTool(deps.subagentManager);
|
|
95
|
+
this.tools.set(taskTool.name, taskTool);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (deps?.skillManager) {
|
|
99
|
+
const skillTool = createSkillTool(deps.skillManager);
|
|
100
|
+
this.tools.set(skillTool.name, skillTool);
|
|
101
|
+
}
|
|
57
102
|
}
|
|
58
103
|
|
|
59
104
|
async execute(
|