wave-agent-sdk 0.0.2 → 0.0.4
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 +5 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +48 -4
- 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.map +1 -1
- package/dist/managers/aiManager.js +4 -7
- 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.map +1 -1
- package/dist/services/aiService.js +40 -14
- package/dist/services/memory.js +2 -2
- 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 +8 -1
- package/dist/types.d.ts.map +1 -1
- 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 +1 -1
- package/src/agent.ts +55 -5
- package/src/index.ts +0 -1
- package/src/managers/aiManager.ts +5 -8
- 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 +44 -16
- package/src/services/memory.ts +2 -2
- 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 +10 -1
- package/src/utils/fileFormat.ts +40 -0
- package/src/utils/messageOperations.ts +80 -0
- package/src/utils/subagentParser.ts +223 -0
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, statSync } from "fs";
|
|
2
|
+
import { join, extname } from "path";
|
|
3
|
+
/**
|
|
4
|
+
* Parse YAML frontmatter from markdown file content
|
|
5
|
+
*/
|
|
6
|
+
function parseFrontmatter(content) {
|
|
7
|
+
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
8
|
+
const match = content.match(frontmatterRegex);
|
|
9
|
+
if (!match) {
|
|
10
|
+
return { frontmatter: {}, body: content.trim() };
|
|
11
|
+
}
|
|
12
|
+
const [, yamlContent, body] = match;
|
|
13
|
+
const frontmatter = parseYamlFrontmatter(yamlContent);
|
|
14
|
+
return { frontmatter, body: body.trim() };
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Simple YAML frontmatter parser for subagent files
|
|
18
|
+
*/
|
|
19
|
+
function parseYamlFrontmatter(yamlContent) {
|
|
20
|
+
const frontmatter = {};
|
|
21
|
+
try {
|
|
22
|
+
const lines = yamlContent.split("\n");
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
const trimmed = line.trim();
|
|
25
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
26
|
+
continue;
|
|
27
|
+
const colonIndex = trimmed.indexOf(":");
|
|
28
|
+
if (colonIndex === -1)
|
|
29
|
+
continue;
|
|
30
|
+
const key = trimmed.substring(0, colonIndex).trim();
|
|
31
|
+
const value = trimmed
|
|
32
|
+
.substring(colonIndex + 1)
|
|
33
|
+
.trim()
|
|
34
|
+
.replace(/^["']|["']$/g, "");
|
|
35
|
+
if (key && value) {
|
|
36
|
+
// Handle array values for tools
|
|
37
|
+
if (key === "tools" && value) {
|
|
38
|
+
let arrayValue = value;
|
|
39
|
+
if (arrayValue.startsWith("[") && arrayValue.endsWith("]")) {
|
|
40
|
+
arrayValue = arrayValue.slice(1, -1);
|
|
41
|
+
}
|
|
42
|
+
frontmatter[key] = arrayValue
|
|
43
|
+
.split(",")
|
|
44
|
+
.map((s) => s.trim())
|
|
45
|
+
.filter(Boolean);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
if (key === "name" || key === "description" || key === "model") {
|
|
49
|
+
frontmatter[key] = value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
// Return empty frontmatter on parse error - validation will catch missing fields
|
|
57
|
+
}
|
|
58
|
+
return frontmatter;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Validate subagent configuration
|
|
62
|
+
*/
|
|
63
|
+
function validateConfiguration(config, filePath) {
|
|
64
|
+
if (!config.name) {
|
|
65
|
+
throw new Error(`Missing required field 'name' in ${filePath}`);
|
|
66
|
+
}
|
|
67
|
+
if (!config.description) {
|
|
68
|
+
throw new Error(`Missing required field 'description' in ${filePath}`);
|
|
69
|
+
}
|
|
70
|
+
// Validate name pattern
|
|
71
|
+
const namePattern = /^[a-z][a-z0-9-]*$/;
|
|
72
|
+
if (!namePattern.test(config.name)) {
|
|
73
|
+
throw new Error(`Invalid subagent name '${config.name}' in ${filePath}. Must start with a letter and contain only lowercase letters, numbers, and hyphens.`);
|
|
74
|
+
}
|
|
75
|
+
// Validate model if specified - allow any non-empty string
|
|
76
|
+
if (config.model && typeof config.model !== "string") {
|
|
77
|
+
throw new Error(`Invalid model '${config.model}' in ${filePath}. Must be a string.`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Parse a single subagent markdown file
|
|
82
|
+
*/
|
|
83
|
+
function parseSubagentFile(filePath, scope) {
|
|
84
|
+
try {
|
|
85
|
+
const content = readFileSync(filePath, "utf-8");
|
|
86
|
+
const { frontmatter, body } = parseFrontmatter(content);
|
|
87
|
+
validateConfiguration(frontmatter, filePath);
|
|
88
|
+
if (!body.trim()) {
|
|
89
|
+
throw new Error(`Empty system prompt in ${filePath}`);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
name: frontmatter.name,
|
|
93
|
+
description: frontmatter.description,
|
|
94
|
+
tools: frontmatter.tools,
|
|
95
|
+
model: frontmatter.model,
|
|
96
|
+
systemPrompt: body,
|
|
97
|
+
filePath,
|
|
98
|
+
scope,
|
|
99
|
+
priority: scope === "project" ? 1 : 2,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
throw new Error(`Failed to parse subagent file ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Scan directory for subagent files
|
|
108
|
+
*/
|
|
109
|
+
function scanSubagentDirectory(dirPath, scope) {
|
|
110
|
+
const configurations = [];
|
|
111
|
+
try {
|
|
112
|
+
const entries = readdirSync(dirPath);
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
const fullPath = join(dirPath, entry);
|
|
115
|
+
const stat = statSync(fullPath);
|
|
116
|
+
if (stat.isFile() && extname(entry) === ".md") {
|
|
117
|
+
try {
|
|
118
|
+
const config = parseSubagentFile(fullPath, scope);
|
|
119
|
+
configurations.push(config);
|
|
120
|
+
}
|
|
121
|
+
catch (parseError) {
|
|
122
|
+
// Log error but continue with other files
|
|
123
|
+
console.warn(`Warning: ${parseError instanceof Error ? parseError.message : String(parseError)}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Directory doesn't exist or can't be read - this is OK
|
|
130
|
+
}
|
|
131
|
+
return configurations;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Load all subagent configurations from project and user directories
|
|
135
|
+
*/
|
|
136
|
+
export async function loadSubagentConfigurations(workdir) {
|
|
137
|
+
const projectDir = join(workdir, ".wave", "agents");
|
|
138
|
+
const userDir = join(process.env.HOME || "~", ".wave", "agents");
|
|
139
|
+
const projectConfigs = scanSubagentDirectory(projectDir, "project");
|
|
140
|
+
const userConfigs = scanSubagentDirectory(userDir, "user");
|
|
141
|
+
// Merge configurations, with project configs taking precedence
|
|
142
|
+
const configMap = new Map();
|
|
143
|
+
// Process in reverse priority order (user first, then project)
|
|
144
|
+
for (const config of [...userConfigs, ...projectConfigs]) {
|
|
145
|
+
configMap.set(config.name, config);
|
|
146
|
+
}
|
|
147
|
+
return Array.from(configMap.values()).sort((a, b) => {
|
|
148
|
+
if (a.priority !== b.priority)
|
|
149
|
+
return a.priority - b.priority;
|
|
150
|
+
return a.name.localeCompare(b.name);
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Find subagent by exact name match
|
|
155
|
+
*/
|
|
156
|
+
export async function findSubagentByName(name, workdir) {
|
|
157
|
+
const configurations = await loadSubagentConfigurations(workdir);
|
|
158
|
+
return configurations.find((config) => config.name === name) || null;
|
|
159
|
+
}
|
package/package.json
CHANGED
package/src/agent.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
} from "./managers/messageManager.js";
|
|
5
5
|
import { AIManager } from "./managers/aiManager.js";
|
|
6
6
|
import { ToolManager } from "./managers/toolManager.js";
|
|
7
|
+
import { SubagentManager } from "./managers/subagentManager.js";
|
|
7
8
|
import * as memory from "./services/memory.js";
|
|
8
9
|
import { McpManager, type McpManagerCallbacks } from "./managers/mcpManager.js";
|
|
9
10
|
import { BashManager } from "./managers/bashManager.js";
|
|
@@ -23,6 +24,7 @@ import type {
|
|
|
23
24
|
import { HookManager } from "./hooks/index.js";
|
|
24
25
|
import { configResolver } from "./utils/configResolver.js";
|
|
25
26
|
import { configValidator } from "./utils/configValidator.js";
|
|
27
|
+
import { SkillManager } from "./managers/skillManager.js";
|
|
26
28
|
|
|
27
29
|
/**
|
|
28
30
|
* Configuration options for Agent instances
|
|
@@ -59,13 +61,13 @@ export interface AgentCallbacks
|
|
|
59
61
|
export class Agent {
|
|
60
62
|
private messageManager: MessageManager;
|
|
61
63
|
private aiManager: AIManager;
|
|
62
|
-
private callbacks: AgentCallbacks;
|
|
63
64
|
|
|
64
65
|
private bashManager: BashManager | null = null;
|
|
65
66
|
private backgroundBashManager: BackgroundBashManager;
|
|
66
67
|
private logger?: Logger; // Add optional logger property
|
|
67
68
|
private toolManager: ToolManager; // Add tool registry instance
|
|
68
69
|
private mcpManager: McpManager; // Add MCP manager instance
|
|
70
|
+
private subagentManager: SubagentManager; // Add subagent manager instance
|
|
69
71
|
private slashCommandManager: SlashCommandManager; // Add slash command manager instance
|
|
70
72
|
private hookManager: HookManager; // Add hooks manager instance
|
|
71
73
|
private workdir: string; // Working directory
|
|
@@ -106,7 +108,6 @@ export class Agent {
|
|
|
106
108
|
modelConfig.fastModel,
|
|
107
109
|
);
|
|
108
110
|
|
|
109
|
-
this.callbacks = callbacks;
|
|
110
111
|
this.logger = logger; // Save the passed logger
|
|
111
112
|
this.workdir = workdir || process.cwd(); // Set working directory, default to current working directory
|
|
112
113
|
this.systemPrompt = systemPrompt; // Save custom system prompt
|
|
@@ -121,7 +122,11 @@ export class Agent {
|
|
|
121
122
|
workdir: this.workdir,
|
|
122
123
|
});
|
|
123
124
|
this.mcpManager = new McpManager({ callbacks, logger: this.logger }); // Initialize MCP manager
|
|
124
|
-
this.toolManager = new ToolManager({
|
|
125
|
+
this.toolManager = new ToolManager({
|
|
126
|
+
mcpManager: this.mcpManager,
|
|
127
|
+
logger: this.logger,
|
|
128
|
+
}); // Initialize tool registry, pass MCP manager
|
|
129
|
+
|
|
125
130
|
this.hookManager = new HookManager(
|
|
126
131
|
this.workdir,
|
|
127
132
|
undefined,
|
|
@@ -136,6 +141,18 @@ export class Agent {
|
|
|
136
141
|
logger: this.logger,
|
|
137
142
|
});
|
|
138
143
|
|
|
144
|
+
// Initialize subagent manager with all dependencies in constructor
|
|
145
|
+
// IMPORTANT: Must be initialized AFTER MessageManager
|
|
146
|
+
this.subagentManager = new SubagentManager({
|
|
147
|
+
workdir: this.workdir,
|
|
148
|
+
parentToolManager: this.toolManager,
|
|
149
|
+
parentMessageManager: this.messageManager,
|
|
150
|
+
logger: this.logger,
|
|
151
|
+
gatewayConfig,
|
|
152
|
+
modelConfig,
|
|
153
|
+
tokenLimit,
|
|
154
|
+
});
|
|
155
|
+
|
|
139
156
|
// Initialize AI manager with resolved configuration
|
|
140
157
|
this.aiManager = new AIManager({
|
|
141
158
|
messageManager: this.messageManager,
|
|
@@ -242,6 +259,25 @@ export class Agent {
|
|
|
242
259
|
continueLastSession?: boolean;
|
|
243
260
|
messages?: Message[];
|
|
244
261
|
}): Promise<void> {
|
|
262
|
+
// Initialize managers first
|
|
263
|
+
try {
|
|
264
|
+
// Initialize SkillManager
|
|
265
|
+
const skillManager = new SkillManager({ logger: this.logger });
|
|
266
|
+
await skillManager.initialize();
|
|
267
|
+
|
|
268
|
+
// Initialize SubagentManager (load and cache configurations)
|
|
269
|
+
await this.subagentManager.initialize();
|
|
270
|
+
|
|
271
|
+
// Initialize built-in tools with dependencies
|
|
272
|
+
this.toolManager.initializeBuiltInTools({
|
|
273
|
+
subagentManager: this.subagentManager,
|
|
274
|
+
skillManager: skillManager,
|
|
275
|
+
});
|
|
276
|
+
} catch (error) {
|
|
277
|
+
this.logger?.error("Failed to initialize managers and tools:", error);
|
|
278
|
+
// Don't throw error to prevent app startup failure
|
|
279
|
+
}
|
|
280
|
+
|
|
245
281
|
// Initialize MCP servers with auto-connect
|
|
246
282
|
try {
|
|
247
283
|
await this.mcpManager.initialize(this.workdir, true);
|
|
@@ -295,6 +331,7 @@ export class Agent {
|
|
|
295
331
|
this.abortAIMessage();
|
|
296
332
|
this.abortBashCommand();
|
|
297
333
|
this.abortSlashCommand();
|
|
334
|
+
this.abortSubagents();
|
|
298
335
|
}
|
|
299
336
|
|
|
300
337
|
/** Add to input history */
|
|
@@ -312,16 +349,29 @@ export class Agent {
|
|
|
312
349
|
this.slashCommandManager.abortCurrentCommand();
|
|
313
350
|
}
|
|
314
351
|
|
|
352
|
+
/** Interrupt all subagent execution */
|
|
353
|
+
public abortSubagents(): void {
|
|
354
|
+
this.subagentManager.abortAllInstances();
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** Interrupt specific subagent execution */
|
|
358
|
+
public abortSubagent(subagentId: string): boolean {
|
|
359
|
+
return this.subagentManager.abortInstance(subagentId);
|
|
360
|
+
}
|
|
361
|
+
|
|
315
362
|
/** Destroy managers, clean up resources */
|
|
316
363
|
public async destroy(): Promise<void> {
|
|
317
364
|
this.messageManager.saveSession();
|
|
318
365
|
this.abortAIMessage();
|
|
319
366
|
this.abortBashCommand();
|
|
320
367
|
this.abortSlashCommand();
|
|
368
|
+
this.abortSubagents();
|
|
321
369
|
// Cleanup background bash manager
|
|
322
370
|
this.backgroundBashManager.cleanup();
|
|
323
371
|
// Cleanup MCP connections
|
|
324
372
|
await this.mcpManager.cleanup();
|
|
373
|
+
// Cleanup subagent manager
|
|
374
|
+
this.subagentManager.cleanup();
|
|
325
375
|
}
|
|
326
376
|
|
|
327
377
|
public async sendMessage(
|
|
@@ -406,7 +456,7 @@ export class Agent {
|
|
|
406
456
|
// Add successful MemoryBlock to the last assistant message
|
|
407
457
|
const memoryText = message.substring(1).trim();
|
|
408
458
|
const typeLabel = type === "project" ? "Project Memory" : "User Memory";
|
|
409
|
-
const storagePath = type === "project" ? "
|
|
459
|
+
const storagePath = type === "project" ? "AGENTS.md" : "user-memory.md";
|
|
410
460
|
|
|
411
461
|
this.messageManager.addMemoryBlock(
|
|
412
462
|
`${typeLabel}: ${memoryText}`,
|
|
@@ -417,7 +467,7 @@ export class Agent {
|
|
|
417
467
|
} catch (error) {
|
|
418
468
|
// Add failed MemoryBlock to the last assistant message
|
|
419
469
|
const typeLabel = type === "project" ? "Project Memory" : "User Memory";
|
|
420
|
-
const storagePath = type === "project" ? "
|
|
470
|
+
const storagePath = type === "project" ? "AGENTS.md" : "user-memory.md";
|
|
421
471
|
|
|
422
472
|
this.messageManager.addMemoryBlock(
|
|
423
473
|
`${typeLabel} add failed: ${
|
package/src/index.ts
CHANGED
|
@@ -14,7 +14,6 @@ export * from "./utils/mcpUtils.js";
|
|
|
14
14
|
export * from "./utils/messageOperations.js";
|
|
15
15
|
export * from "./utils/path.js";
|
|
16
16
|
export * from "./utils/stringUtils.js";
|
|
17
|
-
export * from "./utils/markdownParser.js";
|
|
18
17
|
export * from "./utils/customCommands.js";
|
|
19
18
|
|
|
20
19
|
// Export hooks system
|
|
@@ -444,14 +444,11 @@ export class AIManager {
|
|
|
444
444
|
if (recursionDepth === 0) {
|
|
445
445
|
this.setIsLoading(false);
|
|
446
446
|
|
|
447
|
-
// Save session
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
// Execute Stop hooks when AI response cycle completes
|
|
453
|
-
await this.executeStopHooks();
|
|
454
|
-
})();
|
|
447
|
+
// Save session before executing Stop hooks
|
|
448
|
+
await this.messageManager.saveSession();
|
|
449
|
+
|
|
450
|
+
// Execute Stop hooks when AI response cycle completes
|
|
451
|
+
await this.executeStopHooks();
|
|
455
452
|
}
|
|
456
453
|
}
|
|
457
454
|
}
|
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
addCommandOutputMessage,
|
|
11
11
|
updateCommandOutputInMessage,
|
|
12
12
|
completeCommandInMessage,
|
|
13
|
+
addSubagentBlockToMessage,
|
|
14
|
+
updateSubagentBlockInMessage,
|
|
15
|
+
type AddSubagentBlockParams,
|
|
16
|
+
type UpdateSubagentBlockParams,
|
|
13
17
|
type AgentToolBlockUpdateParams,
|
|
14
18
|
} from "../utils/messageOperations.js";
|
|
15
19
|
import type { Logger, Message } from "../types.js";
|
|
@@ -48,10 +52,19 @@ export interface MessageManagerCallbacks {
|
|
|
48
52
|
type: "project" | "user",
|
|
49
53
|
storagePath: string,
|
|
50
54
|
) => void;
|
|
55
|
+
// Custom command callback
|
|
56
|
+
onCustomCommandAdded?: (
|
|
57
|
+
commandName: string,
|
|
58
|
+
content: string,
|
|
59
|
+
originalInput?: string,
|
|
60
|
+
) => void;
|
|
51
61
|
// Bash command callback
|
|
52
62
|
onAddCommandOutputMessage?: (command: string) => void;
|
|
53
63
|
onUpdateCommandOutputMessage?: (command: string, output: string) => void;
|
|
54
64
|
onCompleteCommandMessage?: (command: string, exitCode: number) => void;
|
|
65
|
+
// Subagent callbacks
|
|
66
|
+
onSubAgentBlockAdded?: (subagentId: string) => void;
|
|
67
|
+
onSubAgentBlockUpdated?: (subagentId: string, messages: Message[]) => void;
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
export interface MessageManagerOptions {
|
|
@@ -271,7 +284,7 @@ export class MessageManager {
|
|
|
271
284
|
},
|
|
272
285
|
});
|
|
273
286
|
this.setMessages(newMessages);
|
|
274
|
-
this.callbacks.
|
|
287
|
+
this.callbacks.onCustomCommandAdded?.(commandName, content, originalInput);
|
|
275
288
|
}
|
|
276
289
|
|
|
277
290
|
public addAssistantMessage(
|
|
@@ -412,4 +425,45 @@ export class MessageManager {
|
|
|
412
425
|
this.setMessages(updatedMessages);
|
|
413
426
|
this.callbacks.onCompleteCommandMessage?.(command, exitCode);
|
|
414
427
|
}
|
|
428
|
+
|
|
429
|
+
// Subagent block methods
|
|
430
|
+
public addSubagentBlock(
|
|
431
|
+
subagentId: string,
|
|
432
|
+
subagentName: string,
|
|
433
|
+
status: "active" | "completed" | "error" = "active",
|
|
434
|
+
subagentMessages: Message[] = [],
|
|
435
|
+
): void {
|
|
436
|
+
const params: AddSubagentBlockParams = {
|
|
437
|
+
messages: this.messages,
|
|
438
|
+
subagentId,
|
|
439
|
+
subagentName,
|
|
440
|
+
status,
|
|
441
|
+
subagentMessages,
|
|
442
|
+
};
|
|
443
|
+
const updatedMessages = addSubagentBlockToMessage(params);
|
|
444
|
+
this.setMessages(updatedMessages);
|
|
445
|
+
this.callbacks.onSubAgentBlockAdded?.(params.subagentId);
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
public updateSubagentBlock(
|
|
449
|
+
subagentId: string,
|
|
450
|
+
updates: Partial<{
|
|
451
|
+
status: "active" | "completed" | "error" | "aborted";
|
|
452
|
+
messages: Message[];
|
|
453
|
+
}>,
|
|
454
|
+
): void {
|
|
455
|
+
const updatedMessages = updateSubagentBlockInMessage(
|
|
456
|
+
this.messages,
|
|
457
|
+
subagentId,
|
|
458
|
+
updates,
|
|
459
|
+
);
|
|
460
|
+
this.setMessages(updatedMessages);
|
|
461
|
+
const params: UpdateSubagentBlockParams = {
|
|
462
|
+
messages: this.messages,
|
|
463
|
+
subagentId,
|
|
464
|
+
status: updates.status || "active",
|
|
465
|
+
subagentMessages: updates.messages || [],
|
|
466
|
+
};
|
|
467
|
+
this.callbacks.onSubAgentBlockUpdated?.(params.subagentId, params.messages);
|
|
468
|
+
}
|
|
415
469
|
}
|
|
@@ -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
|
*/
|