wave-agent-sdk 0.0.7 → 0.0.10
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 +105 -24
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +438 -53
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/managers/aiManager.d.ts +18 -7
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +254 -142
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +11 -9
- package/dist/managers/hookManager.d.ts +6 -6
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +81 -39
- package/dist/managers/liveConfigManager.d.ts +95 -0
- package/dist/managers/liveConfigManager.d.ts.map +1 -0
- package/dist/managers/liveConfigManager.js +442 -0
- package/dist/managers/lspManager.d.ts +43 -0
- package/dist/managers/lspManager.d.ts.map +1 -0
- package/dist/managers/lspManager.js +326 -0
- package/dist/managers/messageManager.d.ts +41 -24
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +184 -73
- package/dist/managers/permissionManager.d.ts +66 -0
- package/dist/managers/permissionManager.d.ts.map +1 -0
- package/dist/managers/permissionManager.js +208 -0
- package/dist/managers/skillManager.d.ts +1 -0
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/skillManager.js +2 -1
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +4 -2
- package/dist/managers/subagentManager.d.ts +42 -6
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +213 -62
- package/dist/managers/toolManager.d.ts +38 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +66 -2
- package/dist/services/aiService.d.ts +15 -5
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +446 -77
- package/dist/services/configurationService.d.ts +116 -0
- package/dist/services/configurationService.d.ts.map +1 -0
- package/dist/services/configurationService.js +585 -0
- package/dist/services/fileWatcher.d.ts +69 -0
- package/dist/services/fileWatcher.d.ts.map +1 -0
- package/dist/services/fileWatcher.js +212 -0
- package/dist/services/hook.d.ts +5 -40
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +47 -109
- package/dist/services/jsonlHandler.d.ts +71 -0
- package/dist/services/jsonlHandler.d.ts.map +1 -0
- package/dist/services/jsonlHandler.js +236 -0
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +33 -11
- package/dist/services/session.d.ts +116 -52
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +415 -143
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +77 -17
- package/dist/tools/deleteFileTool.d.ts.map +1 -1
- package/dist/tools/deleteFileTool.js +27 -1
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +33 -8
- package/dist/tools/lspTool.d.ts +6 -0
- package/dist/tools/lspTool.d.ts.map +1 -0
- package/dist/tools/lspTool.js +589 -0
- package/dist/tools/multiEditTool.d.ts.map +1 -1
- package/dist/tools/multiEditTool.js +30 -10
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +113 -3
- package/dist/tools/skillTool.js +2 -2
- package/dist/tools/todoWriteTool.d.ts.map +1 -1
- package/dist/tools/todoWriteTool.js +23 -0
- package/dist/tools/types.d.ts +11 -8
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/writeTool.d.ts.map +1 -1
- package/dist/tools/writeTool.js +30 -15
- package/dist/types/commands.d.ts +4 -1
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/config.d.ts +4 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/configuration.d.ts +69 -0
- package/dist/types/configuration.d.ts.map +1 -0
- package/dist/types/configuration.js +8 -0
- package/dist/types/core.d.ts +45 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/environment.d.ts +83 -0
- package/dist/types/environment.d.ts.map +1 -0
- package/dist/types/environment.js +21 -0
- package/dist/types/fileSearch.d.ts +5 -0
- package/dist/types/fileSearch.d.ts.map +1 -0
- package/dist/types/fileSearch.js +1 -0
- package/dist/types/hooks.d.ts +18 -3
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +8 -8
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +7 -0
- package/dist/types/lsp.d.ts +90 -0
- package/dist/types/lsp.d.ts.map +1 -0
- package/dist/types/lsp.js +4 -0
- package/dist/types/messaging.d.ts +19 -12
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/permissions.d.ts +35 -0
- package/dist/types/permissions.d.ts.map +1 -0
- package/dist/types/permissions.js +12 -0
- package/dist/types/session.d.ts +15 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +7 -0
- package/dist/types/skills.d.ts +1 -0
- package/dist/types/skills.d.ts.map +1 -1
- package/dist/types/tools.d.ts +35 -0
- package/dist/types/tools.d.ts.map +1 -0
- package/dist/types/tools.js +4 -0
- package/dist/utils/abortUtils.d.ts +34 -0
- package/dist/utils/abortUtils.d.ts.map +1 -0
- package/dist/utils/abortUtils.js +92 -0
- package/dist/utils/bashHistory.d.ts +4 -0
- package/dist/utils/bashHistory.d.ts.map +1 -1
- package/dist/utils/bashHistory.js +48 -30
- package/dist/utils/builtinSubagents.d.ts +7 -0
- package/dist/utils/builtinSubagents.d.ts.map +1 -0
- package/dist/utils/builtinSubagents.js +65 -0
- package/dist/utils/cacheControlUtils.d.ts +96 -0
- package/dist/utils/cacheControlUtils.d.ts.map +1 -0
- package/dist/utils/cacheControlUtils.js +324 -0
- package/dist/utils/commandPathResolver.d.ts +52 -0
- package/dist/utils/commandPathResolver.d.ts.map +1 -0
- package/dist/utils/commandPathResolver.js +145 -0
- package/dist/utils/configPaths.d.ts +85 -0
- package/dist/utils/configPaths.d.ts.map +1 -0
- package/dist/utils/configPaths.js +121 -0
- package/dist/utils/constants.d.ts +1 -13
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +2 -14
- package/dist/utils/convertMessagesForAPI.d.ts +2 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +39 -18
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/utils/customCommands.js +66 -21
- package/dist/utils/fileSearch.d.ts +14 -0
- package/dist/utils/fileSearch.d.ts.map +1 -0
- package/dist/utils/fileSearch.js +88 -0
- package/dist/utils/fileUtils.d.ts +27 -0
- package/dist/utils/fileUtils.d.ts.map +1 -0
- package/dist/utils/fileUtils.js +145 -0
- package/dist/utils/globalLogger.d.ts +88 -0
- package/dist/utils/globalLogger.d.ts.map +1 -0
- package/dist/utils/globalLogger.js +120 -0
- package/dist/utils/largeOutputHandler.d.ts +15 -0
- package/dist/utils/largeOutputHandler.d.ts.map +1 -0
- package/dist/utils/largeOutputHandler.js +40 -0
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/markdownParser.js +1 -17
- package/dist/utils/mcpUtils.d.ts.map +1 -1
- package/dist/utils/mcpUtils.js +25 -3
- package/dist/utils/messageOperations.d.ts +20 -18
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +30 -38
- package/dist/utils/pathEncoder.d.ts +108 -0
- package/dist/utils/pathEncoder.d.ts.map +1 -0
- package/dist/utils/pathEncoder.js +279 -0
- package/dist/utils/subagentParser.d.ts +2 -2
- package/dist/utils/subagentParser.d.ts.map +1 -1
- package/dist/utils/subagentParser.js +12 -8
- package/dist/utils/tokenCalculation.d.ts +26 -0
- package/dist/utils/tokenCalculation.d.ts.map +1 -0
- package/dist/utils/tokenCalculation.js +36 -0
- package/dist/utils/tokenEstimator.d.ts +39 -0
- package/dist/utils/tokenEstimator.d.ts.map +1 -0
- package/dist/utils/tokenEstimator.js +55 -0
- package/package.json +6 -6
- package/src/agent.ts +586 -78
- package/src/index.ts +4 -0
- package/src/managers/aiManager.ts +341 -192
- package/src/managers/backgroundBashManager.ts +11 -9
- package/src/managers/hookManager.ts +102 -54
- package/src/managers/liveConfigManager.ts +634 -0
- package/src/managers/lspManager.ts +434 -0
- package/src/managers/messageManager.ts +258 -121
- package/src/managers/permissionManager.ts +276 -0
- package/src/managers/skillManager.ts +3 -1
- package/src/managers/slashCommandManager.ts +5 -3
- package/src/managers/subagentManager.ts +295 -76
- package/src/managers/toolManager.ts +95 -3
- package/src/services/aiService.ts +656 -84
- package/src/services/configurationService.ts +762 -0
- package/src/services/fileWatcher.ts +300 -0
- package/src/services/hook.ts +54 -144
- package/src/services/jsonlHandler.ts +303 -0
- package/src/services/memory.ts +34 -11
- package/src/services/session.ts +522 -173
- package/src/tools/bashTool.ts +94 -20
- package/src/tools/deleteFileTool.ts +38 -1
- package/src/tools/editTool.ts +44 -9
- package/src/tools/lspTool.ts +760 -0
- package/src/tools/multiEditTool.ts +41 -11
- package/src/tools/readTool.ts +127 -3
- package/src/tools/skillTool.ts +2 -2
- package/src/tools/todoWriteTool.ts +33 -1
- package/src/tools/types.ts +15 -9
- package/src/tools/writeTool.ts +43 -16
- package/src/types/commands.ts +6 -1
- package/src/types/config.ts +5 -0
- package/src/types/configuration.ts +73 -0
- package/src/types/core.ts +55 -0
- package/src/types/environment.ts +104 -0
- package/src/types/fileSearch.ts +4 -0
- package/src/types/hooks.ts +32 -16
- package/src/types/index.ts +7 -0
- package/src/types/lsp.ts +96 -0
- package/src/types/messaging.ts +21 -14
- package/src/types/permissions.ts +48 -0
- package/src/types/session.ts +20 -0
- package/src/types/skills.ts +1 -0
- package/src/types/tools.ts +38 -0
- package/src/utils/abortUtils.ts +118 -0
- package/src/utils/bashHistory.ts +55 -31
- package/src/utils/builtinSubagents.ts +71 -0
- package/src/utils/cacheControlUtils.ts +475 -0
- package/src/utils/commandPathResolver.ts +189 -0
- package/src/utils/configPaths.ts +163 -0
- package/src/utils/constants.ts +2 -17
- package/src/utils/convertMessagesForAPI.ts +44 -18
- package/src/utils/customCommands.ts +90 -22
- package/src/utils/fileSearch.ts +107 -0
- package/src/utils/fileUtils.ts +160 -0
- package/src/utils/globalLogger.ts +128 -0
- package/src/utils/largeOutputHandler.ts +55 -0
- package/src/utils/markdownParser.ts +1 -19
- package/src/utils/mcpUtils.ts +34 -3
- package/src/utils/messageOperations.ts +47 -53
- package/src/utils/pathEncoder.ts +394 -0
- package/src/utils/subagentParser.ts +13 -9
- package/src/utils/tokenCalculation.ts +43 -0
- package/src/utils/tokenEstimator.ts +68 -0
- package/dist/utils/configResolver.d.ts +0 -38
- package/dist/utils/configResolver.d.ts.map +0 -1
- package/dist/utils/configResolver.js +0 -106
- package/src/utils/configResolver.ts +0 -142
package/src/agent.ts
CHANGED
|
@@ -4,16 +4,25 @@ 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 {
|
|
7
|
+
import {
|
|
8
|
+
SubagentManager,
|
|
9
|
+
type SubagentManagerCallbacks,
|
|
10
|
+
} from "./managers/subagentManager.js";
|
|
8
11
|
import * as memory from "./services/memory.js";
|
|
9
12
|
import { McpManager, type McpManagerCallbacks } from "./managers/mcpManager.js";
|
|
13
|
+
import { LspManager } from "./managers/lspManager.js";
|
|
10
14
|
import { BashManager } from "./managers/bashManager.js";
|
|
11
15
|
import {
|
|
12
16
|
BackgroundBashManager,
|
|
13
17
|
type BackgroundBashManagerCallbacks,
|
|
14
18
|
} from "./managers/backgroundBashManager.js";
|
|
15
19
|
import { SlashCommandManager } from "./managers/slashCommandManager.js";
|
|
16
|
-
import
|
|
20
|
+
import { PermissionManager } from "./managers/permissionManager.js";
|
|
21
|
+
import type {
|
|
22
|
+
SlashCommand,
|
|
23
|
+
CustomSlashCommand,
|
|
24
|
+
ILspManager,
|
|
25
|
+
} from "./types/index.js";
|
|
17
26
|
import type {
|
|
18
27
|
Message,
|
|
19
28
|
Logger,
|
|
@@ -21,11 +30,24 @@ import type {
|
|
|
21
30
|
GatewayConfig,
|
|
22
31
|
ModelConfig,
|
|
23
32
|
Usage,
|
|
33
|
+
PermissionMode,
|
|
34
|
+
PermissionCallback,
|
|
24
35
|
} from "./types/index.js";
|
|
25
36
|
import { HookManager } from "./managers/hookManager.js";
|
|
26
|
-
import {
|
|
37
|
+
import { LiveConfigManager } from "./managers/liveConfigManager.js";
|
|
27
38
|
import { configValidator } from "./utils/configValidator.js";
|
|
28
39
|
import { SkillManager } from "./managers/skillManager.js";
|
|
40
|
+
import {
|
|
41
|
+
loadSessionFromJsonl,
|
|
42
|
+
handleSessionRestoration,
|
|
43
|
+
} from "./services/session.js";
|
|
44
|
+
import type { SubagentConfiguration } from "./utils/subagentParser.js";
|
|
45
|
+
import { setGlobalLogger } from "./utils/globalLogger.js";
|
|
46
|
+
import { ConfigurationService } from "./services/configurationService.js";
|
|
47
|
+
import * as fs from "fs/promises";
|
|
48
|
+
import path from "path";
|
|
49
|
+
import os from "os";
|
|
50
|
+
import { ClientOptions } from "openai";
|
|
29
51
|
|
|
30
52
|
/**
|
|
31
53
|
* Configuration options for Agent instances
|
|
@@ -37,6 +59,9 @@ export interface AgentOptions {
|
|
|
37
59
|
// Optional configuration with environment fallbacks
|
|
38
60
|
apiKey?: string;
|
|
39
61
|
baseURL?: string;
|
|
62
|
+
defaultHeaders?: Record<string, string>;
|
|
63
|
+
fetchOptions?: ClientOptions["fetchOptions"];
|
|
64
|
+
fetch?: ClientOptions["fetch"];
|
|
40
65
|
agentModel?: string;
|
|
41
66
|
fastModel?: string;
|
|
42
67
|
tokenLimit?: number;
|
|
@@ -52,20 +77,23 @@ export interface AgentOptions {
|
|
|
52
77
|
workdir?: string;
|
|
53
78
|
/**Optional custom system prompt - if provided, replaces default system prompt */
|
|
54
79
|
systemPrompt?: string;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
80
|
+
/**Permission mode - defaults to "default" */
|
|
81
|
+
permissionMode?: PermissionMode;
|
|
82
|
+
/**Custom permission callback */
|
|
83
|
+
canUseTool?: PermissionCallback;
|
|
84
|
+
/**Whether to use streaming mode for AI responses - defaults to true */
|
|
85
|
+
stream?: boolean;
|
|
86
|
+
/**Optional custom LSP manager - if not provided, a standalone one will be created */
|
|
87
|
+
lspManager?: ILspManager;
|
|
63
88
|
}
|
|
64
89
|
|
|
65
90
|
export interface AgentCallbacks
|
|
66
91
|
extends MessageManagerCallbacks,
|
|
67
92
|
BackgroundBashManagerCallbacks,
|
|
68
|
-
McpManagerCallbacks
|
|
93
|
+
McpManagerCallbacks,
|
|
94
|
+
SubagentManagerCallbacks {
|
|
95
|
+
onPermissionModeChange?: (mode: PermissionMode) => void;
|
|
96
|
+
}
|
|
69
97
|
|
|
70
98
|
export class Agent {
|
|
71
99
|
private messageManager: MessageManager;
|
|
@@ -76,17 +104,80 @@ export class Agent {
|
|
|
76
104
|
private logger?: Logger; // Add optional logger property
|
|
77
105
|
private toolManager: ToolManager; // Add tool registry instance
|
|
78
106
|
private mcpManager: McpManager; // Add MCP manager instance
|
|
107
|
+
private lspManager: ILspManager; // Add LSP manager instance
|
|
108
|
+
private permissionManager: PermissionManager; // Add permission manager instance
|
|
79
109
|
private subagentManager: SubagentManager; // Add subagent manager instance
|
|
80
110
|
private slashCommandManager: SlashCommandManager; // Add slash command manager instance
|
|
81
111
|
private hookManager: HookManager; // Add hooks manager instance
|
|
112
|
+
private liveConfigManager: LiveConfigManager; // Add live configuration manager
|
|
113
|
+
private configurationService: ConfigurationService; // Add configuration service
|
|
82
114
|
private workdir: string; // Working directory
|
|
83
115
|
private systemPrompt?: string; // Custom system prompt
|
|
84
116
|
private _usages: Usage[] = []; // Usage tracking array
|
|
117
|
+
private stream: boolean; // Streaming mode flag
|
|
118
|
+
|
|
119
|
+
// Configuration options storage for dynamic resolution
|
|
120
|
+
private options: AgentOptions;
|
|
121
|
+
|
|
122
|
+
// Memory content storage
|
|
123
|
+
private _projectMemoryContent: string = "";
|
|
124
|
+
private _userMemoryContent: string = "";
|
|
125
|
+
|
|
126
|
+
// Dynamic configuration getter methods
|
|
127
|
+
public getGatewayConfig(): GatewayConfig {
|
|
128
|
+
return this.configurationService.resolveGatewayConfig(
|
|
129
|
+
this.options.apiKey,
|
|
130
|
+
this.options.baseURL,
|
|
131
|
+
this.options.defaultHeaders,
|
|
132
|
+
this.options.fetchOptions,
|
|
133
|
+
this.options.fetch,
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
public getModelConfig(): ModelConfig {
|
|
138
|
+
return this.configurationService.resolveModelConfig(
|
|
139
|
+
this.options.agentModel,
|
|
140
|
+
this.options.fastModel,
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public getTokenLimit(): number {
|
|
145
|
+
return this.configurationService.resolveTokenLimit(this.options.tokenLimit);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Update agent configuration dynamically
|
|
150
|
+
*
|
|
151
|
+
* @param config - Configuration updates for gateway, model, and token limit
|
|
152
|
+
*/
|
|
153
|
+
public updateConfig(config: {
|
|
154
|
+
gateway?: Partial<GatewayConfig>;
|
|
155
|
+
model?: Partial<ModelConfig>;
|
|
156
|
+
tokenLimit?: number;
|
|
157
|
+
}): void {
|
|
158
|
+
if (config.gateway) {
|
|
159
|
+
this.options.apiKey = config.gateway.apiKey ?? this.options.apiKey;
|
|
160
|
+
this.options.baseURL = config.gateway.baseURL ?? this.options.baseURL;
|
|
161
|
+
this.options.defaultHeaders =
|
|
162
|
+
config.gateway.defaultHeaders ?? this.options.defaultHeaders;
|
|
163
|
+
this.options.fetchOptions =
|
|
164
|
+
config.gateway.fetchOptions ?? this.options.fetchOptions;
|
|
165
|
+
this.options.fetch = config.gateway.fetch ?? this.options.fetch;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (config.model) {
|
|
169
|
+
this.options.agentModel =
|
|
170
|
+
config.model.agentModel ?? this.options.agentModel;
|
|
171
|
+
this.options.fastModel = config.model.fastModel ?? this.options.fastModel;
|
|
172
|
+
}
|
|
85
173
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
174
|
+
if (config.tokenLimit !== undefined) {
|
|
175
|
+
this.options.tokenLimit = config.tokenLimit;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Re-validate configuration after update
|
|
179
|
+
this.resolveAndValidateConfig();
|
|
180
|
+
}
|
|
90
181
|
|
|
91
182
|
/**
|
|
92
183
|
* Agent constructor - handles configuration resolution and validation
|
|
@@ -96,7 +187,6 @@ export class Agent {
|
|
|
96
187
|
* Agent.create() to maintain API consistency.
|
|
97
188
|
*
|
|
98
189
|
* @param options - Configuration options for the Agent instance
|
|
99
|
-
* @param options.sessionDir - Optional custom directory for session storage
|
|
100
190
|
*/
|
|
101
191
|
private constructor(options: AgentOptions) {
|
|
102
192
|
const {
|
|
@@ -104,47 +194,37 @@ export class Agent {
|
|
|
104
194
|
logger,
|
|
105
195
|
workdir,
|
|
106
196
|
systemPrompt,
|
|
107
|
-
|
|
197
|
+
stream = true,
|
|
108
198
|
} = options;
|
|
109
199
|
|
|
110
|
-
//
|
|
111
|
-
|
|
112
|
-
options.apiKey,
|
|
113
|
-
options.baseURL,
|
|
114
|
-
);
|
|
115
|
-
const modelConfig = configResolver.resolveModelConfig(
|
|
116
|
-
options.agentModel,
|
|
117
|
-
options.fastModel,
|
|
118
|
-
);
|
|
119
|
-
const tokenLimit = configResolver.resolveTokenLimit(options.tokenLimit);
|
|
200
|
+
// Set working directory early as we need it for loading configuration
|
|
201
|
+
this.workdir = workdir || process.cwd();
|
|
120
202
|
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
configValidator.validateTokenLimit(tokenLimit);
|
|
124
|
-
configValidator.validateModelConfig(
|
|
125
|
-
modelConfig.agentModel,
|
|
126
|
-
modelConfig.fastModel,
|
|
127
|
-
);
|
|
203
|
+
// Initialize configuration service
|
|
204
|
+
this.configurationService = new ConfigurationService();
|
|
128
205
|
|
|
129
206
|
this.logger = logger; // Save the passed logger
|
|
130
|
-
this.workdir = workdir || process.cwd(); // Set working directory, default to current working directory
|
|
131
207
|
this.systemPrompt = systemPrompt; // Save custom system prompt
|
|
208
|
+
this.stream = stream; // Save streaming mode flag
|
|
132
209
|
|
|
133
|
-
// Store
|
|
134
|
-
this.
|
|
135
|
-
this.modelConfig = modelConfig;
|
|
136
|
-
this.tokenLimit = tokenLimit;
|
|
210
|
+
// Store options for dynamic configuration resolution
|
|
211
|
+
this.options = options;
|
|
137
212
|
|
|
138
213
|
this.backgroundBashManager = new BackgroundBashManager({
|
|
139
214
|
callbacks,
|
|
140
215
|
workdir: this.workdir,
|
|
141
216
|
});
|
|
142
217
|
this.mcpManager = new McpManager({ callbacks, logger: this.logger }); // Initialize MCP manager
|
|
143
|
-
this.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
218
|
+
this.lspManager =
|
|
219
|
+
options.lspManager || new LspManager({ logger: this.logger }); // Initialize LSP manager
|
|
220
|
+
|
|
221
|
+
// Initialize permission manager
|
|
222
|
+
this.permissionManager = new PermissionManager({ logger: this.logger });
|
|
223
|
+
this.permissionManager.setOnConfiguredDefaultModeChange((mode) => {
|
|
224
|
+
this.options.callbacks?.onPermissionModeChange?.(mode);
|
|
225
|
+
});
|
|
147
226
|
|
|
227
|
+
// Initialize configuration service and hooks manager
|
|
148
228
|
this.hookManager = new HookManager(this.workdir, undefined, this.logger); // Initialize hooks manager
|
|
149
229
|
|
|
150
230
|
// Initialize MessageManager
|
|
@@ -152,19 +232,89 @@ export class Agent {
|
|
|
152
232
|
callbacks,
|
|
153
233
|
workdir: this.workdir,
|
|
154
234
|
logger: this.logger,
|
|
155
|
-
sessionDir,
|
|
156
235
|
});
|
|
157
236
|
|
|
237
|
+
// Create a wrapper for canUseTool that triggers notification hooks
|
|
238
|
+
const canUseToolWithNotification: PermissionCallback | undefined =
|
|
239
|
+
options.canUseTool
|
|
240
|
+
? async (context) => {
|
|
241
|
+
try {
|
|
242
|
+
// Trigger notification hooks before calling the original callback
|
|
243
|
+
const notificationMessage = `Claude needs your permission to use ${context.toolName}`;
|
|
244
|
+
await this.hookManager.executeHooks("Notification", {
|
|
245
|
+
event: "Notification",
|
|
246
|
+
projectDir: this.workdir,
|
|
247
|
+
timestamp: new Date(),
|
|
248
|
+
sessionId: this.sessionId,
|
|
249
|
+
transcriptPath: this.messageManager.getTranscriptPath(),
|
|
250
|
+
cwd: this.workdir,
|
|
251
|
+
message: notificationMessage,
|
|
252
|
+
notificationType: "permission_prompt",
|
|
253
|
+
env: this.configurationService.getEnvironmentVars(), // Include configuration environment variables
|
|
254
|
+
});
|
|
255
|
+
} catch (error) {
|
|
256
|
+
this.logger?.warn("Failed to execute notification hooks", {
|
|
257
|
+
toolName: context.toolName,
|
|
258
|
+
error: error instanceof Error ? error.message : String(error),
|
|
259
|
+
});
|
|
260
|
+
// Continue with permission check even if hooks fail
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Call the original callback
|
|
264
|
+
const decision = await options.canUseTool!(context);
|
|
265
|
+
|
|
266
|
+
// Handle state changes from decision
|
|
267
|
+
if (decision.newPermissionMode) {
|
|
268
|
+
this.setPermissionMode(decision.newPermissionMode);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (decision.newPermissionRule) {
|
|
272
|
+
await this.addPermissionRule(decision.newPermissionRule);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return decision;
|
|
276
|
+
}
|
|
277
|
+
: undefined;
|
|
278
|
+
|
|
279
|
+
// Initialize tool manager with permission context
|
|
280
|
+
this.toolManager = new ToolManager({
|
|
281
|
+
mcpManager: this.mcpManager,
|
|
282
|
+
lspManager: this.lspManager,
|
|
283
|
+
logger: this.logger,
|
|
284
|
+
permissionManager: this.permissionManager,
|
|
285
|
+
permissionMode: options.permissionMode, // Let PermissionManager handle defaultMode resolution
|
|
286
|
+
canUseToolCallback: canUseToolWithNotification,
|
|
287
|
+
}); // Initialize tool registry with permission support
|
|
288
|
+
this.liveConfigManager = new LiveConfigManager({
|
|
289
|
+
workdir: this.workdir,
|
|
290
|
+
logger: this.logger,
|
|
291
|
+
hookManager: this.hookManager,
|
|
292
|
+
permissionManager: this.permissionManager,
|
|
293
|
+
configurationService: this.configurationService,
|
|
294
|
+
}); // Initialize live configuration manager
|
|
295
|
+
|
|
158
296
|
// Initialize subagent manager with all dependencies in constructor
|
|
159
297
|
// IMPORTANT: Must be initialized AFTER MessageManager
|
|
160
298
|
this.subagentManager = new SubagentManager({
|
|
161
299
|
workdir: this.workdir,
|
|
162
300
|
parentToolManager: this.toolManager,
|
|
163
301
|
parentMessageManager: this.messageManager,
|
|
302
|
+
callbacks: {
|
|
303
|
+
onSubagentUserMessageAdded: callbacks.onSubagentUserMessageAdded,
|
|
304
|
+
onSubagentAssistantMessageAdded:
|
|
305
|
+
callbacks.onSubagentAssistantMessageAdded,
|
|
306
|
+
onSubagentAssistantContentUpdated:
|
|
307
|
+
callbacks.onSubagentAssistantContentUpdated,
|
|
308
|
+
onSubagentAssistantReasoningUpdated:
|
|
309
|
+
callbacks.onSubagentAssistantReasoningUpdated,
|
|
310
|
+
onSubagentToolBlockUpdated: callbacks.onSubagentToolBlockUpdated,
|
|
311
|
+
onSubagentMessagesChange: callbacks.onSubagentMessagesChange,
|
|
312
|
+
}, // Pass subagent callbacks for forwarding
|
|
164
313
|
logger: this.logger,
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
314
|
+
getGatewayConfig: () => this.getGatewayConfig(),
|
|
315
|
+
getModelConfig: () => this.getModelConfig(),
|
|
316
|
+
getTokenLimit: () => this.getTokenLimit(),
|
|
317
|
+
hookManager: this.hookManager,
|
|
168
318
|
onUsageAdded: (usage) => this.addUsage(usage),
|
|
169
319
|
});
|
|
170
320
|
|
|
@@ -183,9 +333,11 @@ export class Agent {
|
|
|
183
333
|
},
|
|
184
334
|
workdir: this.workdir,
|
|
185
335
|
systemPrompt: this.systemPrompt,
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
336
|
+
stream: this.stream, // Pass streaming mode flag
|
|
337
|
+
getGatewayConfig: () => this.getGatewayConfig(),
|
|
338
|
+
getModelConfig: () => this.getModelConfig(),
|
|
339
|
+
getTokenLimit: () => this.getTokenLimit(),
|
|
340
|
+
getEnvironmentVars: () => this.configurationService.getEnvironmentVars(), // Provide access to configuration environment variables
|
|
189
341
|
});
|
|
190
342
|
|
|
191
343
|
// Initialize command manager
|
|
@@ -224,9 +376,9 @@ export class Agent {
|
|
|
224
376
|
* Rebuild usage array from messages containing usage metadata
|
|
225
377
|
* Called during session restoration to reconstruct usage tracking
|
|
226
378
|
*/
|
|
227
|
-
private rebuildUsageFromMessages(): void {
|
|
379
|
+
private rebuildUsageFromMessages(messages: Message[]): void {
|
|
228
380
|
this._usages = [];
|
|
229
|
-
|
|
381
|
+
messages.forEach((message) => {
|
|
230
382
|
if (message.role === "assistant" && message.usage) {
|
|
231
383
|
this._usages.push(message.usage);
|
|
232
384
|
}
|
|
@@ -257,6 +409,31 @@ export class Agent {
|
|
|
257
409
|
return this.workdir;
|
|
258
410
|
}
|
|
259
411
|
|
|
412
|
+
/** Get project memory content */
|
|
413
|
+
public get projectMemory(): string {
|
|
414
|
+
return this._projectMemoryContent;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/** Get user memory content */
|
|
418
|
+
public get userMemory(): string {
|
|
419
|
+
return this._userMemoryContent;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
/** Get combined memory content (project + user) */
|
|
423
|
+
public get combinedMemory(): string {
|
|
424
|
+
let combined = "";
|
|
425
|
+
if (this._projectMemoryContent.trim()) {
|
|
426
|
+
combined += this._projectMemoryContent;
|
|
427
|
+
}
|
|
428
|
+
if (this._userMemoryContent.trim()) {
|
|
429
|
+
if (combined) {
|
|
430
|
+
combined += "\n\n";
|
|
431
|
+
}
|
|
432
|
+
combined += this._userMemoryContent;
|
|
433
|
+
}
|
|
434
|
+
return combined;
|
|
435
|
+
}
|
|
436
|
+
|
|
260
437
|
/** Get AI loading status */
|
|
261
438
|
public get isLoading(): boolean {
|
|
262
439
|
return this.aiManager.isLoading;
|
|
@@ -303,9 +480,9 @@ export class Agent {
|
|
|
303
480
|
* @param options - Configuration options for the Agent instance
|
|
304
481
|
* @param options.apiKey - API key for the AI service (or set WAVE_API_KEY env var)
|
|
305
482
|
* @param options.baseURL - Base URL for the AI service (or set WAVE_BASE_URL env var)
|
|
306
|
-
* @param options.
|
|
307
|
-
*
|
|
308
|
-
*
|
|
483
|
+
* @param options.defaultHeaders - Optional HTTP headers to pass to the AI service
|
|
484
|
+
* @param options.fetchOptions - Optional fetch options to pass to the AI service
|
|
485
|
+
* @param options.fetch - Optional custom fetch implementation
|
|
309
486
|
* @param options.callbacks - Optional callbacks for various Agent events
|
|
310
487
|
* @param options.restoreSessionId - Optional session ID to restore from
|
|
311
488
|
* @param options.continueLastSession - Whether to continue the last session automatically
|
|
@@ -317,22 +494,15 @@ export class Agent {
|
|
|
317
494
|
*
|
|
318
495
|
* @example
|
|
319
496
|
* ```typescript
|
|
320
|
-
* // Basic usage
|
|
497
|
+
* // Basic usage
|
|
321
498
|
* const agent = await Agent.create({
|
|
322
499
|
* apiKey: 'your-api-key',
|
|
323
500
|
* baseURL: 'https://api.example.com'
|
|
324
501
|
* });
|
|
325
|
-
*
|
|
326
|
-
* // Custom session directory
|
|
327
|
-
* const agent = await Agent.create({
|
|
328
|
-
* apiKey: 'your-api-key',
|
|
329
|
-
* baseURL: 'https://api.example.com',
|
|
330
|
-
* sessionDir: './app-sessions'
|
|
331
|
-
* });
|
|
332
502
|
* ```
|
|
333
503
|
*/
|
|
334
504
|
static async create(options: AgentOptions): Promise<Agent> {
|
|
335
|
-
// Create Agent instance
|
|
505
|
+
// Create Agent instance
|
|
336
506
|
const instance = new Agent(options);
|
|
337
507
|
await instance.initialize({
|
|
338
508
|
restoreSessionId: options.restoreSessionId,
|
|
@@ -342,6 +512,27 @@ export class Agent {
|
|
|
342
512
|
return instance;
|
|
343
513
|
}
|
|
344
514
|
|
|
515
|
+
/**
|
|
516
|
+
* Resolve and validate configuration from constructor args, environment variables,
|
|
517
|
+
* and loaded settings.json.
|
|
518
|
+
*
|
|
519
|
+
* This is called during initialization after settings.json has been loaded.
|
|
520
|
+
*/
|
|
521
|
+
private resolveAndValidateConfig(): void {
|
|
522
|
+
// Resolve configuration from constructor args and environment variables (including settings.json)
|
|
523
|
+
const gatewayConfig = this.getGatewayConfig();
|
|
524
|
+
const modelConfig = this.getModelConfig();
|
|
525
|
+
const tokenLimit = this.getTokenLimit();
|
|
526
|
+
|
|
527
|
+
// Validate resolved configuration
|
|
528
|
+
configValidator.validateGatewayConfig(gatewayConfig);
|
|
529
|
+
configValidator.validateTokenLimit(tokenLimit);
|
|
530
|
+
configValidator.validateModelConfig(
|
|
531
|
+
modelConfig.agentModel,
|
|
532
|
+
modelConfig.fastModel,
|
|
533
|
+
);
|
|
534
|
+
}
|
|
535
|
+
|
|
345
536
|
/** Private initialization method, handles async initialization logic */
|
|
346
537
|
private async initialize(options?: {
|
|
347
538
|
restoreSessionId?: string;
|
|
@@ -351,7 +542,10 @@ export class Agent {
|
|
|
351
542
|
// Initialize managers first
|
|
352
543
|
try {
|
|
353
544
|
// Initialize SkillManager
|
|
354
|
-
const skillManager = new SkillManager({
|
|
545
|
+
const skillManager = new SkillManager({
|
|
546
|
+
logger: this.logger,
|
|
547
|
+
workdir: this.workdir,
|
|
548
|
+
});
|
|
355
549
|
await skillManager.initialize();
|
|
356
550
|
|
|
357
551
|
// Initialize SubagentManager (load and cache configurations)
|
|
@@ -370,6 +564,9 @@ export class Agent {
|
|
|
370
564
|
// Initialize MCP servers with auto-connect
|
|
371
565
|
try {
|
|
372
566
|
await this.mcpManager.initialize(this.workdir, true);
|
|
567
|
+
if (this.lspManager instanceof LspManager) {
|
|
568
|
+
await this.lspManager.initialize(this.workdir);
|
|
569
|
+
}
|
|
373
570
|
} catch (error) {
|
|
374
571
|
this.logger?.error("Failed to initialize MCP servers:", error);
|
|
375
572
|
// Don't throw error to prevent app startup failure
|
|
@@ -377,32 +574,253 @@ export class Agent {
|
|
|
377
574
|
|
|
378
575
|
// Initialize hooks configuration
|
|
379
576
|
try {
|
|
380
|
-
// Load hooks configuration
|
|
577
|
+
// Load hooks configuration using ConfigurationService
|
|
381
578
|
this.logger?.debug("Loading hooks configuration...");
|
|
382
|
-
|
|
579
|
+
const configResult =
|
|
580
|
+
await this.configurationService.loadMergedConfiguration(this.workdir);
|
|
581
|
+
|
|
582
|
+
this.hookManager.loadConfigurationFromWaveConfig(
|
|
583
|
+
configResult.configuration,
|
|
584
|
+
);
|
|
383
585
|
this.logger?.debug("Hooks system initialized successfully");
|
|
384
586
|
} catch (error) {
|
|
385
587
|
this.logger?.error("Failed to initialize hooks system:", error);
|
|
386
588
|
// Don't throw error to prevent app startup failure
|
|
387
589
|
}
|
|
388
590
|
|
|
591
|
+
// Resolve and validate configuration after loading settings.json
|
|
592
|
+
this.resolveAndValidateConfig();
|
|
593
|
+
|
|
594
|
+
// Set global logger for SDK-wide access after validation
|
|
595
|
+
setGlobalLogger(this.logger || null);
|
|
596
|
+
|
|
597
|
+
// Initialize live configuration reload
|
|
598
|
+
try {
|
|
599
|
+
this.logger?.debug("Initializing live configuration reload...");
|
|
600
|
+
await this.liveConfigManager.initialize();
|
|
601
|
+
this.logger?.debug("Live configuration reload initialized successfully");
|
|
602
|
+
|
|
603
|
+
// Update permission manager with configuration-based defaultMode
|
|
604
|
+
const currentConfig = this.liveConfigManager.getCurrentConfiguration();
|
|
605
|
+
if (currentConfig?.defaultMode) {
|
|
606
|
+
this.logger?.debug(
|
|
607
|
+
"Applying configured defaultMode to PermissionManager",
|
|
608
|
+
{
|
|
609
|
+
defaultMode: currentConfig.defaultMode,
|
|
610
|
+
},
|
|
611
|
+
);
|
|
612
|
+
this.permissionManager.updateConfiguredDefaultMode(
|
|
613
|
+
currentConfig.defaultMode,
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// Update permission manager with configuration-based allowed rules
|
|
618
|
+
if (currentConfig?.permissions?.allow) {
|
|
619
|
+
this.logger?.debug(
|
|
620
|
+
"Applying configured allowed rules to PermissionManager",
|
|
621
|
+
{
|
|
622
|
+
count: currentConfig.permissions.allow.length,
|
|
623
|
+
},
|
|
624
|
+
);
|
|
625
|
+
this.permissionManager.updateAllowedRules(
|
|
626
|
+
currentConfig.permissions.allow,
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
} catch (error) {
|
|
630
|
+
this.logger?.error(
|
|
631
|
+
"Failed to initialize live configuration reload:",
|
|
632
|
+
error,
|
|
633
|
+
);
|
|
634
|
+
// Don't throw error to prevent app startup failure - continue without live reload
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
// Load memory files during initialization
|
|
638
|
+
try {
|
|
639
|
+
this.logger?.debug("Loading memory files...");
|
|
640
|
+
|
|
641
|
+
// Load project memory from AGENTS.md (bypass memory store for direct file access)
|
|
642
|
+
try {
|
|
643
|
+
const projectMemoryPath = path.join(this.workdir, "AGENTS.md");
|
|
644
|
+
this._projectMemoryContent = await fs.readFile(
|
|
645
|
+
projectMemoryPath,
|
|
646
|
+
"utf-8",
|
|
647
|
+
);
|
|
648
|
+
this.logger?.debug("Project memory loaded successfully");
|
|
649
|
+
} catch (error) {
|
|
650
|
+
this._projectMemoryContent = "";
|
|
651
|
+
this.logger?.debug(
|
|
652
|
+
"Project memory file not found or unreadable, using empty content:",
|
|
653
|
+
error instanceof Error ? error.message : String(error),
|
|
654
|
+
);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Load user memory (bypass memory store for direct file access)
|
|
658
|
+
try {
|
|
659
|
+
const userMemoryPath = path.join(os.homedir(), ".wave", "AGENTS.md");
|
|
660
|
+
this._userMemoryContent = await fs.readFile(userMemoryPath, "utf-8");
|
|
661
|
+
this.logger?.debug("User memory loaded successfully");
|
|
662
|
+
} catch (error) {
|
|
663
|
+
this._userMemoryContent = "";
|
|
664
|
+
this.logger?.debug(
|
|
665
|
+
"User memory file not found or unreadable, using empty content:",
|
|
666
|
+
error instanceof Error ? error.message : String(error),
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
this.logger?.debug("Memory initialization completed");
|
|
671
|
+
} catch (error) {
|
|
672
|
+
// Ensure memory is always initialized even if loading fails
|
|
673
|
+
this._projectMemoryContent = "";
|
|
674
|
+
this._userMemoryContent = "";
|
|
675
|
+
this.logger?.error("Failed to load memory files:", error);
|
|
676
|
+
// Don't throw error to prevent app startup failure
|
|
677
|
+
}
|
|
678
|
+
|
|
389
679
|
// Handle session restoration or set provided messages
|
|
390
680
|
if (options?.messages) {
|
|
391
681
|
// If messages are provided, use them directly (useful for testing)
|
|
392
682
|
this.messageManager.setMessages(options.messages);
|
|
393
683
|
// Rebuild usage array from restored messages
|
|
394
|
-
this.rebuildUsageFromMessages();
|
|
684
|
+
this.rebuildUsageFromMessages(options.messages);
|
|
395
685
|
} else {
|
|
396
686
|
// Otherwise, handle session restoration
|
|
397
|
-
await
|
|
687
|
+
const sessionToRestore = await handleSessionRestoration(
|
|
398
688
|
options?.restoreSessionId,
|
|
399
689
|
options?.continueLastSession,
|
|
690
|
+
this.messageManager.getWorkdir(),
|
|
400
691
|
);
|
|
401
692
|
// Rebuild usage array from restored messages
|
|
402
|
-
this.rebuildUsageFromMessages();
|
|
693
|
+
this.rebuildUsageFromMessages(sessionToRestore?.messages || []);
|
|
694
|
+
|
|
695
|
+
// After main session is restored, restore any associated subagent sessions
|
|
696
|
+
await this.restoreSubagentSessions(sessionToRestore?.messages || []);
|
|
697
|
+
|
|
698
|
+
if (sessionToRestore)
|
|
699
|
+
this.messageManager.initializeFromSession(sessionToRestore);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
/**
|
|
704
|
+
* Restore subagent sessions associated with the current main session
|
|
705
|
+
* This method is called after the main session is restored to load any subagent sessions
|
|
706
|
+
*/
|
|
707
|
+
private async restoreSubagentSessions(messages: Message[]): Promise<void> {
|
|
708
|
+
try {
|
|
709
|
+
// Only attempt to restore subagent sessions if we have messages (session was restored)
|
|
710
|
+
if (messages.length === 0) {
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// Extract sessionId -> subagentId mapping from SubagentBlocks
|
|
715
|
+
const subagentBlockMap = new Map<
|
|
716
|
+
string,
|
|
717
|
+
{ subagentId: string; configuration: SubagentConfiguration }
|
|
718
|
+
>(); // sessionId -> { subagentId, configuration }
|
|
719
|
+
|
|
720
|
+
for (const message of messages) {
|
|
721
|
+
if (message.role === "assistant" && message.blocks) {
|
|
722
|
+
for (const block of message.blocks) {
|
|
723
|
+
if (
|
|
724
|
+
block.type === "subagent" &&
|
|
725
|
+
block.sessionId &&
|
|
726
|
+
block.subagentId &&
|
|
727
|
+
block.configuration
|
|
728
|
+
) {
|
|
729
|
+
subagentBlockMap.set(block.sessionId, {
|
|
730
|
+
subagentId: block.subagentId,
|
|
731
|
+
configuration: block.configuration,
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (subagentBlockMap.size === 0) {
|
|
739
|
+
return; // No subagent blocks found
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
// Load subagent sessions using sessionIds
|
|
743
|
+
const subagentSessions = [];
|
|
744
|
+
for (const [sessionId, blockData] of subagentBlockMap) {
|
|
745
|
+
try {
|
|
746
|
+
const sessionData = await loadSessionFromJsonl(
|
|
747
|
+
sessionId,
|
|
748
|
+
this.messageManager.getWorkdir(),
|
|
749
|
+
"subagent",
|
|
750
|
+
);
|
|
751
|
+
if (sessionData) {
|
|
752
|
+
subagentSessions.push({
|
|
753
|
+
sessionData,
|
|
754
|
+
subagentId: blockData.subagentId, // Use the subagentId from SubagentBlock
|
|
755
|
+
configuration: blockData.configuration, // Include configuration
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
} catch (error) {
|
|
759
|
+
this.logger?.warn(
|
|
760
|
+
`Failed to load subagent session ${sessionId}:`,
|
|
761
|
+
error,
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
if (subagentSessions.length > 0) {
|
|
767
|
+
this.logger?.debug(
|
|
768
|
+
`Found ${subagentSessions.length} subagent sessions to restore`,
|
|
769
|
+
);
|
|
770
|
+
|
|
771
|
+
// Restore subagent sessions through the SubagentManager
|
|
772
|
+
await this.subagentManager.restoreSubagentSessions(subagentSessions);
|
|
773
|
+
|
|
774
|
+
this.logger?.debug("Subagent sessions restored successfully");
|
|
775
|
+
}
|
|
776
|
+
} catch (error) {
|
|
777
|
+
this.logger?.warn("Failed to restore subagent sessions:", error);
|
|
778
|
+
// Don't throw error to prevent app startup failure
|
|
403
779
|
}
|
|
404
780
|
}
|
|
405
781
|
|
|
782
|
+
/**
|
|
783
|
+
* Restore a session by ID, switching to the target session without destroying the Agent instance
|
|
784
|
+
* @param sessionId - The ID of the session to restore
|
|
785
|
+
*/
|
|
786
|
+
public async restoreSession(sessionId: string): Promise<void> {
|
|
787
|
+
// 1. Validation
|
|
788
|
+
if (!sessionId || sessionId === this.sessionId) {
|
|
789
|
+
return; // No-op if session ID is invalid or already current
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// 2. Auto-save current session
|
|
793
|
+
try {
|
|
794
|
+
await this.messageManager.saveSession();
|
|
795
|
+
} catch (error) {
|
|
796
|
+
this.logger?.warn(
|
|
797
|
+
"Failed to save current session before restore:",
|
|
798
|
+
error,
|
|
799
|
+
);
|
|
800
|
+
// Continue with restoration even if save fails
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// 3. Load target session
|
|
804
|
+
const sessionData = await loadSessionFromJsonl(
|
|
805
|
+
sessionId,
|
|
806
|
+
this.messageManager.getWorkdir(),
|
|
807
|
+
);
|
|
808
|
+
if (!sessionData) {
|
|
809
|
+
throw new Error(`Session not found: ${sessionId}`);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
// 4. Clean current state
|
|
813
|
+
this.abortMessage(); // Abort any running operations
|
|
814
|
+
this.subagentManager.cleanup(); // Clean up active subagents
|
|
815
|
+
|
|
816
|
+
// 5. Rebuild usage and restore subagents (in correct order)
|
|
817
|
+
this.rebuildUsageFromMessages(sessionData.messages);
|
|
818
|
+
await this.restoreSubagentSessions(sessionData.messages);
|
|
819
|
+
|
|
820
|
+
// 6. Initialize session state last
|
|
821
|
+
this.messageManager.initializeFromSession(sessionData);
|
|
822
|
+
}
|
|
823
|
+
|
|
406
824
|
public abortAIMessage(): void {
|
|
407
825
|
this.aiManager.abortAIMessage();
|
|
408
826
|
}
|
|
@@ -451,10 +869,50 @@ export class Agent {
|
|
|
451
869
|
this.backgroundBashManager.cleanup();
|
|
452
870
|
// Cleanup MCP connections
|
|
453
871
|
await this.mcpManager.cleanup();
|
|
872
|
+
// Cleanup LSP connections
|
|
873
|
+
if (this.lspManager instanceof LspManager) {
|
|
874
|
+
await this.lspManager.cleanup();
|
|
875
|
+
}
|
|
454
876
|
// Cleanup subagent manager
|
|
455
877
|
this.subagentManager.cleanup();
|
|
878
|
+
// Cleanup live configuration reload
|
|
879
|
+
try {
|
|
880
|
+
await this.liveConfigManager.shutdown();
|
|
881
|
+
} catch (error) {
|
|
882
|
+
this.logger?.error(
|
|
883
|
+
"Error shutting down live configuration reload:",
|
|
884
|
+
error,
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
// Cleanup memory store
|
|
456
888
|
}
|
|
457
889
|
|
|
890
|
+
/**
|
|
891
|
+
* Send a message to the AI agent with optional images
|
|
892
|
+
*
|
|
893
|
+
* @param content - The text content of the message to send
|
|
894
|
+
* @param images - Optional array of images to include with the message
|
|
895
|
+
* @param images[].path - File path to the image or base64 encoded image data
|
|
896
|
+
* @param images[].mimeType - MIME type of the image (e.g., 'image/png', 'image/jpeg')
|
|
897
|
+
* @returns Promise that resolves when the message has been processed
|
|
898
|
+
*
|
|
899
|
+
* @example
|
|
900
|
+
* ```typescript
|
|
901
|
+
* // Send a text message
|
|
902
|
+
* await agent.sendMessage("Hello, how are you?");
|
|
903
|
+
*
|
|
904
|
+
* // Send a message with images using file paths
|
|
905
|
+
* await agent.sendMessage("What do you see in these images?", [
|
|
906
|
+
* { path: "/path/to/image.png", mimeType: "image/png" },
|
|
907
|
+
* { path: "/path/to/photo.jpg", mimeType: "image/jpeg" }
|
|
908
|
+
* ]);
|
|
909
|
+
*
|
|
910
|
+
* // Send a message with base64 encoded image
|
|
911
|
+
* await agent.sendMessage("Analyze this image", [
|
|
912
|
+
* { path: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", mimeType: "image/png" }
|
|
913
|
+
* ]);
|
|
914
|
+
* ```
|
|
915
|
+
*/
|
|
458
916
|
public async sendMessage(
|
|
459
917
|
content: string,
|
|
460
918
|
images?: Array<{ path: string; mimeType: string }>,
|
|
@@ -509,6 +967,7 @@ export class Agent {
|
|
|
509
967
|
transcriptPath: this.messageManager.getTranscriptPath(),
|
|
510
968
|
cwd: this.workdir,
|
|
511
969
|
userPrompt: content,
|
|
970
|
+
env: this.configurationService.getEnvironmentVars(), // Include configuration environment variables
|
|
512
971
|
},
|
|
513
972
|
);
|
|
514
973
|
|
|
@@ -547,16 +1006,25 @@ export class Agent {
|
|
|
547
1006
|
type: "project" | "user",
|
|
548
1007
|
): Promise<void> {
|
|
549
1008
|
try {
|
|
1009
|
+
// Ensure the message starts with # for memory functions
|
|
1010
|
+
const formattedMessage = message.startsWith("#")
|
|
1011
|
+
? message
|
|
1012
|
+
: `#${message}`;
|
|
1013
|
+
|
|
550
1014
|
if (type === "project") {
|
|
551
|
-
await memory.addMemory(
|
|
1015
|
+
await memory.addMemory(formattedMessage, this.workdir);
|
|
1016
|
+
// Update internal state after successful save
|
|
1017
|
+
this._projectMemoryContent = await memory.readMemoryFile(this.workdir);
|
|
552
1018
|
} else {
|
|
553
|
-
await memory.addUserMemory(
|
|
1019
|
+
await memory.addUserMemory(formattedMessage);
|
|
1020
|
+
// Update internal state after successful save
|
|
1021
|
+
this._userMemoryContent = await memory.getUserMemoryContent();
|
|
554
1022
|
}
|
|
555
1023
|
|
|
556
1024
|
// Add successful MemoryBlock to the last assistant message
|
|
557
1025
|
const memoryText = message.substring(1).trim();
|
|
558
1026
|
const typeLabel = type === "project" ? "Project Memory" : "User Memory";
|
|
559
|
-
const storagePath =
|
|
1027
|
+
const storagePath = "AGENTS.md";
|
|
560
1028
|
|
|
561
1029
|
this.messageManager.addMemoryBlock(
|
|
562
1030
|
`${typeLabel}: ${memoryText}`,
|
|
@@ -566,13 +1034,14 @@ export class Agent {
|
|
|
566
1034
|
);
|
|
567
1035
|
} catch (error) {
|
|
568
1036
|
// Add failed MemoryBlock to the last assistant message
|
|
1037
|
+
const memoryText = message.substring(1).trim();
|
|
569
1038
|
const typeLabel = type === "project" ? "Project Memory" : "User Memory";
|
|
570
|
-
const storagePath =
|
|
1039
|
+
const storagePath = "AGENTS.md";
|
|
1040
|
+
const errorMessage =
|
|
1041
|
+
error instanceof Error ? error.message : String(error);
|
|
571
1042
|
|
|
572
1043
|
this.messageManager.addMemoryBlock(
|
|
573
|
-
`${typeLabel}
|
|
574
|
-
error instanceof Error ? error.message : String(error)
|
|
575
|
-
}`,
|
|
1044
|
+
`${typeLabel}: ${memoryText} - Error: ${errorMessage}`,
|
|
576
1045
|
false,
|
|
577
1046
|
type,
|
|
578
1047
|
storagePath,
|
|
@@ -623,4 +1092,43 @@ export class Agent {
|
|
|
623
1092
|
public getCustomCommands(): CustomSlashCommand[] {
|
|
624
1093
|
return this.slashCommandManager.getCustomCommands();
|
|
625
1094
|
}
|
|
1095
|
+
|
|
1096
|
+
/**
|
|
1097
|
+
* Get the current permission mode
|
|
1098
|
+
*/
|
|
1099
|
+
public getPermissionMode(): PermissionMode {
|
|
1100
|
+
return this.toolManager.getPermissionMode();
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
/**
|
|
1104
|
+
* Set the permission mode
|
|
1105
|
+
* @param mode - The new permission mode
|
|
1106
|
+
*/
|
|
1107
|
+
public setPermissionMode(mode: PermissionMode): void {
|
|
1108
|
+
this.toolManager.setPermissionMode(mode);
|
|
1109
|
+
this.options.callbacks?.onPermissionModeChange?.(mode);
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
/**
|
|
1113
|
+
* Add a persistent permission rule
|
|
1114
|
+
* @param rule - The rule to add (e.g., "Bash(ls)")
|
|
1115
|
+
*/
|
|
1116
|
+
private async addPermissionRule(rule: string): Promise<void> {
|
|
1117
|
+
// 1. Update PermissionManager state
|
|
1118
|
+
const currentRules = this.permissionManager.getAllowedRules();
|
|
1119
|
+
if (!currentRules.includes(rule)) {
|
|
1120
|
+
this.permissionManager.updateAllowedRules([...currentRules, rule]);
|
|
1121
|
+
|
|
1122
|
+
// 2. Persist to settings.local.json
|
|
1123
|
+
try {
|
|
1124
|
+
await this.configurationService.addAllowedRule(this.workdir, rule);
|
|
1125
|
+
this.logger?.debug("Persistent permission rule added", { rule });
|
|
1126
|
+
} catch (error) {
|
|
1127
|
+
this.logger?.error("Failed to persist permission rule", {
|
|
1128
|
+
rule,
|
|
1129
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
626
1134
|
}
|