wave-agent-sdk 1.0.4 → 1.0.6
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 +23 -1
- package/dist/agent.js +34 -4
- package/dist/managers/aiManager.d.ts +36 -0
- package/dist/managers/aiManager.js +240 -8
- package/dist/managers/messageManager.d.ts +1 -3
- package/dist/managers/messageManager.js +19 -9
- package/dist/managers/slashCommandManager.js +28 -0
- package/dist/managers/subagentManager.d.ts +0 -2
- package/dist/services/session.js +2 -9
- package/dist/telemetry/instrumentation.d.ts +1 -1
- package/dist/telemetry/instrumentation.js +57 -28
- package/dist/tools/bashTool.js +16 -6
- package/dist/tools/grepTool.js +11 -3
- package/dist/types/index.d.ts +3 -0
- package/dist/types/messaging.d.ts +2 -0
- package/dist/utils/containerSetup.js +0 -3
- package/dist/utils/messageOperations.d.ts +10 -1
- package/dist/utils/messageOperations.js +19 -1
- package/dist/utils/notificationXml.js +5 -0
- package/dist/utils/ripgrep.d.ts +4 -4
- package/dist/utils/ripgrep.js +4 -27
- package/package.json +20 -8
- package/bin/rg +0 -79
- package/dist/managers/forkedAgentManager.d.ts +0 -50
- package/dist/managers/forkedAgentManager.js +0 -130
- package/scripts/install_ripgrep.js +0 -111
- package/scripts/postinstall.js +0 -38
- package/src/agent.ts +0 -1271
- package/src/constants/subagents.ts +0 -4
- package/src/constants/toolLimits.ts +0 -15
- package/src/constants/tools.ts +0 -24
- package/src/core/plugin.ts +0 -237
- package/src/core/session.ts +0 -9
- package/src/index.ts +0 -38
- package/src/managers/MemoryRuleManager.ts +0 -198
- package/src/managers/aiManager.ts +0 -2429
- package/src/managers/backgroundTaskManager.ts +0 -480
- package/src/managers/bangManager.ts +0 -119
- package/src/managers/cronManager.ts +0 -401
- package/src/managers/foregroundTaskManager.ts +0 -30
- package/src/managers/forkedAgentManager.ts +0 -216
- package/src/managers/hookManager.ts +0 -1089
- package/src/managers/liveConfigManager.ts +0 -445
- package/src/managers/lspManager.ts +0 -470
- package/src/managers/mcpManager.ts +0 -1010
- package/src/managers/messageManager.ts +0 -1180
- package/src/managers/messageQueue.ts +0 -157
- package/src/managers/permissionManager.ts +0 -1140
- package/src/managers/planManager.ts +0 -112
- package/src/managers/pluginManager.ts +0 -330
- package/src/managers/pluginScopeManager.ts +0 -124
- package/src/managers/reversionManager.ts +0 -178
- package/src/managers/skillManager.ts +0 -578
- package/src/managers/slashCommandManager.ts +0 -564
- package/src/managers/subagentManager.ts +0 -915
- package/src/managers/toolManager.ts +0 -489
- package/src/managers/workflowManager.ts +0 -493
- package/src/prompts/autoMemory.ts +0 -33
- package/src/prompts/autoMemoryExtraction.ts +0 -146
- package/src/prompts/index.ts +0 -506
- package/src/prompts/planModeReminders.ts +0 -126
- package/src/services/GitService.ts +0 -131
- package/src/services/MarketplaceService.ts +0 -1052
- package/src/services/MemoryRuleService.ts +0 -71
- package/src/services/aiService.ts +0 -919
- package/src/services/authService.ts +0 -565
- package/src/services/autoMemoryService.ts +0 -280
- package/src/services/configurationService.ts +0 -1520
- package/src/services/fileWatcher.ts +0 -319
- package/src/services/hook.ts +0 -348
- package/src/services/initializationService.ts +0 -357
- package/src/services/interactionService.ts +0 -229
- package/src/services/jsonlHandler.ts +0 -295
- package/src/services/memory.ts +0 -234
- package/src/services/pluginLoader.ts +0 -252
- package/src/services/remoteSettingsService.ts +0 -366
- package/src/services/reversionService.ts +0 -122
- package/src/services/session.ts +0 -922
- package/src/services/taskManager.ts +0 -321
- package/src/telemetry/events.ts +0 -65
- package/src/telemetry/instrumentation.ts +0 -499
- package/src/telemetry/sessionTracing.ts +0 -348
- package/src/tools/agentTool.ts +0 -322
- package/src/tools/askUserQuestion.ts +0 -160
- package/src/tools/bashTool.ts +0 -621
- package/src/tools/buildTool.ts +0 -61
- package/src/tools/cronCreateTool.ts +0 -161
- package/src/tools/cronDeleteTool.ts +0 -51
- package/src/tools/cronListTool.ts +0 -47
- package/src/tools/editTool.ts +0 -313
- package/src/tools/enterPlanMode.ts +0 -124
- package/src/tools/enterWorktreeTool.ts +0 -190
- package/src/tools/exitPlanMode.ts +0 -139
- package/src/tools/exitWorktreeTool.ts +0 -236
- package/src/tools/globTool.ts +0 -167
- package/src/tools/grepTool.ts +0 -399
- package/src/tools/lspTool.ts +0 -883
- package/src/tools/readTool.ts +0 -426
- package/src/tools/skillTool.ts +0 -248
- package/src/tools/taskManagementTools.ts +0 -574
- package/src/tools/taskStopTool.ts +0 -78
- package/src/tools/types.ts +0 -137
- package/src/tools/webFetchTool.ts +0 -373
- package/src/tools/workflowTool.ts +0 -205
- package/src/tools/writeTool.ts +0 -267
- package/src/types/agent.ts +0 -128
- package/src/types/auth.ts +0 -19
- package/src/types/commands.ts +0 -30
- package/src/types/config.ts +0 -43
- package/src/types/configuration.ts +0 -168
- package/src/types/core.ts +0 -105
- package/src/types/cron.ts +0 -13
- package/src/types/environment.ts +0 -106
- package/src/types/fileSearch.ts +0 -4
- package/src/types/history.ts +0 -7
- package/src/types/hooks.ts +0 -256
- package/src/types/index.ts +0 -41
- package/src/types/lsp.ts +0 -98
- package/src/types/marketplace.ts +0 -71
- package/src/types/mcp.ts +0 -43
- package/src/types/memoryRule.ts +0 -31
- package/src/types/messaging.ts +0 -114
- package/src/types/permissions.ts +0 -80
- package/src/types/plugins.ts +0 -39
- package/src/types/processes.ts +0 -99
- package/src/types/reversion.ts +0 -29
- package/src/types/session.ts +0 -12
- package/src/types/skills.ts +0 -108
- package/src/types/tasks.ts +0 -13
- package/src/types/telemetry.ts +0 -98
- package/src/types/tools.ts +0 -44
- package/src/types/workflow.ts +0 -6
- package/src/utils/abortUtils.ts +0 -118
- package/src/utils/atomicWrite.ts +0 -61
- package/src/utils/bashParser.ts +0 -899
- package/src/utils/cacheControlUtils.ts +0 -426
- package/src/utils/commandArgumentParser.ts +0 -161
- package/src/utils/commandPathResolver.ts +0 -88
- package/src/utils/configPaths.ts +0 -220
- package/src/utils/configValidator.ts +0 -100
- package/src/utils/constants.ts +0 -39
- package/src/utils/container.ts +0 -92
- package/src/utils/containerSetup.ts +0 -371
- package/src/utils/convertMessagesForAPI.ts +0 -326
- package/src/utils/cronTasks.ts +0 -128
- package/src/utils/cronTasksLock.ts +0 -182
- package/src/utils/cronToHuman.ts +0 -99
- package/src/utils/customCommands.ts +0 -95
- package/src/utils/editUtils.ts +0 -20
- package/src/utils/fileFormat.ts +0 -40
- package/src/utils/fileSearch.ts +0 -151
- package/src/utils/fileUtils.ts +0 -223
- package/src/utils/gitUtils.ts +0 -315
- package/src/utils/globalLogger.ts +0 -128
- package/src/utils/groupMessagesByApiRound.ts +0 -121
- package/src/utils/hookMatcher.ts +0 -176
- package/src/utils/markdownParser.ts +0 -317
- package/src/utils/mcpUtils.ts +0 -138
- package/src/utils/messageOperations.ts +0 -641
- package/src/utils/modelCapabilities.ts +0 -30
- package/src/utils/nameGenerator.ts +0 -99
- package/src/utils/notificationXml.ts +0 -57
- package/src/utils/openaiClient.ts +0 -251
- package/src/utils/parseCronExpression.ts +0 -78
- package/src/utils/path.ts +0 -72
- package/src/utils/pathEncoder.ts +0 -400
- package/src/utils/pathSafety.ts +0 -40
- package/src/utils/promptHistory.ts +0 -168
- package/src/utils/ripgrep.ts +0 -35
- package/src/utils/shellResolver.ts +0 -190
- package/src/utils/skillParser.ts +0 -246
- package/src/utils/stringUtils.ts +0 -156
- package/src/utils/subagentParser.ts +0 -279
- package/src/utils/taskReminder.ts +0 -96
- package/src/utils/tokenCalculation.ts +0 -43
- package/src/utils/tokenEstimate.ts +0 -34
- package/src/utils/toolResultStorage.ts +0 -117
- package/src/utils/worktreeSession.ts +0 -26
- package/src/utils/worktreeUtils.ts +0 -786
- package/src/workflow/budgetTracker.ts +0 -34
- package/src/workflow/concurrencyLimiter.ts +0 -47
- package/src/workflow/journal.ts +0 -95
- package/src/workflow/progressReporter.ts +0 -141
- package/src/workflow/runState.ts +0 -65
- package/src/workflow/scriptRuntime.ts +0 -274
- package/src/workflow/structuredOutput.ts +0 -123
- package/src/workflow/types.ts +0 -101
- package/src/workflow/workflowApis.ts +0 -410
- package/vendor/ripgrep/linux-aarch64/rg +0 -0
- package/vendor/ripgrep/linux-x86_64/rg +0 -0
- package/vendor/ripgrep/macos-aarch64/rg +0 -0
- package/vendor/ripgrep/macos-x86_64/rg +0 -0
- package/vendor/ripgrep/windows-aarch64/rg.exe +0 -0
- package/vendor/ripgrep/windows-x86_64/rg.exe +0 -0
package/src/agent.ts
DELETED
|
@@ -1,1271 +0,0 @@
|
|
|
1
|
-
import { ForegroundTaskManager } from "./managers/foregroundTaskManager.js";
|
|
2
|
-
import { MessageManager } from "./managers/messageManager.js";
|
|
3
|
-
import { AIManager } from "./managers/aiManager.js";
|
|
4
|
-
import { ToolManager } from "./managers/toolManager.js";
|
|
5
|
-
import { SubagentManager } from "./managers/subagentManager.js";
|
|
6
|
-
import { ForkedAgentManager } from "./managers/forkedAgentManager.js";
|
|
7
|
-
import { McpManager } from "./managers/mcpManager.js";
|
|
8
|
-
import { LspManager } from "./managers/lspManager.js";
|
|
9
|
-
import { BangManager } from "./managers/bangManager.js";
|
|
10
|
-
import { CronManager } from "./managers/cronManager.js";
|
|
11
|
-
import { BackgroundTaskManager } from "./managers/backgroundTaskManager.js";
|
|
12
|
-
import { MessageQueue, type QueuedMessage } from "./managers/messageQueue.js";
|
|
13
|
-
import { SlashCommandManager } from "./managers/slashCommandManager.js";
|
|
14
|
-
import { PluginManager } from "./managers/pluginManager.js";
|
|
15
|
-
import { HookManager } from "./managers/hookManager.js";
|
|
16
|
-
import { ReversionManager } from "./managers/reversionManager.js";
|
|
17
|
-
import { PermissionManager } from "./managers/permissionManager.js";
|
|
18
|
-
import { PlanManager } from "./managers/planManager.js";
|
|
19
|
-
import {
|
|
20
|
-
SlashCommand,
|
|
21
|
-
CustomSlashCommand,
|
|
22
|
-
ILspManager,
|
|
23
|
-
AgentOptions,
|
|
24
|
-
} from "./types/index.js";
|
|
25
|
-
import type {
|
|
26
|
-
Message,
|
|
27
|
-
Logger,
|
|
28
|
-
McpServerStatus,
|
|
29
|
-
GatewayConfig,
|
|
30
|
-
ModelConfig,
|
|
31
|
-
Usage,
|
|
32
|
-
PermissionMode,
|
|
33
|
-
ForegroundTask,
|
|
34
|
-
} from "./types/index.js";
|
|
35
|
-
import { MemoryRuleManager } from "./managers/MemoryRuleManager.js";
|
|
36
|
-
import { LiveConfigManager } from "./managers/liveConfigManager.js";
|
|
37
|
-
import { configValidator } from "./utils/configValidator.js";
|
|
38
|
-
import { SkillManager } from "./managers/skillManager.js";
|
|
39
|
-
import { TaskManager } from "./services/taskManager.js";
|
|
40
|
-
import type { WorktreeSession } from "./utils/worktreeSession.js";
|
|
41
|
-
import path from "node:path";
|
|
42
|
-
import { parseTaskNotificationXml } from "./utils/notificationXml.js";
|
|
43
|
-
import { InitializationService } from "./services/initializationService.js";
|
|
44
|
-
import { InteractionService } from "./services/interactionService.js";
|
|
45
|
-
import { ConfigurationService } from "./services/configurationService.js";
|
|
46
|
-
import { Container } from "./utils/container.js";
|
|
47
|
-
import { setupAgentContainer } from "./utils/containerSetup.js";
|
|
48
|
-
import {
|
|
49
|
-
initializeTelemetry,
|
|
50
|
-
shutdownTelemetry,
|
|
51
|
-
} from "./telemetry/instrumentation.js";
|
|
52
|
-
import { logOTelEvent } from "./telemetry/events.js";
|
|
53
|
-
import { remoteSettingsService } from "./services/remoteSettingsService.js";
|
|
54
|
-
|
|
55
|
-
export class Agent {
|
|
56
|
-
private messageManager: MessageManager;
|
|
57
|
-
private aiManager: AIManager;
|
|
58
|
-
|
|
59
|
-
private bangManager: BangManager | null = null;
|
|
60
|
-
private backgroundTaskManager: BackgroundTaskManager;
|
|
61
|
-
private logger?: Logger; // Add optional logger property
|
|
62
|
-
private toolManager: ToolManager; // Add tool registry instance
|
|
63
|
-
private mcpManager: McpManager; // Add MCP manager instance
|
|
64
|
-
private lspManager: ILspManager; // Add LSP manager instance
|
|
65
|
-
private permissionManager: PermissionManager; // Add permission manager instance
|
|
66
|
-
private planManager: PlanManager; // Add plan manager instance
|
|
67
|
-
private subagentManager: SubagentManager; // Add subagent manager instance
|
|
68
|
-
private forkedAgentManager: ForkedAgentManager; // Add forked agent manager instance
|
|
69
|
-
private slashCommandManager: SlashCommandManager; // Add slash command manager instance
|
|
70
|
-
private pluginManager: PluginManager; // Add plugin manager instance
|
|
71
|
-
private skillManager: SkillManager; // Add skill manager instance
|
|
72
|
-
private cronManager: CronManager; // Add cron manager instance
|
|
73
|
-
private hookManager: HookManager; // Add hooks manager instance
|
|
74
|
-
private reversionManager: ReversionManager;
|
|
75
|
-
private messageQueue: MessageQueue; // Unified queue for messages, bang commands, and notifications
|
|
76
|
-
private dispatchPromise: Promise<void> | null = null; // Track current dispatch for teardown
|
|
77
|
-
private isAborting = false; // Guard: prevents tryDispatch from firing during abortMessage
|
|
78
|
-
private memoryRuleManager: MemoryRuleManager; // Add memory rule manager instance
|
|
79
|
-
private liveConfigManager: LiveConfigManager; // Add live configuration manager
|
|
80
|
-
private taskManager: TaskManager;
|
|
81
|
-
private foregroundTaskManager: ForegroundTaskManager;
|
|
82
|
-
private container: Container;
|
|
83
|
-
private configurationService: ConfigurationService; // Add configuration service
|
|
84
|
-
private workdir: string; // Working directory
|
|
85
|
-
private systemPrompt?: string; // Custom system prompt
|
|
86
|
-
private stream: boolean; // Streaming mode flag
|
|
87
|
-
private sessionStartTime: number = Date.now();
|
|
88
|
-
|
|
89
|
-
// Configuration options storage for dynamic resolution
|
|
90
|
-
private options: AgentOptions;
|
|
91
|
-
|
|
92
|
-
// Dynamic configuration getter methods
|
|
93
|
-
public getGatewayConfig(): GatewayConfig {
|
|
94
|
-
return {
|
|
95
|
-
...this.configurationService.resolveGatewayConfig(),
|
|
96
|
-
sessionId: this.messageManager.getSessionId(),
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public getModelConfig(): ModelConfig {
|
|
101
|
-
return this.configurationService.resolveModelConfig(
|
|
102
|
-
undefined,
|
|
103
|
-
undefined,
|
|
104
|
-
undefined,
|
|
105
|
-
this.getPermissionMode(),
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
public getMaxInputTokens(): number {
|
|
110
|
-
return this.configurationService.resolveMaxInputTokens();
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
public getLanguage(): string | undefined {
|
|
114
|
-
return this.configurationService.resolveLanguage();
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Set the active model for the agent session
|
|
119
|
-
* @param model - The ID of the model to use
|
|
120
|
-
*/
|
|
121
|
-
public setModel(model: string): void {
|
|
122
|
-
this.configurationService.setModel(model);
|
|
123
|
-
this.options.callbacks?.onModelChange?.(model);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Get all configured models from settings.json and defaults
|
|
128
|
-
* @returns Array of model IDs
|
|
129
|
-
*/
|
|
130
|
-
public getConfiguredModels(): string[] {
|
|
131
|
-
return this.configurationService.getConfiguredModels();
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Agent constructor - handles configuration resolution and validation
|
|
136
|
-
*
|
|
137
|
-
* IMPORTANT: This constructor is private. Use Agent.create() instead for proper
|
|
138
|
-
* async initialization. Keep this constructor's signature exactly the same as
|
|
139
|
-
* Agent.create() to maintain API consistency.
|
|
140
|
-
*
|
|
141
|
-
* @param options - Configuration options for the Agent instance
|
|
142
|
-
*/
|
|
143
|
-
private constructor(options: AgentOptions) {
|
|
144
|
-
const { logger, workdir, systemPrompt, stream = true } = options;
|
|
145
|
-
|
|
146
|
-
// Set working directory early as we need it for loading configuration
|
|
147
|
-
this.workdir = workdir || process.cwd();
|
|
148
|
-
|
|
149
|
-
// Initialize configuration service
|
|
150
|
-
this.configurationService = new ConfigurationService();
|
|
151
|
-
this.configurationService.setOptions(options);
|
|
152
|
-
|
|
153
|
-
this.logger = logger; // Save the passed logger
|
|
154
|
-
this.systemPrompt = systemPrompt; // Save custom system prompt
|
|
155
|
-
this.stream = stream; // Save streaming mode flag
|
|
156
|
-
|
|
157
|
-
// Store options for dynamic configuration resolution
|
|
158
|
-
this.options = options;
|
|
159
|
-
|
|
160
|
-
this.container = setupAgentContainer({
|
|
161
|
-
options,
|
|
162
|
-
workdir: this.workdir,
|
|
163
|
-
configurationService: this.configurationService,
|
|
164
|
-
systemPrompt: this.systemPrompt,
|
|
165
|
-
stream: this.stream,
|
|
166
|
-
onTasksChange: (tasks) => {
|
|
167
|
-
this.options.callbacks?.onTasksChange?.(tasks);
|
|
168
|
-
},
|
|
169
|
-
onBackgroundTasksChange: (tasks) => {
|
|
170
|
-
this.options.callbacks?.onBackgroundTasksChange?.(tasks);
|
|
171
|
-
},
|
|
172
|
-
onPermissionModeChange: (mode) => {
|
|
173
|
-
this.options.callbacks?.onPermissionModeChange?.(mode);
|
|
174
|
-
},
|
|
175
|
-
handlePlanModeTransition: (mode) => {
|
|
176
|
-
this.planManager.handlePlanModeTransition(mode);
|
|
177
|
-
},
|
|
178
|
-
setPermissionMode: (mode) => {
|
|
179
|
-
this.setPermissionMode(mode);
|
|
180
|
-
},
|
|
181
|
-
addPermissionRule: (rule) => this.addPermissionRule(rule),
|
|
182
|
-
addUsage: (usage) => this.messageManager.addUsage(usage),
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
// Retrieve managers from container
|
|
186
|
-
this.foregroundTaskManager = this.container.get("ForegroundTaskManager")!;
|
|
187
|
-
this.memoryRuleManager = this.container.get("MemoryRuleManager")!;
|
|
188
|
-
this.messageManager = this.container.get("MessageManager")!;
|
|
189
|
-
this.taskManager = this.container.get("TaskManager")!;
|
|
190
|
-
this.backgroundTaskManager = this.container.get("BackgroundTaskManager")!;
|
|
191
|
-
this.mcpManager = this.container.get("McpManager")!;
|
|
192
|
-
this.lspManager = this.container.get("LspManager")!;
|
|
193
|
-
this.permissionManager = this.container.get("PermissionManager")!;
|
|
194
|
-
this.planManager = this.container.get("PlanManager")!;
|
|
195
|
-
this.hookManager = this.container.get("HookManager")!;
|
|
196
|
-
this.skillManager = this.container.get("SkillManager")!;
|
|
197
|
-
this.reversionManager = this.container.get("ReversionManager")!;
|
|
198
|
-
this.toolManager = this.container.get("ToolManager")!;
|
|
199
|
-
this.liveConfigManager = this.container.get("LiveConfigManager")!;
|
|
200
|
-
this.subagentManager = this.container.get("SubagentManager")!;
|
|
201
|
-
this.forkedAgentManager = this.container.get("ForkedAgentManager")!;
|
|
202
|
-
this.aiManager = this.container.get("AIManager")!;
|
|
203
|
-
this.slashCommandManager = this.container.get("SlashCommandManager")!;
|
|
204
|
-
this.pluginManager = this.container.get("PluginManager")!;
|
|
205
|
-
this.bangManager = this.container.get("BangManager")!;
|
|
206
|
-
this.cronManager = this.container.get("CronManager")!;
|
|
207
|
-
this.messageQueue = this.container.get("MessageQueue")!;
|
|
208
|
-
|
|
209
|
-
// Wire up CWD change callback from AIManager to sync Agent's workdir
|
|
210
|
-
this.aiManager.setOnCwdChange((newCwd) => {
|
|
211
|
-
this.workdir = newCwd;
|
|
212
|
-
this.container.register("Workdir", newCwd);
|
|
213
|
-
this.options.callbacks?.onWorkdirChange?.(newCwd);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
// Wire up message queue to process when agent becomes idle.
|
|
217
|
-
// Both user messages and background task notifications enqueue here,
|
|
218
|
-
// unified through a single dispatch path (tryDispatch).
|
|
219
|
-
this.messageQueue.onMessageEnqueued = () => this.tryDispatch();
|
|
220
|
-
|
|
221
|
-
// Wire up AI loading changes to process queue when AI becomes idle
|
|
222
|
-
this.aiManager.onLoadingChange = (loading: boolean) => {
|
|
223
|
-
if (!loading) this.tryDispatch();
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
// Wire up bang manager callback for command running changes
|
|
227
|
-
this.bangManager.onCommandRunningChange = (running: boolean) => {
|
|
228
|
-
this.options.callbacks?.onCommandRunningChange?.(running);
|
|
229
|
-
if (!running) this.tryDispatch();
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
// Set initial permission mode if provided
|
|
233
|
-
if (options.permissionMode) {
|
|
234
|
-
this.setPermissionMode(options.permissionMode);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Public getter methods
|
|
239
|
-
public get sessionId(): string {
|
|
240
|
-
return this.messageManager.getSessionId();
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
public get messages(): Message[] {
|
|
244
|
-
return this.messageManager.getMessages();
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
public get usages(): Usage[] {
|
|
248
|
-
return this.messageManager.getUsages();
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
public get sessionFilePath(): string {
|
|
252
|
-
return this.messageManager.getTranscriptPath();
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
public get latestTotalTokens(): number {
|
|
256
|
-
return this.messageManager.getLatestTotalTokens();
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/** Get working directory */
|
|
260
|
-
public get workingDirectory(): string {
|
|
261
|
-
return this.workdir;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Set the working directory
|
|
266
|
-
* @param newCwd - The new working directory
|
|
267
|
-
*/
|
|
268
|
-
public setWorkdir(newCwd: string): void {
|
|
269
|
-
this.workdir = newCwd;
|
|
270
|
-
this.container.register("Workdir", newCwd);
|
|
271
|
-
this.options.callbacks?.onWorkdirChange?.(newCwd);
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
/**
|
|
275
|
-
* Set this session's worktree session state (used by CLI -w startup to inject the
|
|
276
|
-
* session created before the agent existed). Delegates to AIManager so the state is
|
|
277
|
-
* stored in this agent's own DI container.
|
|
278
|
-
*/
|
|
279
|
-
public setWorktreeSession(session: WorktreeSession | null): void {
|
|
280
|
-
this.aiManager.setWorktreeSession(session);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/** Get project memory content */
|
|
284
|
-
public get projectMemory(): string {
|
|
285
|
-
const memoryService =
|
|
286
|
-
this.container.get<import("./services/memory.js").MemoryService>(
|
|
287
|
-
"MemoryService",
|
|
288
|
-
);
|
|
289
|
-
return memoryService?.cachedProjectMemory ?? "";
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/** Get user memory content */
|
|
293
|
-
public get userMemory(): string {
|
|
294
|
-
const memoryService =
|
|
295
|
-
this.container.get<import("./services/memory.js").MemoryService>(
|
|
296
|
-
"MemoryService",
|
|
297
|
-
);
|
|
298
|
-
return memoryService?.cachedUserMemory ?? "";
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
/** Get combined memory content (project + user + modular rules) */
|
|
302
|
-
public async getCombinedMemory(): Promise<string> {
|
|
303
|
-
return this.messageManager.getCombinedMemory();
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/** Get AI loading status */
|
|
307
|
-
public get isLoading(): boolean {
|
|
308
|
-
return this.aiManager.isLoading;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/** Get message compaction status */
|
|
312
|
-
public get isCompacting(): boolean {
|
|
313
|
-
return this.aiManager.getIsCompacting();
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/** Get bash command execution status */
|
|
317
|
-
public get isCommandRunning(): boolean {
|
|
318
|
-
return this.bangManager?.isCommandRunning ?? false;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
/** Get queued user-facing messages (excludes background notifications) */
|
|
322
|
-
public get queuedMessages(): QueuedMessage[] {
|
|
323
|
-
return this.messageQueue
|
|
324
|
-
.getQueue()
|
|
325
|
-
.filter((m) => m.type !== "notification");
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Remove a queued message by index
|
|
330
|
-
* @param index - The index of the message to remove
|
|
331
|
-
* @returns true if the message was removed, false if the index was out of bounds
|
|
332
|
-
*/
|
|
333
|
-
public removeQueuedMessage(index: number): boolean {
|
|
334
|
-
const removed = this.messageQueue.removeAt(index);
|
|
335
|
-
if (removed) {
|
|
336
|
-
this.options.callbacks?.onQueuedMessagesChange?.(this.queuedMessages);
|
|
337
|
-
}
|
|
338
|
-
return removed;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Recall the last editable queued message (for inline editing)
|
|
343
|
-
* @returns The recalled message, or null if no editable message exists
|
|
344
|
-
*/
|
|
345
|
-
public recallQueuedMessage(): QueuedMessage | null {
|
|
346
|
-
const msg = this.messageQueue.popLastEditable();
|
|
347
|
-
if (msg) {
|
|
348
|
-
this.options.callbacks?.onQueuedMessagesChange?.(this.queuedMessages);
|
|
349
|
-
}
|
|
350
|
-
return msg;
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
/**
|
|
354
|
-
* Remove a queued message by its ID
|
|
355
|
-
* @param id - The ID of the message to remove
|
|
356
|
-
* @returns true if the message was removed, false if not found
|
|
357
|
-
*/
|
|
358
|
-
public removeQueuedMessageById(id: string): boolean {
|
|
359
|
-
const removed = this.messageQueue.removeById(id);
|
|
360
|
-
if (removed) {
|
|
361
|
-
this.options.callbacks?.onQueuedMessagesChange?.(this.queuedMessages);
|
|
362
|
-
}
|
|
363
|
-
return removed;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Update a queued message's content by its ID (does not change queue order)
|
|
368
|
-
* @param id - The ID of the message to update
|
|
369
|
-
* @param patch - The fields to update
|
|
370
|
-
* @returns true if the message was updated, false if not found
|
|
371
|
-
*/
|
|
372
|
-
public updateQueuedMessageById(
|
|
373
|
-
id: string,
|
|
374
|
-
patch: {
|
|
375
|
-
content?: string;
|
|
376
|
-
images?: Array<{ path: string; mimeType: string }>;
|
|
377
|
-
type?: "message" | "bang";
|
|
378
|
-
},
|
|
379
|
-
): boolean {
|
|
380
|
-
const updated = this.messageQueue.updateById(id, patch);
|
|
381
|
-
if (updated) {
|
|
382
|
-
this.options.callbacks?.onQueuedMessagesChange?.(this.queuedMessages);
|
|
383
|
-
}
|
|
384
|
-
return updated;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Unified dispatch trigger — checks state machine before processing.
|
|
389
|
-
* Handles user messages, bang commands, and background task notifications
|
|
390
|
-
* through a single serialized path. Called from onMessageEnqueued,
|
|
391
|
-
* onLoadingChange(false), and onCommandRunningChange(false).
|
|
392
|
-
*/
|
|
393
|
-
private tryDispatch(): void {
|
|
394
|
-
if (this.isAborting) return; // Suppress dispatch during abort to prevent queued notifications from being dispatched as a side-effect
|
|
395
|
-
if (this.messageQueue.state !== "idle") return;
|
|
396
|
-
if (!this.messageQueue.hasPending()) return;
|
|
397
|
-
if (this.aiManager.isLoading || this.isCommandRunning) return;
|
|
398
|
-
|
|
399
|
-
this.messageQueue.transitionTo("dispatching");
|
|
400
|
-
this.dispatchPromise = this.processQueuedMessage()
|
|
401
|
-
.catch((error) => {
|
|
402
|
-
this.logger?.error("Failed to process queued message:", error);
|
|
403
|
-
})
|
|
404
|
-
.finally(() => {
|
|
405
|
-
this.messageQueue.transitionTo("idle");
|
|
406
|
-
this.dispatchPromise = null;
|
|
407
|
-
this.tryDispatch(); // Re-check after processing
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Process the next queued item when the agent becomes idle.
|
|
413
|
-
* Handles three item types: user messages, bang commands, and notifications.
|
|
414
|
-
*/
|
|
415
|
-
private async processQueuedMessage(): Promise<void> {
|
|
416
|
-
const next = this.messageQueue.dequeue();
|
|
417
|
-
if (!next) return;
|
|
418
|
-
|
|
419
|
-
this.messageQueue.transitionTo("running");
|
|
420
|
-
this.options.callbacks?.onQueuedMessagesChange?.(this.queuedMessages);
|
|
421
|
-
|
|
422
|
-
if (next.type === "bang") {
|
|
423
|
-
await this.bangManager?.executeCommand(next.content);
|
|
424
|
-
await this.messageManager.saveSession();
|
|
425
|
-
} else if (next.type === "notification") {
|
|
426
|
-
// Drain all pending notifications and batch them into a single AI turn
|
|
427
|
-
const allNotifications = [
|
|
428
|
-
next.content,
|
|
429
|
-
...this.messageQueue.drainNotifications(),
|
|
430
|
-
];
|
|
431
|
-
for (const xml of allNotifications) {
|
|
432
|
-
const block = parseTaskNotificationXml(xml);
|
|
433
|
-
if (block) {
|
|
434
|
-
this.messageManager.addNotificationMessage({
|
|
435
|
-
taskId: block.taskId,
|
|
436
|
-
taskType: block.taskType,
|
|
437
|
-
status: block.status,
|
|
438
|
-
summary: block.summary,
|
|
439
|
-
outputFile: block.outputFile,
|
|
440
|
-
});
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
await this.aiManager.sendAIMessage({ recursionDepth: 0 });
|
|
444
|
-
} else {
|
|
445
|
-
await this.sendMessage(next.content, next.images);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
/** Get background bash shell output */
|
|
450
|
-
public getBackgroundShellOutput(
|
|
451
|
-
id: string,
|
|
452
|
-
filter?: string,
|
|
453
|
-
): {
|
|
454
|
-
stdout: string;
|
|
455
|
-
stderr: string;
|
|
456
|
-
status: string;
|
|
457
|
-
outputPath?: string;
|
|
458
|
-
type: string;
|
|
459
|
-
exitCode?: number;
|
|
460
|
-
} | null {
|
|
461
|
-
return this.backgroundTaskManager.getOutput(id, filter);
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
/** Kill background bash shell */
|
|
465
|
-
public killBackgroundShell(id: string): boolean {
|
|
466
|
-
return this.backgroundTaskManager.stopTask(id);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
/** Get background task output */
|
|
470
|
-
public getBackgroundTaskOutput(
|
|
471
|
-
id: string,
|
|
472
|
-
filter?: string,
|
|
473
|
-
): {
|
|
474
|
-
stdout: string;
|
|
475
|
-
stderr: string;
|
|
476
|
-
status: string;
|
|
477
|
-
outputPath?: string;
|
|
478
|
-
type: string;
|
|
479
|
-
exitCode?: number;
|
|
480
|
-
} | null {
|
|
481
|
-
return this.backgroundTaskManager.getOutput(id, filter);
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
/** Stop background task */
|
|
485
|
-
public stopBackgroundTask(id: string): boolean {
|
|
486
|
-
return this.backgroundTaskManager.stopTask(id);
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
/** Get all workflow runs */
|
|
490
|
-
public async getWorkflowRuns(): Promise<
|
|
491
|
-
import("./workflow/types.js").WorkflowRun[]
|
|
492
|
-
> {
|
|
493
|
-
if (!this.container.has("WorkflowManager")) return [];
|
|
494
|
-
return this.container
|
|
495
|
-
.get<
|
|
496
|
-
import("./managers/workflowManager.js").WorkflowManager
|
|
497
|
-
>("WorkflowManager")!
|
|
498
|
-
.listRuns();
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
/** Get a specific workflow run by ID */
|
|
502
|
-
public getWorkflowRun(
|
|
503
|
-
runId: string,
|
|
504
|
-
): import("./workflow/types.js").WorkflowRun | undefined {
|
|
505
|
-
if (!this.container.has("WorkflowManager")) return undefined;
|
|
506
|
-
return this.container
|
|
507
|
-
.get<
|
|
508
|
-
import("./managers/workflowManager.js").WorkflowManager
|
|
509
|
-
>("WorkflowManager")!
|
|
510
|
-
.getRun(runId);
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
/** Stop a workflow run */
|
|
514
|
-
public stopWorkflowRun(runId: string): void {
|
|
515
|
-
if (!this.container.has("WorkflowManager")) return;
|
|
516
|
-
this.container
|
|
517
|
-
.get<
|
|
518
|
-
import("./managers/workflowManager.js").WorkflowManager
|
|
519
|
-
>("WorkflowManager")!
|
|
520
|
-
.stopRun(runId);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
/**
|
|
524
|
-
* Static async factory method for creating Agent instances
|
|
525
|
-
*
|
|
526
|
-
* IMPORTANT: Keep this method's signature exactly the same as the constructor
|
|
527
|
-
* to maintain consistency and avoid confusion for users of the API.
|
|
528
|
-
*
|
|
529
|
-
* @param options - Same AgentOptions interface used by constructor
|
|
530
|
-
* @returns Promise<Agent> - Fully initialized Agent instance
|
|
531
|
-
*/
|
|
532
|
-
/**
|
|
533
|
-
* Create a new Agent instance with async initialization
|
|
534
|
-
*
|
|
535
|
-
* This is the recommended way to create Agent instances. The constructor is private
|
|
536
|
-
* to ensure proper async initialization of all components.
|
|
537
|
-
*
|
|
538
|
-
* @param options - Configuration options for the Agent instance
|
|
539
|
-
* @param options.apiKey - API key for the AI service (or set WAVE_API_KEY env var)
|
|
540
|
-
* @param options.baseURL - Base URL for the AI service (or set WAVE_BASE_URL env var)
|
|
541
|
-
* @param options.defaultHeaders - Optional HTTP headers to pass to the AI service
|
|
542
|
-
* @param options.fetchOptions - Optional fetch options to pass to the AI service
|
|
543
|
-
* @param options.fetch - Optional custom fetch implementation
|
|
544
|
-
* @param options.callbacks - Optional callbacks for various Agent events
|
|
545
|
-
* @param options.restoreSessionId - Optional session ID to restore from
|
|
546
|
-
* @param options.continueLastSession - Whether to continue the last session automatically
|
|
547
|
-
* @param options.logger - Optional custom logger implementation
|
|
548
|
-
* @param options.messages - Optional initial messages for testing convenience
|
|
549
|
-
* @param options.workdir - Working directory (defaults to process.cwd())
|
|
550
|
-
* @param options.systemPrompt - Optional custom system prompt
|
|
551
|
-
* @param options.mcpServers - Optional MCP server configs to connect at startup
|
|
552
|
-
* @returns Promise that resolves to initialized Agent instance
|
|
553
|
-
*
|
|
554
|
-
* @example
|
|
555
|
-
* ```typescript
|
|
556
|
-
* // Basic usage
|
|
557
|
-
* const agent = await Agent.create({
|
|
558
|
-
* apiKey: 'your-api-key',
|
|
559
|
-
* baseURL: 'https://api.example.com'
|
|
560
|
-
* });
|
|
561
|
-
* ```
|
|
562
|
-
*/
|
|
563
|
-
static async create(options: AgentOptions): Promise<Agent> {
|
|
564
|
-
// Create Agent instance
|
|
565
|
-
const instance = new Agent(options);
|
|
566
|
-
await instance.initialize({
|
|
567
|
-
restoreSessionId: options.restoreSessionId,
|
|
568
|
-
continueLastSession: options.continueLastSession,
|
|
569
|
-
messages: options.messages,
|
|
570
|
-
});
|
|
571
|
-
return instance;
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
/**
|
|
575
|
-
* Resolve and validate configuration from constructor args, environment variables,
|
|
576
|
-
* and loaded settings.json.
|
|
577
|
-
*
|
|
578
|
-
* This is called during initialization after settings.json has been loaded.
|
|
579
|
-
*/
|
|
580
|
-
private resolveAndValidateConfig(): void {
|
|
581
|
-
// Resolve configuration from constructor args and environment variables (including settings.json)
|
|
582
|
-
const gatewayConfig = this.getGatewayConfig();
|
|
583
|
-
const maxInputTokens = this.getMaxInputTokens();
|
|
584
|
-
|
|
585
|
-
// Validate resolved configuration
|
|
586
|
-
configValidator.validateGatewayConfig(gatewayConfig);
|
|
587
|
-
configValidator.validateMaxInputTokens(maxInputTokens);
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
/** Private initialization method, handles async initialization logic */
|
|
591
|
-
private async initialize(options?: {
|
|
592
|
-
restoreSessionId?: string;
|
|
593
|
-
continueLastSession?: boolean;
|
|
594
|
-
messages?: Message[];
|
|
595
|
-
}): Promise<void> {
|
|
596
|
-
await InitializationService.initialize(
|
|
597
|
-
{
|
|
598
|
-
skillManager: this.skillManager,
|
|
599
|
-
subagentManager: this.subagentManager,
|
|
600
|
-
container: this.container,
|
|
601
|
-
toolManager: this.toolManager,
|
|
602
|
-
pluginManager: this.pluginManager,
|
|
603
|
-
options: this.options,
|
|
604
|
-
slashCommandManager: this.slashCommandManager,
|
|
605
|
-
logger: this.logger,
|
|
606
|
-
mcpManager: this.mcpManager,
|
|
607
|
-
workdir: this.workdir,
|
|
608
|
-
lspManager: this.lspManager,
|
|
609
|
-
configurationService: this.configurationService,
|
|
610
|
-
hookManager: this.hookManager,
|
|
611
|
-
messageManager: this.messageManager,
|
|
612
|
-
memoryRuleManager: this.memoryRuleManager,
|
|
613
|
-
liveConfigManager: this.liveConfigManager,
|
|
614
|
-
taskManager: this.taskManager,
|
|
615
|
-
resolveAndValidateConfig: () => this.resolveAndValidateConfig(),
|
|
616
|
-
},
|
|
617
|
-
options,
|
|
618
|
-
);
|
|
619
|
-
|
|
620
|
-
// Initialize OpenTelemetry (awaited to ensure ALS context is ready before
|
|
621
|
-
// startInteractionSpan is called, preventing trace context fragmentation)
|
|
622
|
-
const telemetryConfig = this.configurationService.resolveTelemetryConfig();
|
|
623
|
-
try {
|
|
624
|
-
await initializeTelemetry(telemetryConfig);
|
|
625
|
-
} catch (error) {
|
|
626
|
-
this.logger?.warn("Telemetry initialization failed:", error);
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
// Log session_start event
|
|
630
|
-
try {
|
|
631
|
-
const modelConfig = this.getModelConfig();
|
|
632
|
-
if (modelConfig.model) {
|
|
633
|
-
await logOTelEvent("session_start", {
|
|
634
|
-
sessionId: this.messageManager.getSessionId(),
|
|
635
|
-
model: modelConfig.model,
|
|
636
|
-
workdir: this.workdir,
|
|
637
|
-
}).catch(() => {}); // Non-blocking
|
|
638
|
-
}
|
|
639
|
-
} catch {
|
|
640
|
-
// Model not configured yet - will be available after SSO login
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
/**
|
|
645
|
-
* Restore a session by ID, switching to the target session without destroying the Agent instance
|
|
646
|
-
* @param sessionId - The ID of the session to restore
|
|
647
|
-
*/
|
|
648
|
-
public async restoreSession(sessionId: string): Promise<void> {
|
|
649
|
-
await InteractionService.restoreSession(
|
|
650
|
-
{
|
|
651
|
-
messageManager: this.messageManager,
|
|
652
|
-
slashCommandManager: this.slashCommandManager,
|
|
653
|
-
hookManager: this.hookManager,
|
|
654
|
-
workdir: this.workdir,
|
|
655
|
-
configurationService: this.configurationService,
|
|
656
|
-
logger: this.logger,
|
|
657
|
-
aiManager: this.aiManager,
|
|
658
|
-
subagentManager: this.subagentManager,
|
|
659
|
-
taskManager: this.taskManager,
|
|
660
|
-
options: this.options,
|
|
661
|
-
abortMessage: () => this.abortMessage(),
|
|
662
|
-
},
|
|
663
|
-
sessionId,
|
|
664
|
-
);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
public abortAIMessage(): void {
|
|
668
|
-
this.aiManager.abortAIMessage();
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
/** Execute bash command (bang command) */
|
|
672
|
-
public async bang(command: string): Promise<void> {
|
|
673
|
-
// If the agent is busy, enqueue the bang command
|
|
674
|
-
if (this.aiManager.isLoading || this.isCommandRunning) {
|
|
675
|
-
this.messageQueue.enqueue({ type: "bang", content: command });
|
|
676
|
-
this.options.callbacks?.onQueuedMessagesChange?.(this.queuedMessages);
|
|
677
|
-
return;
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
await this.bangManager?.executeCommand(command);
|
|
681
|
-
await this.messageManager.saveSession();
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
public async clearMessages(): Promise<void> {
|
|
685
|
-
// Aligned with webview (ChatApp handleClearChat): /clear is ignored
|
|
686
|
-
// while the agent is running, instead of aborting the AI mid-turn
|
|
687
|
-
// (which used to inject a late "Request was aborted" error into the
|
|
688
|
-
// newly cleared session).
|
|
689
|
-
if (this.aiManager.isLoading) {
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
this.aiManager.abortAIMessage();
|
|
694
|
-
|
|
695
|
-
// Capture old session info before clearing
|
|
696
|
-
const oldSessionId = this.messageManager.getSessionId();
|
|
697
|
-
const transcriptPath = this.messageManager.getTranscriptPath();
|
|
698
|
-
|
|
699
|
-
// Run SessionEnd hooks (cleanup before clear)
|
|
700
|
-
try {
|
|
701
|
-
await this.hookManager.executeSessionEndHooks(
|
|
702
|
-
"clear",
|
|
703
|
-
oldSessionId,
|
|
704
|
-
transcriptPath,
|
|
705
|
-
);
|
|
706
|
-
} catch (error) {
|
|
707
|
-
this.logger?.warn(
|
|
708
|
-
`SessionEnd hooks on clear failed: ${(error as Error).message}`,
|
|
709
|
-
);
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
// Clear messages and generate new session
|
|
713
|
-
this.messageManager.clearMessages();
|
|
714
|
-
await this.taskManager.syncWithSession();
|
|
715
|
-
|
|
716
|
-
// Run SessionStart hooks (restore context for new session)
|
|
717
|
-
try {
|
|
718
|
-
const newSessionId = this.messageManager.getSessionId();
|
|
719
|
-
const sessionStartResult =
|
|
720
|
-
await this.hookManager.executeSessionStartHooks(
|
|
721
|
-
"clear",
|
|
722
|
-
newSessionId,
|
|
723
|
-
this.messageManager.getTranscriptPath(),
|
|
724
|
-
);
|
|
725
|
-
|
|
726
|
-
// Inject additionalContext as a meta user message
|
|
727
|
-
if (sessionStartResult.additionalContext) {
|
|
728
|
-
this.messageManager.addUserMessage({
|
|
729
|
-
content: `<system-reminder>\nSessionStart hook additional context: ${sessionStartResult.additionalContext}\n</system-reminder>`,
|
|
730
|
-
isMeta: true,
|
|
731
|
-
});
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
// Inject initialUserMessage as a meta user message
|
|
735
|
-
if (sessionStartResult.initialUserMessage) {
|
|
736
|
-
this.messageManager.addUserMessage({
|
|
737
|
-
content: sessionStartResult.initialUserMessage,
|
|
738
|
-
isMeta: true,
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
} catch (error) {
|
|
742
|
-
this.logger?.warn(
|
|
743
|
-
`SessionStart hooks on clear failed: ${(error as Error).message}`,
|
|
744
|
-
);
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
await this.messageManager.saveSession();
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
/**
|
|
751
|
-
* Compact conversation history to reduce context usage
|
|
752
|
-
* @param customInstructions - Optional custom instructions for compaction
|
|
753
|
-
*/
|
|
754
|
-
public async compact(customInstructions?: string): Promise<void> {
|
|
755
|
-
// Aligned with webview: /compact is ignored while the agent is running,
|
|
756
|
-
// instead of aborting the AI mid-turn before compacting.
|
|
757
|
-
if (this.aiManager.isLoading) {
|
|
758
|
-
return;
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
this.aiManager.abortAIMessage();
|
|
762
|
-
|
|
763
|
-
await this.aiManager.compactConversation({
|
|
764
|
-
customInstructions,
|
|
765
|
-
});
|
|
766
|
-
|
|
767
|
-
await this.messageManager.saveSession();
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
/** Unified interrupt method, interrupts both AI messages and command execution */
|
|
771
|
-
public abortMessage(): void {
|
|
772
|
-
// Guard: prevent tryDispatch (triggered by abortAIMessage → setIsLoading(false))
|
|
773
|
-
// from dispatching preserved notifications as a new AI turn during the abort.
|
|
774
|
-
this.isAborting = true;
|
|
775
|
-
try {
|
|
776
|
-
if (this.aiManager.isLoading || this.isCommandRunning) {
|
|
777
|
-
// Clear user-facing queue items first to prevent processQueuedMessage
|
|
778
|
-
// from dequeuing when abortAIMessage triggers onLoadingChange(false).
|
|
779
|
-
// Notifications are preserved so background task results aren't lost.
|
|
780
|
-
this.messageQueue.clear();
|
|
781
|
-
this.options.callbacks?.onQueuedMessagesChange?.(this.queuedMessages);
|
|
782
|
-
}
|
|
783
|
-
this.messageQueue.transitionTo("idle"); // Reset state on abort
|
|
784
|
-
this.abortAIMessage(); // This will abort tools including Agent tool (subagents)
|
|
785
|
-
this.abortBashCommand();
|
|
786
|
-
this.abortSlashCommand();
|
|
787
|
-
} finally {
|
|
788
|
-
this.isAborting = false;
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
/** Interrupt bash command execution */
|
|
793
|
-
public abortBashCommand(): void {
|
|
794
|
-
this.bangManager?.abortCommand();
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
/** Interrupt slash command execution */
|
|
798
|
-
public abortSlashCommand(): void {
|
|
799
|
-
this.slashCommandManager.abortCurrentCommand();
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
/**
|
|
803
|
-
* Register a foreground task that can be backgrounded
|
|
804
|
-
*/
|
|
805
|
-
public registerForegroundTask(task: ForegroundTask): void {
|
|
806
|
-
this.foregroundTaskManager.registerForegroundTask(task);
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
/**
|
|
810
|
-
* Unregister a foreground task
|
|
811
|
-
*/
|
|
812
|
-
public unregisterForegroundTask(id: string): void {
|
|
813
|
-
this.foregroundTaskManager.unregisterForegroundTask(id);
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
/**
|
|
817
|
-
* Background the current foreground task
|
|
818
|
-
*/
|
|
819
|
-
public async backgroundCurrentTask(): Promise<void> {
|
|
820
|
-
await this.foregroundTaskManager.backgroundCurrentTask();
|
|
821
|
-
this.options.callbacks?.onBackgroundCurrentTask?.();
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
/**
|
|
825
|
-
* Trigger WorktreeRemove hook before agent destruction.
|
|
826
|
-
* Called from CLI exit dialog when user chooses to remove the worktree.
|
|
827
|
-
* Non-blocking: errors logged but don't prevent removal.
|
|
828
|
-
*/
|
|
829
|
-
public async triggerWorktreeRemoveHook(worktreePath: string): Promise<void> {
|
|
830
|
-
if (!this.hookManager.hasHooks("WorktreeRemove")) {
|
|
831
|
-
return;
|
|
832
|
-
}
|
|
833
|
-
try {
|
|
834
|
-
const sessionId = this.messageManager.getSessionId();
|
|
835
|
-
const transcriptPath = this.messageManager.getTranscriptPath();
|
|
836
|
-
const hookResults = await this.hookManager.executeHooks(
|
|
837
|
-
"WorktreeRemove",
|
|
838
|
-
{
|
|
839
|
-
event: "WorktreeRemove",
|
|
840
|
-
projectDir: this.workdir,
|
|
841
|
-
timestamp: new Date(),
|
|
842
|
-
sessionId,
|
|
843
|
-
transcriptPath,
|
|
844
|
-
cwd: this.workdir,
|
|
845
|
-
worktreePath,
|
|
846
|
-
env: Object.fromEntries(
|
|
847
|
-
Object.entries(this.configurationService.getMergedEnv()).filter(
|
|
848
|
-
(e) => e[1] !== undefined,
|
|
849
|
-
),
|
|
850
|
-
) as Record<string, string>,
|
|
851
|
-
},
|
|
852
|
-
);
|
|
853
|
-
// Process results via messageManager (may not be visible during shutdown)
|
|
854
|
-
this.hookManager.processHookResults(
|
|
855
|
-
"WorktreeRemove",
|
|
856
|
-
hookResults,
|
|
857
|
-
this.messageManager,
|
|
858
|
-
);
|
|
859
|
-
} catch (error) {
|
|
860
|
-
this.logger?.warn("WorktreeRemove hooks execution failed:", error);
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
|
|
864
|
-
/** Destroy managers, clean up resources */
|
|
865
|
-
public async destroy(): Promise<void> {
|
|
866
|
-
// Log session_end event and shutdown telemetry
|
|
867
|
-
await logOTelEvent("session_end", {
|
|
868
|
-
duration: String(Math.round((Date.now() - this.sessionStartTime) / 1000)),
|
|
869
|
-
totalTokens: String(this.messageManager.getLatestTotalTokens()),
|
|
870
|
-
exitReason: "destroy",
|
|
871
|
-
}).catch(() => {});
|
|
872
|
-
await shutdownTelemetry();
|
|
873
|
-
|
|
874
|
-
// Clear message queue callback first to prevent any late triggers from
|
|
875
|
-
// starting async work during teardown
|
|
876
|
-
this.messageQueue.onMessageEnqueued = undefined;
|
|
877
|
-
|
|
878
|
-
// Await any pending dispatch to prevent race conditions
|
|
879
|
-
// with test teardown (e.g., V8 coverage stream cleanup)
|
|
880
|
-
if (this.dispatchPromise) {
|
|
881
|
-
await this.dispatchPromise.catch(() => {});
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
// Fire SessionEnd hooks (fire-and-forget, don't block shutdown)
|
|
885
|
-
try {
|
|
886
|
-
const sessionId = this.messageManager.getSessionId();
|
|
887
|
-
const transcriptPath = this.messageManager.getTranscriptPath();
|
|
888
|
-
await this.hookManager.executeSessionEndHooks(
|
|
889
|
-
"stop",
|
|
890
|
-
sessionId,
|
|
891
|
-
transcriptPath,
|
|
892
|
-
);
|
|
893
|
-
} catch (error) {
|
|
894
|
-
this.logger?.warn(`SessionEnd hooks failed: ${(error as Error).message}`);
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
await this.messageManager.saveSession();
|
|
898
|
-
this.abortAIMessage(); // This will abort tools including Agent tool (subagents)
|
|
899
|
-
this.abortBashCommand();
|
|
900
|
-
this.abortSlashCommand();
|
|
901
|
-
this.cronManager.stop();
|
|
902
|
-
// Cleanup background task manager
|
|
903
|
-
this.backgroundTaskManager.cleanup();
|
|
904
|
-
// Cleanup MCP connections
|
|
905
|
-
await this.mcpManager.cleanup();
|
|
906
|
-
// Cleanup LSP connections
|
|
907
|
-
if (this.lspManager instanceof LspManager) {
|
|
908
|
-
await this.lspManager.cleanup();
|
|
909
|
-
}
|
|
910
|
-
// Cleanup subagent manager
|
|
911
|
-
this.subagentManager.cleanup();
|
|
912
|
-
// Cleanup forked agent manager
|
|
913
|
-
await this.forkedAgentManager.cleanup();
|
|
914
|
-
// Drain an in-flight auto-memory extraction fork so the process doesn't
|
|
915
|
-
// exit mid-extraction
|
|
916
|
-
try {
|
|
917
|
-
const autoMemoryService =
|
|
918
|
-
this.container.get<
|
|
919
|
-
import("./services/autoMemoryService.js").AutoMemoryService
|
|
920
|
-
>("AutoMemoryService");
|
|
921
|
-
if (autoMemoryService) {
|
|
922
|
-
await autoMemoryService.drain();
|
|
923
|
-
}
|
|
924
|
-
} catch (error) {
|
|
925
|
-
this.logger?.warn(
|
|
926
|
-
`Auto-memory extraction drain failed: ${(error as Error).message}`,
|
|
927
|
-
);
|
|
928
|
-
}
|
|
929
|
-
// Cleanup skill manager
|
|
930
|
-
await this.skillManager.destroy();
|
|
931
|
-
// Cleanup live configuration reload
|
|
932
|
-
try {
|
|
933
|
-
await this.liveConfigManager.shutdown();
|
|
934
|
-
} catch (error) {
|
|
935
|
-
this.logger?.error(
|
|
936
|
-
"Error shutting down live configuration reload:",
|
|
937
|
-
error,
|
|
938
|
-
);
|
|
939
|
-
}
|
|
940
|
-
// Cleanup remote settings polling
|
|
941
|
-
remoteSettingsService.shutdown();
|
|
942
|
-
// Cleanup memory store
|
|
943
|
-
}
|
|
944
|
-
|
|
945
|
-
/**
|
|
946
|
-
* Trigger the rewind UI callback
|
|
947
|
-
*/
|
|
948
|
-
public triggerShowRewind(): void {
|
|
949
|
-
this.messageManager.triggerShowRewind();
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
/**
|
|
953
|
-
* Ask a side question without interrupting the main agent.
|
|
954
|
-
*
|
|
955
|
-
* Runs a single-turn fork of the conversation that reuses the main loop's
|
|
956
|
-
* system prompt, tools, and memory injection (prompt-cache friendly) and
|
|
957
|
-
* never executes tools. The abort signal lets the UI cancel a pending
|
|
958
|
-
* question (loading dismiss); aborts propagate as thrown errors.
|
|
959
|
-
*
|
|
960
|
-
* @param question - The side question to ask
|
|
961
|
-
* @param abortSignal - Optional signal to abort the pending request
|
|
962
|
-
* @returns Promise that resolves to the AI's answer
|
|
963
|
-
*/
|
|
964
|
-
public async askBtw(
|
|
965
|
-
question: string,
|
|
966
|
-
abortSignal?: AbortSignal,
|
|
967
|
-
onContent?: (content: string) => void,
|
|
968
|
-
onReasoning?: (content: string) => void,
|
|
969
|
-
): Promise<string> {
|
|
970
|
-
const result = await this.aiManager.runBtwFork(
|
|
971
|
-
question,
|
|
972
|
-
abortSignal,
|
|
973
|
-
onContent,
|
|
974
|
-
onReasoning,
|
|
975
|
-
);
|
|
976
|
-
return result.content ?? result.error ?? "No response received";
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
/**
|
|
980
|
-
* Send a message to the AI agent with optional images
|
|
981
|
-
*
|
|
982
|
-
* @param content - The text content of the message to send
|
|
983
|
-
* @param images - Optional array of images to include with the message
|
|
984
|
-
* @param images[].path - File path to the image or base64 encoded image data
|
|
985
|
-
* @param images[].mimeType - MIME type of the image (e.g., 'image/png', 'image/jpeg')
|
|
986
|
-
* @returns Promise that resolves when the message has been processed
|
|
987
|
-
*
|
|
988
|
-
* @example
|
|
989
|
-
* ```typescript
|
|
990
|
-
* // Send a text message
|
|
991
|
-
* await agent.sendMessage("Hello, how are you?");
|
|
992
|
-
*
|
|
993
|
-
* // Send a message with images using file paths
|
|
994
|
-
* await agent.sendMessage("What do you see in these images?", [
|
|
995
|
-
* { path: "/path/to/image.png", mimeType: "image/png" },
|
|
996
|
-
* { path: "/path/to/photo.jpg", mimeType: "image/jpeg" }
|
|
997
|
-
* ]);
|
|
998
|
-
*
|
|
999
|
-
* // Send a message with base64 encoded image
|
|
1000
|
-
* await agent.sendMessage("Analyze this image", [
|
|
1001
|
-
* { path: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...", mimeType: "image/png" }
|
|
1002
|
-
* ]);
|
|
1003
|
-
* ```
|
|
1004
|
-
*/
|
|
1005
|
-
public async sendMessage(
|
|
1006
|
-
content: string,
|
|
1007
|
-
images?: Array<{ path: string; mimeType: string }>,
|
|
1008
|
-
): Promise<void> {
|
|
1009
|
-
// If the agent is busy, enqueue the message — unless it's an immediate
|
|
1010
|
-
// slash command (e.g., /clear, /compact) that should execute
|
|
1011
|
-
// right away even while AI is processing
|
|
1012
|
-
if (this.aiManager.isLoading || this.isCommandRunning) {
|
|
1013
|
-
const trimmed = content.trim();
|
|
1014
|
-
const isImmediate =
|
|
1015
|
-
trimmed.startsWith("/") &&
|
|
1016
|
-
trimmed !== "/" &&
|
|
1017
|
-
this.slashCommandManager.isImmediateCommand(trimmed);
|
|
1018
|
-
|
|
1019
|
-
if (!isImmediate) {
|
|
1020
|
-
this.messageQueue.enqueue({
|
|
1021
|
-
content,
|
|
1022
|
-
images,
|
|
1023
|
-
});
|
|
1024
|
-
this.options.callbacks?.onQueuedMessagesChange?.(this.queuedMessages);
|
|
1025
|
-
return;
|
|
1026
|
-
}
|
|
1027
|
-
// Immediate slash command: fall through to InteractionService
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
await InteractionService.sendMessage(
|
|
1031
|
-
{
|
|
1032
|
-
messageManager: this.messageManager,
|
|
1033
|
-
slashCommandManager: this.slashCommandManager,
|
|
1034
|
-
hookManager: this.hookManager,
|
|
1035
|
-
workdir: this.workdir,
|
|
1036
|
-
configurationService: this.configurationService,
|
|
1037
|
-
logger: this.logger,
|
|
1038
|
-
aiManager: this.aiManager,
|
|
1039
|
-
subagentManager: this.subagentManager,
|
|
1040
|
-
taskManager: this.taskManager,
|
|
1041
|
-
options: this.options,
|
|
1042
|
-
abortMessage: () => this.abortMessage(),
|
|
1043
|
-
},
|
|
1044
|
-
content,
|
|
1045
|
-
images,
|
|
1046
|
-
);
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
// ========== Additional Directories ==========
|
|
1050
|
-
|
|
1051
|
-
/**
|
|
1052
|
-
* Add an additional directory to the Safe Zone for this session.
|
|
1053
|
-
*
|
|
1054
|
-
* The directory immediately becomes part of the Safe Zone (permission
|
|
1055
|
-
* checks and the system prompt), and with `remember: true` it is also
|
|
1056
|
-
* persisted to `.wave/settings.local.json` `permissions.additionalDirectories`
|
|
1057
|
-
* so future sessions pick it up automatically.
|
|
1058
|
-
*
|
|
1059
|
-
* @param directory Path of the directory to add (relative paths resolve against the workdir).
|
|
1060
|
-
* @param options.remember Whether to persist the directory across sessions.
|
|
1061
|
-
*/
|
|
1062
|
-
public async addAdditionalDirectory(
|
|
1063
|
-
directory: string,
|
|
1064
|
-
options?: { remember?: boolean },
|
|
1065
|
-
): Promise<void> {
|
|
1066
|
-
const resolvedPath = path.isAbsolute(directory)
|
|
1067
|
-
? directory
|
|
1068
|
-
: path.resolve(this.workdir, directory);
|
|
1069
|
-
this.permissionManager.addInstanceAdditionalDirectory(resolvedPath);
|
|
1070
|
-
if (options?.remember) {
|
|
1071
|
-
await this.configurationService.addAdditionalDirectory(
|
|
1072
|
-
this.workdir,
|
|
1073
|
-
resolvedPath,
|
|
1074
|
-
);
|
|
1075
|
-
}
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
/**
|
|
1079
|
-
* Get the effective additional directories for this session (config +
|
|
1080
|
-
* session-level union), matching what is listed in the system prompt.
|
|
1081
|
-
*/
|
|
1082
|
-
public getAdditionalDirectories(): string[] {
|
|
1083
|
-
return this.permissionManager.getEffectiveAdditionalDirectories();
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
// ========== MCP Management Methods ==========
|
|
1087
|
-
|
|
1088
|
-
/** Get all MCP server status */
|
|
1089
|
-
public getMcpServers(): McpServerStatus[] {
|
|
1090
|
-
return this.mcpManager.getAllServers();
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
/** Connect MCP server */
|
|
1094
|
-
public async connectMcpServer(serverName: string): Promise<boolean> {
|
|
1095
|
-
return await this.mcpManager.connectServer(serverName);
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
/** Disconnect MCP server */
|
|
1099
|
-
public async disconnectMcpServer(serverName: string): Promise<boolean> {
|
|
1100
|
-
return await this.mcpManager.disconnectServer(serverName);
|
|
1101
|
-
}
|
|
1102
|
-
|
|
1103
|
-
// ========== Slash Command Management Methods ==========
|
|
1104
|
-
|
|
1105
|
-
/** Get all available slash commands */
|
|
1106
|
-
public getSlashCommands(): SlashCommand[] {
|
|
1107
|
-
return this.slashCommandManager.getCommands();
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
/** Check if slash command exists */
|
|
1111
|
-
public hasSlashCommand(commandId: string): boolean {
|
|
1112
|
-
return this.slashCommandManager.hasCommand(commandId);
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
/** Reload custom commands */
|
|
1116
|
-
public async reloadCustomCommands(): Promise<void> {
|
|
1117
|
-
await this.skillManager.initialize();
|
|
1118
|
-
this.slashCommandManager.reloadCustomCommands();
|
|
1119
|
-
this.slashCommandManager.registerSkillCommands(
|
|
1120
|
-
this.skillManager.getAvailableSkills(),
|
|
1121
|
-
);
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
/** Get custom command details */
|
|
1125
|
-
public getCustomCommand(commandId: string): CustomSlashCommand | undefined {
|
|
1126
|
-
return this.slashCommandManager.getCustomCommand(commandId);
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
/** Get all custom commands */
|
|
1130
|
-
public getCustomCommands(): CustomSlashCommand[] {
|
|
1131
|
-
return this.slashCommandManager.getCustomCommands();
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
/**
|
|
1135
|
-
* Register a custom slash command
|
|
1136
|
-
*/
|
|
1137
|
-
public registerSlashCommand(command: SlashCommand): void {
|
|
1138
|
-
this.slashCommandManager.registerCommand(command);
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
/**
|
|
1142
|
-
* Get the current permission mode
|
|
1143
|
-
*/
|
|
1144
|
-
public getPermissionMode(): PermissionMode {
|
|
1145
|
-
return this.toolManager.getPermissionMode();
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
/**
|
|
1149
|
-
* Get the names of tools currently visible to the AI model (filtered by
|
|
1150
|
-
* permission mode, denied rules, etc.)
|
|
1151
|
-
*/
|
|
1152
|
-
public getAvailableToolNames(): string[] {
|
|
1153
|
-
return this.toolManager.getToolsConfig().map((t) => t.function.name);
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
/**
|
|
1157
|
-
* Set the permission mode
|
|
1158
|
-
* @param mode - The new permission mode
|
|
1159
|
-
*/
|
|
1160
|
-
public setPermissionMode(mode: PermissionMode): void {
|
|
1161
|
-
this.logger?.debug("Setting permission mode", { mode });
|
|
1162
|
-
this.toolManager.setPermissionMode(mode);
|
|
1163
|
-
|
|
1164
|
-
this.planManager.handlePlanModeTransition(mode);
|
|
1165
|
-
|
|
1166
|
-
this.options.callbacks?.onPermissionModeChange?.(mode);
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
/**
|
|
1170
|
-
* Truncate history to a specific index and revert file changes.
|
|
1171
|
-
* @param index - The index of the user message to truncate to.
|
|
1172
|
-
*/
|
|
1173
|
-
public async truncateHistory(index: number): Promise<void> {
|
|
1174
|
-
await this.messageManager.truncateHistory(index, this.reversionManager);
|
|
1175
|
-
// After truncating history, the task list might have changed, so refresh it.
|
|
1176
|
-
// We explicitly load tasks and trigger the callback to ensure UI updates immediately and in order.
|
|
1177
|
-
const tasks = await this.taskManager.listTasks();
|
|
1178
|
-
this.options.callbacks?.onTasksChange?.(tasks);
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
/**
|
|
1182
|
-
* Get the full message thread including parent sessions
|
|
1183
|
-
*/
|
|
1184
|
-
public async getFullMessageThread(): Promise<{
|
|
1185
|
-
messages: Message[];
|
|
1186
|
-
sessionIds: string[];
|
|
1187
|
-
}> {
|
|
1188
|
-
return this.messageManager.getFullMessageThread();
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
/**
|
|
1192
|
-
* Get the current plan file path (for testing and UI)
|
|
1193
|
-
*/
|
|
1194
|
-
public getPlanFilePath(): string | undefined {
|
|
1195
|
-
return this.permissionManager.getPlanFilePath();
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
/**
|
|
1199
|
-
* Get all currently allowed rules (user-defined and default)
|
|
1200
|
-
*/
|
|
1201
|
-
public getAllowedRules(): string[] {
|
|
1202
|
-
return [
|
|
1203
|
-
...this.permissionManager.getAllowedRules(),
|
|
1204
|
-
...this.permissionManager.getDefaultAllowedRules(),
|
|
1205
|
-
];
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
/**
|
|
1209
|
-
* Get only user-defined allowed rules
|
|
1210
|
-
*/
|
|
1211
|
-
public getUserAllowedRules(): string[] {
|
|
1212
|
-
return this.permissionManager.getAllowedRules();
|
|
1213
|
-
}
|
|
1214
|
-
|
|
1215
|
-
/**
|
|
1216
|
-
* Check permission for a tool call (for testing)
|
|
1217
|
-
*/
|
|
1218
|
-
public async checkPermission(
|
|
1219
|
-
context: import("./types/permissions.js").ToolPermissionContext,
|
|
1220
|
-
): Promise<import("./types/permissions.js").PermissionDecision> {
|
|
1221
|
-
return this.permissionManager.checkPermission(context);
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
/**
|
|
1225
|
-
* Add a persistent permission rule
|
|
1226
|
-
* @param rule - The rule to add (e.g., "Bash(ls)")
|
|
1227
|
-
*/
|
|
1228
|
-
public async addPermissionRule(rule: string): Promise<void> {
|
|
1229
|
-
await this.permissionManager.addPermissionRule(rule);
|
|
1230
|
-
}
|
|
1231
|
-
|
|
1232
|
-
/**
|
|
1233
|
-
* Get subagent instance by ID
|
|
1234
|
-
* @param subagentId - The ID of the subagent instance
|
|
1235
|
-
* @returns The subagent instance or null if not found
|
|
1236
|
-
*/
|
|
1237
|
-
public getSubagentInstance(
|
|
1238
|
-
subagentId: string,
|
|
1239
|
-
): import("./managers/subagentManager.js").SubagentInstance | null {
|
|
1240
|
-
return this.subagentManager.getInstance(subagentId);
|
|
1241
|
-
}
|
|
1242
|
-
|
|
1243
|
-
/**
|
|
1244
|
-
* Get the current task list ID
|
|
1245
|
-
*/
|
|
1246
|
-
public get taskListId(): string {
|
|
1247
|
-
return this.taskManager.getTaskListId();
|
|
1248
|
-
}
|
|
1249
|
-
|
|
1250
|
-
/**
|
|
1251
|
-
* Check if there are any running background tasks or active subagents
|
|
1252
|
-
*/
|
|
1253
|
-
public get hasRunningBackgroundWork(): boolean {
|
|
1254
|
-
const runningTasks = this.backgroundTaskManager
|
|
1255
|
-
.getAllTasks()
|
|
1256
|
-
.some((t) => t.status === "running");
|
|
1257
|
-
const activeSubagents =
|
|
1258
|
-
this.subagentManager.getActiveInstances().length > 0;
|
|
1259
|
-
return runningTasks || activeSubagents;
|
|
1260
|
-
}
|
|
1261
|
-
|
|
1262
|
-
/**
|
|
1263
|
-
* Check if there are pending items (messages, bang commands, or background
|
|
1264
|
-
* task notifications) in the message queue. Background task completion
|
|
1265
|
-
* notifications are enqueued before the main agent's dispatch consumes them,
|
|
1266
|
-
* so callers waiting for the agent to fully settle must also wait on this.
|
|
1267
|
-
*/
|
|
1268
|
-
public get hasPendingMessages(): boolean {
|
|
1269
|
-
return this.messageQueue.hasPending();
|
|
1270
|
-
}
|
|
1271
|
-
}
|