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
|
@@ -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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-agent-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "SDK for building AI-powered development tools and agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -18,18 +18,6 @@
|
|
|
18
18
|
"src",
|
|
19
19
|
"README.md"
|
|
20
20
|
],
|
|
21
|
-
"scripts": {
|
|
22
|
-
"build": "rimraf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
23
|
-
"type-check": "tsc --noEmit --incremental",
|
|
24
|
-
"dev": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
|
|
25
|
-
"test": "vitest run",
|
|
26
|
-
"lint": "eslint --cache",
|
|
27
|
-
"format": "prettier --write .",
|
|
28
|
-
"release:patch": "pnpm version patch && npm publish",
|
|
29
|
-
"release:minor": "pnpm version minor && npm publish",
|
|
30
|
-
"release:major": "pnpm version major && npm publish",
|
|
31
|
-
"prepublishOnly": "npm run build"
|
|
32
|
-
},
|
|
33
21
|
"dependencies": {
|
|
34
22
|
"@modelcontextprotocol/sdk": "^1.18.2",
|
|
35
23
|
"@vscode/ripgrep": "^1.15.14",
|
|
@@ -47,5 +35,13 @@
|
|
|
47
35
|
"engines": {
|
|
48
36
|
"node": ">=16.0.0"
|
|
49
37
|
},
|
|
50
|
-
"license": "MIT"
|
|
51
|
-
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "rimraf dist && tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json",
|
|
41
|
+
"type-check": "tsc --noEmit --incremental",
|
|
42
|
+
"dev": "tsc -p tsconfig.build.json --watch & tsc-alias -p tsconfig.build.json --watch",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"lint": "eslint --cache",
|
|
45
|
+
"format": "prettier --write ."
|
|
46
|
+
}
|
|
47
|
+
}
|
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";
|
|
@@ -13,10 +14,33 @@ import {
|
|
|
13
14
|
} from "./managers/backgroundBashManager.js";
|
|
14
15
|
import { SlashCommandManager } from "./managers/slashCommandManager.js";
|
|
15
16
|
import type { SlashCommand, CustomSlashCommand } from "./types.js";
|
|
16
|
-
import type {
|
|
17
|
+
import type {
|
|
18
|
+
Message,
|
|
19
|
+
Logger,
|
|
20
|
+
McpServerStatus,
|
|
21
|
+
GatewayConfig,
|
|
22
|
+
ModelConfig,
|
|
23
|
+
} from "./types.js";
|
|
17
24
|
import { HookManager } from "./hooks/index.js";
|
|
18
|
-
|
|
25
|
+
import { configResolver } from "./utils/configResolver.js";
|
|
26
|
+
import { configValidator } from "./utils/configValidator.js";
|
|
27
|
+
import { SkillManager } from "./managers/skillManager.js";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Configuration options for Agent instances
|
|
31
|
+
*
|
|
32
|
+
* IMPORTANT: This interface is used by both Agent constructor and Agent.create()
|
|
33
|
+
* Any changes to this interface must be compatible with both methods.
|
|
34
|
+
*/
|
|
19
35
|
export interface AgentOptions {
|
|
36
|
+
// Optional configuration with environment fallbacks
|
|
37
|
+
apiKey?: string;
|
|
38
|
+
baseURL?: string;
|
|
39
|
+
agentModel?: string;
|
|
40
|
+
fastModel?: string;
|
|
41
|
+
tokenLimit?: number;
|
|
42
|
+
|
|
43
|
+
// Existing options (preserved)
|
|
20
44
|
callbacks?: AgentCallbacks;
|
|
21
45
|
restoreSessionId?: string;
|
|
22
46
|
continueLastSession?: boolean;
|
|
@@ -37,32 +61,72 @@ export interface AgentCallbacks
|
|
|
37
61
|
export class Agent {
|
|
38
62
|
private messageManager: MessageManager;
|
|
39
63
|
private aiManager: AIManager;
|
|
40
|
-
private callbacks: AgentCallbacks;
|
|
41
64
|
|
|
42
65
|
private bashManager: BashManager | null = null;
|
|
43
66
|
private backgroundBashManager: BackgroundBashManager;
|
|
44
67
|
private logger?: Logger; // Add optional logger property
|
|
45
68
|
private toolManager: ToolManager; // Add tool registry instance
|
|
46
69
|
private mcpManager: McpManager; // Add MCP manager instance
|
|
70
|
+
private subagentManager: SubagentManager; // Add subagent manager instance
|
|
47
71
|
private slashCommandManager: SlashCommandManager; // Add slash command manager instance
|
|
48
72
|
private hookManager: HookManager; // Add hooks manager instance
|
|
49
73
|
private workdir: string; // Working directory
|
|
50
74
|
private systemPrompt?: string; // Custom system prompt
|
|
51
75
|
|
|
52
|
-
//
|
|
53
|
-
private
|
|
76
|
+
// Configuration properties
|
|
77
|
+
private gatewayConfig: GatewayConfig;
|
|
78
|
+
private modelConfig: ModelConfig;
|
|
79
|
+
private tokenLimit: number;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Agent constructor - handles configuration resolution and validation
|
|
83
|
+
*
|
|
84
|
+
* IMPORTANT: Keep this constructor's signature exactly the same as Agent.create()
|
|
85
|
+
* to maintain API consistency. Both methods should accept the same AgentOptions.
|
|
86
|
+
*
|
|
87
|
+
* @param options - Configuration options for the Agent instance
|
|
88
|
+
*/
|
|
89
|
+
constructor(options: AgentOptions) {
|
|
54
90
|
const { callbacks = {}, logger, workdir, systemPrompt } = options;
|
|
55
91
|
|
|
56
|
-
|
|
92
|
+
// Resolve configuration from constructor args and environment variables
|
|
93
|
+
const gatewayConfig = configResolver.resolveGatewayConfig(
|
|
94
|
+
options.apiKey,
|
|
95
|
+
options.baseURL,
|
|
96
|
+
);
|
|
97
|
+
const modelConfig = configResolver.resolveModelConfig(
|
|
98
|
+
options.agentModel,
|
|
99
|
+
options.fastModel,
|
|
100
|
+
);
|
|
101
|
+
const tokenLimit = configResolver.resolveTokenLimit(options.tokenLimit);
|
|
102
|
+
|
|
103
|
+
// Validate resolved configuration
|
|
104
|
+
configValidator.validateGatewayConfig(gatewayConfig);
|
|
105
|
+
configValidator.validateTokenLimit(tokenLimit);
|
|
106
|
+
configValidator.validateModelConfig(
|
|
107
|
+
modelConfig.agentModel,
|
|
108
|
+
modelConfig.fastModel,
|
|
109
|
+
);
|
|
110
|
+
|
|
57
111
|
this.logger = logger; // Save the passed logger
|
|
58
112
|
this.workdir = workdir || process.cwd(); // Set working directory, default to current working directory
|
|
59
113
|
this.systemPrompt = systemPrompt; // Save custom system prompt
|
|
114
|
+
|
|
115
|
+
// Store resolved configuration
|
|
116
|
+
this.gatewayConfig = gatewayConfig;
|
|
117
|
+
this.modelConfig = modelConfig;
|
|
118
|
+
this.tokenLimit = tokenLimit;
|
|
119
|
+
|
|
60
120
|
this.backgroundBashManager = new BackgroundBashManager({
|
|
61
121
|
callbacks,
|
|
62
122
|
workdir: this.workdir,
|
|
63
123
|
});
|
|
64
124
|
this.mcpManager = new McpManager({ callbacks, logger: this.logger }); // Initialize MCP manager
|
|
65
|
-
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
|
+
|
|
66
130
|
this.hookManager = new HookManager(
|
|
67
131
|
this.workdir,
|
|
68
132
|
undefined,
|
|
@@ -77,7 +141,19 @@ export class Agent {
|
|
|
77
141
|
logger: this.logger,
|
|
78
142
|
});
|
|
79
143
|
|
|
80
|
-
// Initialize
|
|
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
|
+
|
|
156
|
+
// Initialize AI manager with resolved configuration
|
|
81
157
|
this.aiManager = new AIManager({
|
|
82
158
|
messageManager: this.messageManager,
|
|
83
159
|
toolManager: this.toolManager,
|
|
@@ -87,6 +163,9 @@ export class Agent {
|
|
|
87
163
|
callbacks,
|
|
88
164
|
workdir: this.workdir,
|
|
89
165
|
systemPrompt: this.systemPrompt,
|
|
166
|
+
gatewayConfig: this.gatewayConfig,
|
|
167
|
+
modelConfig: this.modelConfig,
|
|
168
|
+
tokenLimit: this.tokenLimit,
|
|
90
169
|
});
|
|
91
170
|
|
|
92
171
|
// Initialize command manager
|
|
@@ -154,8 +233,17 @@ export class Agent {
|
|
|
154
233
|
return this.backgroundBashManager.killShell(id);
|
|
155
234
|
}
|
|
156
235
|
|
|
157
|
-
/**
|
|
236
|
+
/**
|
|
237
|
+
* Static async factory method for creating Agent instances
|
|
238
|
+
*
|
|
239
|
+
* IMPORTANT: Keep this method's signature exactly the same as the constructor
|
|
240
|
+
* to maintain consistency and avoid confusion for users of the API.
|
|
241
|
+
*
|
|
242
|
+
* @param options - Same AgentOptions interface used by constructor
|
|
243
|
+
* @returns Promise<Agent> - Fully initialized Agent instance
|
|
244
|
+
*/
|
|
158
245
|
static async create(options: AgentOptions): Promise<Agent> {
|
|
246
|
+
// Create Agent instance - configuration resolution and validation now happens in constructor
|
|
159
247
|
const instance = new Agent(options);
|
|
160
248
|
await instance.initialize({
|
|
161
249
|
restoreSessionId: options.restoreSessionId,
|
|
@@ -171,6 +259,25 @@ export class Agent {
|
|
|
171
259
|
continueLastSession?: boolean;
|
|
172
260
|
messages?: Message[];
|
|
173
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
|
+
|
|
174
281
|
// Initialize MCP servers with auto-connect
|
|
175
282
|
try {
|
|
176
283
|
await this.mcpManager.initialize(this.workdir, true);
|
|
@@ -224,6 +331,7 @@ export class Agent {
|
|
|
224
331
|
this.abortAIMessage();
|
|
225
332
|
this.abortBashCommand();
|
|
226
333
|
this.abortSlashCommand();
|
|
334
|
+
this.abortSubagents();
|
|
227
335
|
}
|
|
228
336
|
|
|
229
337
|
/** Add to input history */
|
|
@@ -241,16 +349,29 @@ export class Agent {
|
|
|
241
349
|
this.slashCommandManager.abortCurrentCommand();
|
|
242
350
|
}
|
|
243
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
|
+
|
|
244
362
|
/** Destroy managers, clean up resources */
|
|
245
363
|
public async destroy(): Promise<void> {
|
|
246
364
|
this.messageManager.saveSession();
|
|
247
365
|
this.abortAIMessage();
|
|
248
366
|
this.abortBashCommand();
|
|
249
367
|
this.abortSlashCommand();
|
|
368
|
+
this.abortSubagents();
|
|
250
369
|
// Cleanup background bash manager
|
|
251
370
|
this.backgroundBashManager.cleanup();
|
|
252
371
|
// Cleanup MCP connections
|
|
253
372
|
await this.mcpManager.cleanup();
|
|
373
|
+
// Cleanup subagent manager
|
|
374
|
+
this.subagentManager.cleanup();
|
|
254
375
|
}
|
|
255
376
|
|
|
256
377
|
public async sendMessage(
|
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
|
|
@@ -2,12 +2,11 @@ import { callAgent, compressMessages } from "../services/aiService.js";
|
|
|
2
2
|
import { getMessagesToCompress } from "../utils/messageOperations.js";
|
|
3
3
|
import { convertMessagesForAPI } from "../utils/convertMessagesForAPI.js";
|
|
4
4
|
import * as memory from "../services/memory.js";
|
|
5
|
-
import type { Logger } from "../types.js";
|
|
5
|
+
import type { Logger, GatewayConfig, ModelConfig } from "../types.js";
|
|
6
6
|
import type { ToolManager } from "./toolManager.js";
|
|
7
7
|
import type { ToolContext, ToolResult } from "../tools/types.js";
|
|
8
8
|
import type { MessageManager } from "./messageManager.js";
|
|
9
9
|
import type { BackgroundBashManager } from "./backgroundBashManager.js";
|
|
10
|
-
import { DEFAULT_TOKEN_LIMIT } from "../utils/constants.js";
|
|
11
10
|
import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
12
11
|
import type { HookManager } from "../hooks/index.js";
|
|
13
12
|
import type { ExtendedHookExecutionContext } from "../hooks/types.js";
|
|
@@ -25,6 +24,10 @@ export interface AIManagerOptions {
|
|
|
25
24
|
callbacks?: AIManagerCallbacks;
|
|
26
25
|
workdir: string;
|
|
27
26
|
systemPrompt?: string;
|
|
27
|
+
// Resolved configuration
|
|
28
|
+
gatewayConfig: GatewayConfig;
|
|
29
|
+
modelConfig: ModelConfig;
|
|
30
|
+
tokenLimit: number;
|
|
28
31
|
}
|
|
29
32
|
|
|
30
33
|
export class AIManager {
|
|
@@ -39,6 +42,11 @@ export class AIManager {
|
|
|
39
42
|
private workdir: string;
|
|
40
43
|
private systemPrompt?: string;
|
|
41
44
|
|
|
45
|
+
// Configuration properties
|
|
46
|
+
private gatewayConfig: GatewayConfig;
|
|
47
|
+
private modelConfig: ModelConfig;
|
|
48
|
+
private tokenLimit: number;
|
|
49
|
+
|
|
42
50
|
constructor(options: AIManagerOptions) {
|
|
43
51
|
this.messageManager = options.messageManager;
|
|
44
52
|
this.toolManager = options.toolManager;
|
|
@@ -48,6 +56,11 @@ export class AIManager {
|
|
|
48
56
|
this.workdir = options.workdir;
|
|
49
57
|
this.systemPrompt = options.systemPrompt;
|
|
50
58
|
this.callbacks = options.callbacks ?? {};
|
|
59
|
+
|
|
60
|
+
// Store resolved configuration
|
|
61
|
+
this.gatewayConfig = options.gatewayConfig;
|
|
62
|
+
this.modelConfig = options.modelConfig;
|
|
63
|
+
this.tokenLimit = options.tokenLimit;
|
|
51
64
|
}
|
|
52
65
|
|
|
53
66
|
private isCompressing: boolean = false;
|
|
@@ -125,15 +138,10 @@ export class AIManager {
|
|
|
125
138
|
// Update token statistics - display latest token usage
|
|
126
139
|
this.messageManager.setlatestTotalTokens(usage.total_tokens);
|
|
127
140
|
|
|
128
|
-
// Check if token limit exceeded
|
|
129
|
-
|
|
130
|
-
process.env.TOKEN_LIMIT || `${DEFAULT_TOKEN_LIMIT}`,
|
|
131
|
-
10,
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
if (usage.total_tokens > tokenLimit) {
|
|
141
|
+
// Check if token limit exceeded - use injected configuration
|
|
142
|
+
if (usage.total_tokens > this.tokenLimit) {
|
|
135
143
|
this.logger?.info(
|
|
136
|
-
`Token usage exceeded ${tokenLimit}, compressing messages...`,
|
|
144
|
+
`Token usage exceeded ${this.tokenLimit}, compressing messages...`,
|
|
137
145
|
);
|
|
138
146
|
|
|
139
147
|
// Check if messages need compression
|
|
@@ -149,6 +157,8 @@ export class AIManager {
|
|
|
149
157
|
this.setIsCompressing(true);
|
|
150
158
|
try {
|
|
151
159
|
const compressedContent = await compressMessages({
|
|
160
|
+
gatewayConfig: this.gatewayConfig,
|
|
161
|
+
modelConfig: this.modelConfig,
|
|
152
162
|
messages: recentChatMessages,
|
|
153
163
|
abortSignal: abortController.signal,
|
|
154
164
|
});
|
|
@@ -221,6 +231,8 @@ export class AIManager {
|
|
|
221
231
|
|
|
222
232
|
// Call AI service (non-streaming)
|
|
223
233
|
const result = await callAgent({
|
|
234
|
+
gatewayConfig: this.gatewayConfig,
|
|
235
|
+
modelConfig: this.modelConfig,
|
|
224
236
|
messages: recentMessages,
|
|
225
237
|
sessionId: this.messageManager.getSessionId(),
|
|
226
238
|
abortSignal: abortController.signal,
|
|
@@ -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
|
}
|