wave-agent-sdk 0.0.8 → 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 +92 -23
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +340 -137
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/managers/aiManager.d.ts +14 -36
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +74 -77
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +4 -3
- package/dist/managers/hookManager.d.ts +3 -8
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +39 -29
- package/dist/managers/liveConfigManager.d.ts +55 -18
- package/dist/managers/liveConfigManager.d.ts.map +1 -1
- package/dist/managers/liveConfigManager.js +372 -90
- 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 +8 -16
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +52 -74
- 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 +0 -1
- package/dist/managers/subagentManager.d.ts +8 -23
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +97 -117
- 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 +3 -1
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +123 -30
- 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.map +1 -1
- package/dist/services/fileWatcher.js +5 -6
- package/dist/services/hook.d.ts +7 -124
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +46 -458
- package/dist/services/jsonlHandler.d.ts +24 -15
- package/dist/services/jsonlHandler.d.ts.map +1 -1
- package/dist/services/jsonlHandler.js +67 -88
- package/dist/services/memory.d.ts +0 -9
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +2 -49
- package/dist/services/session.d.ts +82 -33
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +275 -181
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +72 -13
- package/dist/tools/deleteFileTool.d.ts.map +1 -1
- package/dist/tools/deleteFileTool.js +25 -0
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +30 -6
- 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 +26 -7
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +111 -2
- 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 +25 -9
- package/dist/types/commands.d.ts +0 -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 +10 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/environment.d.ts +41 -0
- package/dist/types/environment.d.ts.map +1 -1
- 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 +11 -2
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +1 -7
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +5 -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 +6 -11
- 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 +1 -6
- package/dist/types/session.d.ts.map +1 -1
- 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 +21 -4
- 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 +8 -33
- package/dist/utils/cacheControlUtils.d.ts.map +1 -1
- package/dist/utils/cacheControlUtils.js +83 -126
- package/dist/utils/constants.d.ts +0 -12
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +1 -13
- package/dist/utils/convertMessagesForAPI.d.ts +2 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +33 -14
- 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 +14 -2
- package/dist/utils/fileUtils.d.ts.map +1 -1
- package/dist/utils/fileUtils.js +101 -17
- package/dist/utils/globalLogger.d.ts +0 -14
- package/dist/utils/globalLogger.d.ts.map +1 -1
- package/dist/utils/globalLogger.js +0 -16
- 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/messageOperations.d.ts +1 -11
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +7 -24
- package/dist/utils/pathEncoder.d.ts +4 -0
- package/dist/utils/pathEncoder.d.ts.map +1 -1
- package/dist/utils/pathEncoder.js +16 -9
- package/dist/utils/subagentParser.d.ts +2 -2
- package/dist/utils/subagentParser.d.ts.map +1 -1
- package/dist/utils/subagentParser.js +10 -7
- 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 +5 -8
- package/src/agent.ts +460 -216
- package/src/index.ts +2 -0
- package/src/managers/aiManager.ts +107 -111
- package/src/managers/backgroundBashManager.ts +4 -3
- package/src/managers/hookManager.ts +44 -39
- package/src/managers/liveConfigManager.ts +524 -138
- package/src/managers/lspManager.ts +434 -0
- package/src/managers/messageManager.ts +73 -103
- package/src/managers/permissionManager.ts +276 -0
- package/src/managers/skillManager.ts +3 -1
- package/src/managers/slashCommandManager.ts +1 -2
- package/src/managers/subagentManager.ts +116 -159
- package/src/managers/toolManager.ts +95 -3
- package/src/services/aiService.ts +207 -26
- package/src/services/configurationService.ts +762 -0
- package/src/services/fileWatcher.ts +5 -6
- package/src/services/hook.ts +50 -631
- package/src/services/jsonlHandler.ts +84 -100
- package/src/services/memory.ts +2 -59
- package/src/services/session.ts +338 -213
- package/src/tools/bashTool.ts +89 -16
- package/src/tools/deleteFileTool.ts +36 -0
- package/src/tools/editTool.ts +41 -7
- package/src/tools/lspTool.ts +760 -0
- package/src/tools/multiEditTool.ts +37 -8
- package/src/tools/readTool.ts +125 -2
- 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 +36 -10
- package/src/types/commands.ts +0 -1
- package/src/types/config.ts +5 -0
- package/src/types/configuration.ts +73 -0
- package/src/types/core.ts +11 -0
- package/src/types/environment.ts +44 -0
- package/src/types/fileSearch.ts +4 -0
- package/src/types/hooks.ts +14 -11
- package/src/types/index.ts +5 -0
- package/src/types/lsp.ts +96 -0
- package/src/types/messaging.ts +8 -13
- package/src/types/permissions.ts +48 -0
- package/src/types/session.ts +3 -8
- 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 +28 -4
- package/src/utils/builtinSubagents.ts +71 -0
- package/src/utils/cacheControlUtils.ts +106 -171
- package/src/utils/constants.ts +1 -16
- package/src/utils/convertMessagesForAPI.ts +38 -14
- package/src/utils/fileSearch.ts +107 -0
- package/src/utils/fileUtils.ts +114 -19
- package/src/utils/globalLogger.ts +0 -17
- package/src/utils/largeOutputHandler.ts +55 -0
- package/src/utils/markdownParser.ts +1 -19
- package/src/utils/messageOperations.ts +7 -35
- package/src/utils/pathEncoder.ts +24 -9
- package/src/utils/subagentParser.ts +11 -8
- package/src/utils/tokenEstimator.ts +68 -0
- package/dist/constants/events.d.ts +0 -28
- package/dist/constants/events.d.ts.map +0 -1
- package/dist/constants/events.js +0 -27
- package/dist/services/configurationWatcher.d.ts +0 -120
- package/dist/services/configurationWatcher.d.ts.map +0 -1
- package/dist/services/configurationWatcher.js +0 -439
- package/dist/services/memoryStore.d.ts +0 -81
- package/dist/services/memoryStore.d.ts.map +0 -1
- package/dist/services/memoryStore.js +0 -200
- package/dist/types/memoryStore.d.ts +0 -82
- package/dist/types/memoryStore.d.ts.map +0 -1
- package/dist/types/memoryStore.js +0 -7
- package/dist/utils/configResolver.d.ts +0 -65
- package/dist/utils/configResolver.d.ts.map +0 -1
- package/dist/utils/configResolver.js +0 -210
- package/src/constants/events.ts +0 -38
- package/src/services/configurationWatcher.ts +0 -622
- package/src/services/memoryStore.ts +0 -279
- package/src/types/memoryStore.ts +0 -94
- package/src/utils/configResolver.ts +0 -302
package/src/agent.ts
CHANGED
|
@@ -10,13 +10,19 @@ import {
|
|
|
10
10
|
} from "./managers/subagentManager.js";
|
|
11
11
|
import * as memory from "./services/memory.js";
|
|
12
12
|
import { McpManager, type McpManagerCallbacks } from "./managers/mcpManager.js";
|
|
13
|
+
import { LspManager } from "./managers/lspManager.js";
|
|
13
14
|
import { BashManager } from "./managers/bashManager.js";
|
|
14
15
|
import {
|
|
15
16
|
BackgroundBashManager,
|
|
16
17
|
type BackgroundBashManagerCallbacks,
|
|
17
18
|
} from "./managers/backgroundBashManager.js";
|
|
18
19
|
import { SlashCommandManager } from "./managers/slashCommandManager.js";
|
|
19
|
-
import
|
|
20
|
+
import { PermissionManager } from "./managers/permissionManager.js";
|
|
21
|
+
import type {
|
|
22
|
+
SlashCommand,
|
|
23
|
+
CustomSlashCommand,
|
|
24
|
+
ILspManager,
|
|
25
|
+
} from "./types/index.js";
|
|
20
26
|
import type {
|
|
21
27
|
Message,
|
|
22
28
|
Logger,
|
|
@@ -24,17 +30,24 @@ import type {
|
|
|
24
30
|
GatewayConfig,
|
|
25
31
|
ModelConfig,
|
|
26
32
|
Usage,
|
|
33
|
+
PermissionMode,
|
|
34
|
+
PermissionCallback,
|
|
27
35
|
} from "./types/index.js";
|
|
28
36
|
import { HookManager } from "./managers/hookManager.js";
|
|
29
|
-
import { MemoryStoreService } from "./services/memoryStore.js";
|
|
30
|
-
import { initializeMemoryStore } from "./services/memory.js";
|
|
31
37
|
import { LiveConfigManager } from "./managers/liveConfigManager.js";
|
|
32
|
-
import { configResolver } from "./utils/configResolver.js";
|
|
33
38
|
import { configValidator } from "./utils/configValidator.js";
|
|
34
39
|
import { SkillManager } from "./managers/skillManager.js";
|
|
35
|
-
import {
|
|
40
|
+
import {
|
|
41
|
+
loadSessionFromJsonl,
|
|
42
|
+
handleSessionRestoration,
|
|
43
|
+
} from "./services/session.js";
|
|
36
44
|
import type { SubagentConfiguration } from "./utils/subagentParser.js";
|
|
37
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";
|
|
38
51
|
|
|
39
52
|
/**
|
|
40
53
|
* Configuration options for Agent instances
|
|
@@ -46,6 +59,9 @@ export interface AgentOptions {
|
|
|
46
59
|
// Optional configuration with environment fallbacks
|
|
47
60
|
apiKey?: string;
|
|
48
61
|
baseURL?: string;
|
|
62
|
+
defaultHeaders?: Record<string, string>;
|
|
63
|
+
fetchOptions?: ClientOptions["fetchOptions"];
|
|
64
|
+
fetch?: ClientOptions["fetch"];
|
|
49
65
|
agentModel?: string;
|
|
50
66
|
fastModel?: string;
|
|
51
67
|
tokenLimit?: number;
|
|
@@ -61,13 +77,23 @@ export interface AgentOptions {
|
|
|
61
77
|
workdir?: string;
|
|
62
78
|
/**Optional custom system prompt - if provided, replaces default system prompt */
|
|
63
79
|
systemPrompt?: string;
|
|
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;
|
|
64
88
|
}
|
|
65
89
|
|
|
66
90
|
export interface AgentCallbacks
|
|
67
91
|
extends MessageManagerCallbacks,
|
|
68
92
|
BackgroundBashManagerCallbacks,
|
|
69
93
|
McpManagerCallbacks,
|
|
70
|
-
SubagentManagerCallbacks {
|
|
94
|
+
SubagentManagerCallbacks {
|
|
95
|
+
onPermissionModeChange?: (mode: PermissionMode) => void;
|
|
96
|
+
}
|
|
71
97
|
|
|
72
98
|
export class Agent {
|
|
73
99
|
private messageManager: MessageManager;
|
|
@@ -78,26 +104,80 @@ export class Agent {
|
|
|
78
104
|
private logger?: Logger; // Add optional logger property
|
|
79
105
|
private toolManager: ToolManager; // Add tool registry instance
|
|
80
106
|
private mcpManager: McpManager; // Add MCP manager instance
|
|
107
|
+
private lspManager: ILspManager; // Add LSP manager instance
|
|
108
|
+
private permissionManager: PermissionManager; // Add permission manager instance
|
|
81
109
|
private subagentManager: SubagentManager; // Add subagent manager instance
|
|
82
110
|
private slashCommandManager: SlashCommandManager; // Add slash command manager instance
|
|
83
111
|
private hookManager: HookManager; // Add hooks manager instance
|
|
84
|
-
private memoryStore: MemoryStoreService; // Add memory store service
|
|
85
112
|
private liveConfigManager: LiveConfigManager; // Add live configuration manager
|
|
113
|
+
private configurationService: ConfigurationService; // Add configuration service
|
|
86
114
|
private workdir: string; // Working directory
|
|
87
115
|
private systemPrompt?: string; // Custom system prompt
|
|
88
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
|
+
}
|
|
89
173
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
private tokenLimit: number;
|
|
174
|
+
if (config.tokenLimit !== undefined) {
|
|
175
|
+
this.options.tokenLimit = config.tokenLimit;
|
|
176
|
+
}
|
|
94
177
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
private readonly constructorAgentModel?: string;
|
|
99
|
-
private readonly constructorFastModel?: string;
|
|
100
|
-
private readonly constructorTokenLimit?: number;
|
|
178
|
+
// Re-validate configuration after update
|
|
179
|
+
this.resolveAndValidateConfig();
|
|
180
|
+
}
|
|
101
181
|
|
|
102
182
|
/**
|
|
103
183
|
* Agent constructor - handles configuration resolution and validation
|
|
@@ -109,110 +189,43 @@ export class Agent {
|
|
|
109
189
|
* @param options - Configuration options for the Agent instance
|
|
110
190
|
*/
|
|
111
191
|
private constructor(options: AgentOptions) {
|
|
112
|
-
const {
|
|
113
|
-
|
|
114
|
-
|
|
192
|
+
const {
|
|
193
|
+
callbacks = {},
|
|
194
|
+
logger,
|
|
195
|
+
workdir,
|
|
196
|
+
systemPrompt,
|
|
197
|
+
stream = true,
|
|
198
|
+
} = options;
|
|
199
|
+
|
|
200
|
+
// Set working directory early as we need it for loading configuration
|
|
115
201
|
this.workdir = workdir || process.cwd();
|
|
116
202
|
|
|
117
|
-
//
|
|
118
|
-
this.
|
|
119
|
-
this.constructorBaseURL = options.baseURL;
|
|
120
|
-
this.constructorAgentModel = options.agentModel;
|
|
121
|
-
this.constructorFastModel = options.fastModel;
|
|
122
|
-
this.constructorTokenLimit = options.tokenLimit;
|
|
123
|
-
|
|
124
|
-
// Resolve configuration from constructor args and environment variables with live config support
|
|
125
|
-
const gatewayConfig = configResolver.resolveGatewayConfig(
|
|
126
|
-
options.apiKey,
|
|
127
|
-
options.baseURL,
|
|
128
|
-
this.workdir,
|
|
129
|
-
);
|
|
130
|
-
const modelConfig = configResolver.resolveModelConfig(
|
|
131
|
-
options.agentModel,
|
|
132
|
-
options.fastModel,
|
|
133
|
-
this.workdir,
|
|
134
|
-
);
|
|
135
|
-
const tokenLimit = configResolver.resolveTokenLimit(
|
|
136
|
-
options.tokenLimit,
|
|
137
|
-
this.workdir,
|
|
138
|
-
);
|
|
139
|
-
|
|
140
|
-
// Validate resolved configuration
|
|
141
|
-
configValidator.validateGatewayConfig(gatewayConfig);
|
|
142
|
-
configValidator.validateTokenLimit(tokenLimit);
|
|
143
|
-
configValidator.validateModelConfig(
|
|
144
|
-
modelConfig.agentModel,
|
|
145
|
-
modelConfig.fastModel,
|
|
146
|
-
);
|
|
203
|
+
// Initialize configuration service
|
|
204
|
+
this.configurationService = new ConfigurationService();
|
|
147
205
|
|
|
148
206
|
this.logger = logger; // Save the passed logger
|
|
149
207
|
this.systemPrompt = systemPrompt; // Save custom system prompt
|
|
208
|
+
this.stream = stream; // Save streaming mode flag
|
|
150
209
|
|
|
151
|
-
//
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
// Store resolved configuration
|
|
155
|
-
this.gatewayConfig = gatewayConfig;
|
|
156
|
-
this.modelConfig = modelConfig;
|
|
157
|
-
this.tokenLimit = tokenLimit;
|
|
210
|
+
// Store options for dynamic configuration resolution
|
|
211
|
+
this.options = options;
|
|
158
212
|
|
|
159
213
|
this.backgroundBashManager = new BackgroundBashManager({
|
|
160
214
|
callbacks,
|
|
161
215
|
workdir: this.workdir,
|
|
162
216
|
});
|
|
163
217
|
this.mcpManager = new McpManager({ callbacks, logger: this.logger }); // Initialize MCP manager
|
|
164
|
-
this.
|
|
165
|
-
|
|
166
|
-
logger: this.logger,
|
|
167
|
-
}); // Initialize tool registry, pass MCP manager
|
|
218
|
+
this.lspManager =
|
|
219
|
+
options.lspManager || new LspManager({ logger: this.logger }); // Initialize LSP manager
|
|
168
220
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
this.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
logger: this.logger,
|
|
175
|
-
onConfigurationChanged: () => {
|
|
176
|
-
// Update Agent configuration (AIManager, SubagentManager)
|
|
177
|
-
this.updateConfiguration();
|
|
221
|
+
// Initialize permission manager
|
|
222
|
+
this.permissionManager = new PermissionManager({ logger: this.logger });
|
|
223
|
+
this.permissionManager.setOnConfiguredDefaultModeChange((mode) => {
|
|
224
|
+
this.options.callbacks?.onPermissionModeChange?.(mode);
|
|
225
|
+
});
|
|
178
226
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
this.hookManager.loadConfigurationFromSettings();
|
|
182
|
-
this.logger?.info(
|
|
183
|
-
"Live Config: Hook configuration reloaded successfully",
|
|
184
|
-
);
|
|
185
|
-
} catch (error) {
|
|
186
|
-
this.logger?.error(
|
|
187
|
-
`Live Config: Failed to reload hook configuration: ${(error as Error).message}`,
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
},
|
|
191
|
-
onMemoryStoreFileChanged: async (
|
|
192
|
-
filePath: string,
|
|
193
|
-
changeType: "add" | "change" | "unlink",
|
|
194
|
-
) => {
|
|
195
|
-
try {
|
|
196
|
-
if (changeType === "unlink") {
|
|
197
|
-
// Handle file deletion gracefully
|
|
198
|
-
this.memoryStore.removeContent(filePath);
|
|
199
|
-
this.logger?.info(
|
|
200
|
-
"Live Config: Removed AGENTS.md from memory store due to file deletion",
|
|
201
|
-
);
|
|
202
|
-
} else {
|
|
203
|
-
// Update memory store content for add/change
|
|
204
|
-
await this.memoryStore.updateContent(filePath);
|
|
205
|
-
this.logger?.info(
|
|
206
|
-
"Live Config: Updated AGENTS.md content in memory store",
|
|
207
|
-
);
|
|
208
|
-
}
|
|
209
|
-
} catch (error) {
|
|
210
|
-
this.logger?.error(
|
|
211
|
-
`Live Config: Failed to update memory store: ${(error as Error).message}`,
|
|
212
|
-
);
|
|
213
|
-
}
|
|
214
|
-
},
|
|
215
|
-
}); // Initialize live configuration manager
|
|
227
|
+
// Initialize configuration service and hooks manager
|
|
228
|
+
this.hookManager = new HookManager(this.workdir, undefined, this.logger); // Initialize hooks manager
|
|
216
229
|
|
|
217
230
|
// Initialize MessageManager
|
|
218
231
|
this.messageManager = new MessageManager({
|
|
@@ -221,6 +234,65 @@ export class Agent {
|
|
|
221
234
|
logger: this.logger,
|
|
222
235
|
});
|
|
223
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
|
+
|
|
224
296
|
// Initialize subagent manager with all dependencies in constructor
|
|
225
297
|
// IMPORTANT: Must be initialized AFTER MessageManager
|
|
226
298
|
this.subagentManager = new SubagentManager({
|
|
@@ -233,13 +305,15 @@ export class Agent {
|
|
|
233
305
|
callbacks.onSubagentAssistantMessageAdded,
|
|
234
306
|
onSubagentAssistantContentUpdated:
|
|
235
307
|
callbacks.onSubagentAssistantContentUpdated,
|
|
308
|
+
onSubagentAssistantReasoningUpdated:
|
|
309
|
+
callbacks.onSubagentAssistantReasoningUpdated,
|
|
236
310
|
onSubagentToolBlockUpdated: callbacks.onSubagentToolBlockUpdated,
|
|
237
311
|
onSubagentMessagesChange: callbacks.onSubagentMessagesChange,
|
|
238
312
|
}, // Pass subagent callbacks for forwarding
|
|
239
313
|
logger: this.logger,
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
314
|
+
getGatewayConfig: () => this.getGatewayConfig(),
|
|
315
|
+
getModelConfig: () => this.getModelConfig(),
|
|
316
|
+
getTokenLimit: () => this.getTokenLimit(),
|
|
243
317
|
hookManager: this.hookManager,
|
|
244
318
|
onUsageAdded: (usage) => this.addUsage(usage),
|
|
245
319
|
});
|
|
@@ -259,9 +333,11 @@ export class Agent {
|
|
|
259
333
|
},
|
|
260
334
|
workdir: this.workdir,
|
|
261
335
|
systemPrompt: this.systemPrompt,
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
|
265
341
|
});
|
|
266
342
|
|
|
267
343
|
// Initialize command manager
|
|
@@ -300,9 +376,9 @@ export class Agent {
|
|
|
300
376
|
* Rebuild usage array from messages containing usage metadata
|
|
301
377
|
* Called during session restoration to reconstruct usage tracking
|
|
302
378
|
*/
|
|
303
|
-
private rebuildUsageFromMessages(): void {
|
|
379
|
+
private rebuildUsageFromMessages(messages: Message[]): void {
|
|
304
380
|
this._usages = [];
|
|
305
|
-
|
|
381
|
+
messages.forEach((message) => {
|
|
306
382
|
if (message.role === "assistant" && message.usage) {
|
|
307
383
|
this._usages.push(message.usage);
|
|
308
384
|
}
|
|
@@ -333,9 +409,29 @@ export class Agent {
|
|
|
333
409
|
return this.workdir;
|
|
334
410
|
}
|
|
335
411
|
|
|
336
|
-
/** Get
|
|
337
|
-
public get
|
|
338
|
-
return this.
|
|
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;
|
|
339
435
|
}
|
|
340
436
|
|
|
341
437
|
/** Get AI loading status */
|
|
@@ -384,6 +480,9 @@ export class Agent {
|
|
|
384
480
|
* @param options - Configuration options for the Agent instance
|
|
385
481
|
* @param options.apiKey - API key for the AI service (or set WAVE_API_KEY env var)
|
|
386
482
|
* @param options.baseURL - Base URL for the AI service (or set WAVE_BASE_URL env var)
|
|
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
|
|
387
486
|
* @param options.callbacks - Optional callbacks for various Agent events
|
|
388
487
|
* @param options.restoreSessionId - Optional session ID to restore from
|
|
389
488
|
* @param options.continueLastSession - Whether to continue the last session automatically
|
|
@@ -403,7 +502,7 @@ export class Agent {
|
|
|
403
502
|
* ```
|
|
404
503
|
*/
|
|
405
504
|
static async create(options: AgentOptions): Promise<Agent> {
|
|
406
|
-
// Create Agent instance
|
|
505
|
+
// Create Agent instance
|
|
407
506
|
const instance = new Agent(options);
|
|
408
507
|
await instance.initialize({
|
|
409
508
|
restoreSessionId: options.restoreSessionId,
|
|
@@ -413,6 +512,27 @@ export class Agent {
|
|
|
413
512
|
return instance;
|
|
414
513
|
}
|
|
415
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
|
+
|
|
416
536
|
/** Private initialization method, handles async initialization logic */
|
|
417
537
|
private async initialize(options?: {
|
|
418
538
|
restoreSessionId?: string;
|
|
@@ -422,7 +542,10 @@ export class Agent {
|
|
|
422
542
|
// Initialize managers first
|
|
423
543
|
try {
|
|
424
544
|
// Initialize SkillManager
|
|
425
|
-
const skillManager = new SkillManager({
|
|
545
|
+
const skillManager = new SkillManager({
|
|
546
|
+
logger: this.logger,
|
|
547
|
+
workdir: this.workdir,
|
|
548
|
+
});
|
|
426
549
|
await skillManager.initialize();
|
|
427
550
|
|
|
428
551
|
// Initialize SubagentManager (load and cache configurations)
|
|
@@ -441,6 +564,9 @@ export class Agent {
|
|
|
441
564
|
// Initialize MCP servers with auto-connect
|
|
442
565
|
try {
|
|
443
566
|
await this.mcpManager.initialize(this.workdir, true);
|
|
567
|
+
if (this.lspManager instanceof LspManager) {
|
|
568
|
+
await this.lspManager.initialize(this.workdir);
|
|
569
|
+
}
|
|
444
570
|
} catch (error) {
|
|
445
571
|
this.logger?.error("Failed to initialize MCP servers:", error);
|
|
446
572
|
// Don't throw error to prevent app startup failure
|
|
@@ -448,20 +574,58 @@ export class Agent {
|
|
|
448
574
|
|
|
449
575
|
// Initialize hooks configuration
|
|
450
576
|
try {
|
|
451
|
-
// Load hooks configuration
|
|
577
|
+
// Load hooks configuration using ConfigurationService
|
|
452
578
|
this.logger?.debug("Loading hooks configuration...");
|
|
453
|
-
|
|
579
|
+
const configResult =
|
|
580
|
+
await this.configurationService.loadMergedConfiguration(this.workdir);
|
|
581
|
+
|
|
582
|
+
this.hookManager.loadConfigurationFromWaveConfig(
|
|
583
|
+
configResult.configuration,
|
|
584
|
+
);
|
|
454
585
|
this.logger?.debug("Hooks system initialized successfully");
|
|
455
586
|
} catch (error) {
|
|
456
587
|
this.logger?.error("Failed to initialize hooks system:", error);
|
|
457
588
|
// Don't throw error to prevent app startup failure
|
|
458
589
|
}
|
|
459
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
|
+
|
|
460
597
|
// Initialize live configuration reload
|
|
461
598
|
try {
|
|
462
599
|
this.logger?.debug("Initializing live configuration reload...");
|
|
463
600
|
await this.liveConfigManager.initialize();
|
|
464
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
|
+
}
|
|
465
629
|
} catch (error) {
|
|
466
630
|
this.logger?.error(
|
|
467
631
|
"Failed to initialize live configuration reload:",
|
|
@@ -470,23 +634,69 @@ export class Agent {
|
|
|
470
634
|
// Don't throw error to prevent app startup failure - continue without live reload
|
|
471
635
|
}
|
|
472
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
|
+
|
|
473
679
|
// Handle session restoration or set provided messages
|
|
474
680
|
if (options?.messages) {
|
|
475
681
|
// If messages are provided, use them directly (useful for testing)
|
|
476
682
|
this.messageManager.setMessages(options.messages);
|
|
477
683
|
// Rebuild usage array from restored messages
|
|
478
|
-
this.rebuildUsageFromMessages();
|
|
684
|
+
this.rebuildUsageFromMessages(options.messages);
|
|
479
685
|
} else {
|
|
480
686
|
// Otherwise, handle session restoration
|
|
481
|
-
await
|
|
687
|
+
const sessionToRestore = await handleSessionRestoration(
|
|
482
688
|
options?.restoreSessionId,
|
|
483
689
|
options?.continueLastSession,
|
|
690
|
+
this.messageManager.getWorkdir(),
|
|
484
691
|
);
|
|
485
692
|
// Rebuild usage array from restored messages
|
|
486
|
-
this.rebuildUsageFromMessages();
|
|
693
|
+
this.rebuildUsageFromMessages(sessionToRestore?.messages || []);
|
|
487
694
|
|
|
488
695
|
// After main session is restored, restore any associated subagent sessions
|
|
489
|
-
await this.restoreSubagentSessions();
|
|
696
|
+
await this.restoreSubagentSessions(sessionToRestore?.messages || []);
|
|
697
|
+
|
|
698
|
+
if (sessionToRestore)
|
|
699
|
+
this.messageManager.initializeFromSession(sessionToRestore);
|
|
490
700
|
}
|
|
491
701
|
}
|
|
492
702
|
|
|
@@ -494,10 +704,10 @@ export class Agent {
|
|
|
494
704
|
* Restore subagent sessions associated with the current main session
|
|
495
705
|
* This method is called after the main session is restored to load any subagent sessions
|
|
496
706
|
*/
|
|
497
|
-
private async restoreSubagentSessions(): Promise<void> {
|
|
707
|
+
private async restoreSubagentSessions(messages: Message[]): Promise<void> {
|
|
498
708
|
try {
|
|
499
709
|
// Only attempt to restore subagent sessions if we have messages (session was restored)
|
|
500
|
-
if (
|
|
710
|
+
if (messages.length === 0) {
|
|
501
711
|
return;
|
|
502
712
|
}
|
|
503
713
|
|
|
@@ -507,7 +717,7 @@ export class Agent {
|
|
|
507
717
|
{ subagentId: string; configuration: SubagentConfiguration }
|
|
508
718
|
>(); // sessionId -> { subagentId, configuration }
|
|
509
719
|
|
|
510
|
-
for (const message of
|
|
720
|
+
for (const message of messages) {
|
|
511
721
|
if (message.role === "assistant" && message.blocks) {
|
|
512
722
|
for (const block of message.blocks) {
|
|
513
723
|
if (
|
|
@@ -536,6 +746,7 @@ export class Agent {
|
|
|
536
746
|
const sessionData = await loadSessionFromJsonl(
|
|
537
747
|
sessionId,
|
|
538
748
|
this.messageManager.getWorkdir(),
|
|
749
|
+
"subagent",
|
|
539
750
|
);
|
|
540
751
|
if (sessionData) {
|
|
541
752
|
subagentSessions.push({
|
|
@@ -568,6 +779,48 @@ export class Agent {
|
|
|
568
779
|
}
|
|
569
780
|
}
|
|
570
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
|
+
|
|
571
824
|
public abortAIMessage(): void {
|
|
572
825
|
this.aiManager.abortAIMessage();
|
|
573
826
|
}
|
|
@@ -616,6 +869,10 @@ export class Agent {
|
|
|
616
869
|
this.backgroundBashManager.cleanup();
|
|
617
870
|
// Cleanup MCP connections
|
|
618
871
|
await this.mcpManager.cleanup();
|
|
872
|
+
// Cleanup LSP connections
|
|
873
|
+
if (this.lspManager instanceof LspManager) {
|
|
874
|
+
await this.lspManager.cleanup();
|
|
875
|
+
}
|
|
619
876
|
// Cleanup subagent manager
|
|
620
877
|
this.subagentManager.cleanup();
|
|
621
878
|
// Cleanup live configuration reload
|
|
@@ -628,14 +885,34 @@ export class Agent {
|
|
|
628
885
|
);
|
|
629
886
|
}
|
|
630
887
|
// Cleanup memory store
|
|
631
|
-
try {
|
|
632
|
-
this.memoryStore.clear();
|
|
633
|
-
this.logger?.debug("Memory store cleared successfully");
|
|
634
|
-
} catch (error) {
|
|
635
|
-
this.logger?.error("Error clearing memory store:", error);
|
|
636
|
-
}
|
|
637
888
|
}
|
|
638
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
|
+
*/
|
|
639
916
|
public async sendMessage(
|
|
640
917
|
content: string,
|
|
641
918
|
images?: Array<{ path: string; mimeType: string }>,
|
|
@@ -690,6 +967,7 @@ export class Agent {
|
|
|
690
967
|
transcriptPath: this.messageManager.getTranscriptPath(),
|
|
691
968
|
cwd: this.workdir,
|
|
692
969
|
userPrompt: content,
|
|
970
|
+
env: this.configurationService.getEnvironmentVars(), // Include configuration environment variables
|
|
693
971
|
},
|
|
694
972
|
);
|
|
695
973
|
|
|
@@ -728,16 +1006,25 @@ export class Agent {
|
|
|
728
1006
|
type: "project" | "user",
|
|
729
1007
|
): Promise<void> {
|
|
730
1008
|
try {
|
|
1009
|
+
// Ensure the message starts with # for memory functions
|
|
1010
|
+
const formattedMessage = message.startsWith("#")
|
|
1011
|
+
? message
|
|
1012
|
+
: `#${message}`;
|
|
1013
|
+
|
|
731
1014
|
if (type === "project") {
|
|
732
|
-
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);
|
|
733
1018
|
} else {
|
|
734
|
-
await memory.addUserMemory(
|
|
1019
|
+
await memory.addUserMemory(formattedMessage);
|
|
1020
|
+
// Update internal state after successful save
|
|
1021
|
+
this._userMemoryContent = await memory.getUserMemoryContent();
|
|
735
1022
|
}
|
|
736
1023
|
|
|
737
1024
|
// Add successful MemoryBlock to the last assistant message
|
|
738
1025
|
const memoryText = message.substring(1).trim();
|
|
739
1026
|
const typeLabel = type === "project" ? "Project Memory" : "User Memory";
|
|
740
|
-
const storagePath =
|
|
1027
|
+
const storagePath = "AGENTS.md";
|
|
741
1028
|
|
|
742
1029
|
this.messageManager.addMemoryBlock(
|
|
743
1030
|
`${typeLabel}: ${memoryText}`,
|
|
@@ -747,13 +1034,14 @@ export class Agent {
|
|
|
747
1034
|
);
|
|
748
1035
|
} catch (error) {
|
|
749
1036
|
// Add failed MemoryBlock to the last assistant message
|
|
1037
|
+
const memoryText = message.substring(1).trim();
|
|
750
1038
|
const typeLabel = type === "project" ? "Project Memory" : "User Memory";
|
|
751
|
-
const storagePath =
|
|
1039
|
+
const storagePath = "AGENTS.md";
|
|
1040
|
+
const errorMessage =
|
|
1041
|
+
error instanceof Error ? error.message : String(error);
|
|
752
1042
|
|
|
753
1043
|
this.messageManager.addMemoryBlock(
|
|
754
|
-
`${typeLabel}
|
|
755
|
-
error instanceof Error ? error.message : String(error)
|
|
756
|
-
}`,
|
|
1044
|
+
`${typeLabel}: ${memoryText} - Error: ${errorMessage}`,
|
|
757
1045
|
false,
|
|
758
1046
|
type,
|
|
759
1047
|
storagePath,
|
|
@@ -805,86 +1093,42 @@ export class Agent {
|
|
|
805
1093
|
return this.slashCommandManager.getCustomCommands();
|
|
806
1094
|
}
|
|
807
1095
|
|
|
808
|
-
// ========== Live Configuration Management ==========
|
|
809
|
-
|
|
810
1096
|
/**
|
|
811
|
-
*
|
|
812
|
-
* This method refreshes all configuration-dependent components with new values
|
|
813
|
-
* Note: Constructor values still take precedence over live configuration
|
|
1097
|
+
* Get the current permission mode
|
|
814
1098
|
*/
|
|
815
|
-
public
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
"Live Config: Updating Agent configuration from live settings",
|
|
819
|
-
);
|
|
820
|
-
|
|
821
|
-
// Re-resolve configuration with current workdir, preserving constructor overrides
|
|
822
|
-
// We need to track what was explicitly provided in constructor vs. what should use live config
|
|
823
|
-
const newGatewayConfig = configResolver.resolveGatewayConfig(
|
|
824
|
-
this.constructorApiKey, // Preserve constructor override if provided
|
|
825
|
-
this.constructorBaseURL, // Preserve constructor override if provided
|
|
826
|
-
this.workdir,
|
|
827
|
-
);
|
|
828
|
-
const newModelConfig = configResolver.resolveModelConfig(
|
|
829
|
-
this.constructorAgentModel, // Preserve constructor override if provided
|
|
830
|
-
this.constructorFastModel, // Preserve constructor override if provided
|
|
831
|
-
this.workdir,
|
|
832
|
-
);
|
|
833
|
-
const newTokenLimit = configResolver.resolveTokenLimit(
|
|
834
|
-
this.constructorTokenLimit,
|
|
835
|
-
this.workdir,
|
|
836
|
-
);
|
|
837
|
-
|
|
838
|
-
// Validate new configuration
|
|
839
|
-
configValidator.validateGatewayConfig(newGatewayConfig);
|
|
840
|
-
configValidator.validateTokenLimit(newTokenLimit);
|
|
841
|
-
configValidator.validateModelConfig(
|
|
842
|
-
newModelConfig.agentModel,
|
|
843
|
-
newModelConfig.fastModel,
|
|
844
|
-
);
|
|
845
|
-
|
|
846
|
-
// Update stored configuration
|
|
847
|
-
this.gatewayConfig = newGatewayConfig;
|
|
848
|
-
this.modelConfig = newModelConfig;
|
|
849
|
-
this.tokenLimit = newTokenLimit;
|
|
850
|
-
|
|
851
|
-
// Update AIManager with new configuration
|
|
852
|
-
this.aiManager.updateConfiguration(
|
|
853
|
-
newGatewayConfig,
|
|
854
|
-
newModelConfig,
|
|
855
|
-
newTokenLimit,
|
|
856
|
-
);
|
|
857
|
-
|
|
858
|
-
// Update SubagentManager with new configuration
|
|
859
|
-
this.subagentManager.updateConfiguration(
|
|
860
|
-
newGatewayConfig,
|
|
861
|
-
newModelConfig,
|
|
862
|
-
newTokenLimit,
|
|
863
|
-
);
|
|
1099
|
+
public getPermissionMode(): PermissionMode {
|
|
1100
|
+
return this.toolManager.getPermissionMode();
|
|
1101
|
+
}
|
|
864
1102
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
// Don't throw - continue with previous configuration
|
|
873
|
-
}
|
|
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);
|
|
874
1110
|
}
|
|
875
1111
|
|
|
876
1112
|
/**
|
|
877
|
-
*
|
|
1113
|
+
* Add a persistent permission rule
|
|
1114
|
+
* @param rule - The rule to add (e.g., "Bash(ls)")
|
|
878
1115
|
*/
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
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
|
+
}
|
|
889
1133
|
}
|
|
890
1134
|
}
|