wave-agent-sdk 0.4.0 → 0.5.0
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 +28 -5
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +59 -37
- package/dist/constants/tools.d.ts +2 -2
- package/dist/constants/tools.js +2 -2
- package/dist/managers/MemoryRuleManager.js +1 -1
- package/dist/managers/aiManager.d.ts +8 -3
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +35 -9
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +1 -0
- package/dist/managers/backgroundTaskManager.d.ts +35 -0
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -0
- package/dist/managers/backgroundTaskManager.js +249 -0
- package/dist/managers/foregroundTaskManager.d.ts +9 -0
- package/dist/managers/foregroundTaskManager.d.ts.map +1 -0
- package/dist/managers/foregroundTaskManager.js +20 -0
- package/dist/managers/liveConfigManager.d.ts +1 -1
- package/dist/managers/lspManager.d.ts.map +1 -1
- package/dist/managers/lspManager.js +3 -1
- package/dist/managers/messageManager.d.ts +12 -2
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +36 -2
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +1 -7
- package/dist/managers/pluginManager.d.ts.map +1 -1
- package/dist/managers/pluginManager.js +3 -2
- package/dist/managers/slashCommandManager.d.ts +3 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +1 -0
- package/dist/managers/subagentManager.d.ts +11 -2
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +141 -35
- package/dist/managers/toolManager.d.ts +7 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +9 -3
- package/dist/services/GitService.d.ts.map +1 -1
- package/dist/services/GitService.js +6 -2
- package/dist/services/MarketplaceService.d.ts +2 -2
- package/dist/services/MarketplaceService.d.ts.map +1 -1
- package/dist/services/MarketplaceService.js +18 -11
- package/dist/services/MemoryRuleService.d.ts +1 -1
- package/dist/services/MemoryRuleService.d.ts.map +1 -1
- package/dist/services/MemoryRuleService.js +13 -2
- package/dist/services/memory.js +1 -1
- package/dist/tools/bashTool.d.ts +0 -8
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +52 -174
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +6 -5
- package/dist/tools/multiEditTool.d.ts.map +1 -1
- package/dist/tools/multiEditTool.js +7 -6
- package/dist/tools/taskOutputTool.d.ts +3 -0
- package/dist/tools/taskOutputTool.d.ts.map +1 -0
- package/dist/tools/taskOutputTool.js +149 -0
- package/dist/tools/taskStopTool.d.ts +3 -0
- package/dist/tools/taskStopTool.d.ts.map +1 -0
- package/dist/tools/taskStopTool.js +65 -0
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +105 -63
- package/dist/tools/types.d.ts +3 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/marketplace.d.ts +1 -0
- package/dist/types/marketplace.d.ts.map +1 -1
- package/dist/types/messaging.d.ts +1 -0
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/processes.d.ts +24 -4
- package/dist/types/processes.d.ts.map +1 -1
- package/dist/utils/editUtils.d.ts +2 -11
- package/dist/utils/editUtils.d.ts.map +1 -1
- package/dist/utils/editUtils.js +52 -79
- package/dist/utils/messageOperations.d.ts +3 -1
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +5 -1
- package/package.json +5 -5
- package/src/agent.ts +79 -45
- package/src/constants/tools.ts +2 -2
- package/src/managers/MemoryRuleManager.ts +1 -1
- package/src/managers/aiManager.ts +50 -17
- package/src/managers/backgroundBashManager.ts +1 -0
- package/src/managers/backgroundTaskManager.ts +306 -0
- package/src/managers/foregroundTaskManager.ts +26 -0
- package/src/managers/lspManager.ts +3 -1
- package/src/managers/messageManager.ts +48 -2
- package/src/managers/permissionManager.ts +1 -7
- package/src/managers/pluginManager.ts +4 -3
- package/src/managers/slashCommandManager.ts +4 -0
- package/src/managers/subagentManager.ts +171 -31
- package/src/managers/toolManager.ts +16 -4
- package/src/services/GitService.ts +6 -2
- package/src/services/MarketplaceService.ts +30 -12
- package/src/services/MemoryRuleService.ts +18 -6
- package/src/services/memory.ts +1 -1
- package/src/tools/bashTool.ts +73 -200
- package/src/tools/editTool.ts +6 -17
- package/src/tools/multiEditTool.ts +7 -18
- package/src/tools/taskOutputTool.ts +174 -0
- package/src/tools/taskStopTool.ts +72 -0
- package/src/tools/taskTool.ts +130 -74
- package/src/tools/types.ts +3 -0
- package/src/types/marketplace.ts +1 -0
- package/src/types/messaging.ts +1 -0
- package/src/types/processes.ts +33 -4
- package/src/utils/editUtils.ts +65 -103
- package/src/utils/messageOperations.ts +7 -0
package/src/agent.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ForegroundTaskManager } from "./managers/foregroundTaskManager.js";
|
|
1
2
|
import {
|
|
2
3
|
MessageManager,
|
|
3
4
|
type MessageManagerCallbacks,
|
|
@@ -13,9 +14,9 @@ import { McpManager, type McpManagerCallbacks } from "./managers/mcpManager.js";
|
|
|
13
14
|
import { LspManager } from "./managers/lspManager.js";
|
|
14
15
|
import { BashManager } from "./managers/bashManager.js";
|
|
15
16
|
import {
|
|
16
|
-
|
|
17
|
-
type
|
|
18
|
-
} from "./managers/
|
|
17
|
+
BackgroundTaskManager,
|
|
18
|
+
type BackgroundTaskManagerCallbacks,
|
|
19
|
+
} from "./managers/backgroundTaskManager.js";
|
|
19
20
|
import { SlashCommandManager } from "./managers/slashCommandManager.js";
|
|
20
21
|
import { PluginManager } from "./managers/pluginManager.js";
|
|
21
22
|
import { HookManager } from "./managers/hookManager.js";
|
|
@@ -38,6 +39,8 @@ import type {
|
|
|
38
39
|
Usage,
|
|
39
40
|
PermissionMode,
|
|
40
41
|
PermissionCallback,
|
|
42
|
+
BackgroundTask,
|
|
43
|
+
ForegroundTask,
|
|
41
44
|
} from "./types/index.js";
|
|
42
45
|
import { MemoryRuleManager } from "./managers/MemoryRuleManager.js";
|
|
43
46
|
import { LiveConfigManager } from "./managers/liveConfigManager.js";
|
|
@@ -100,10 +103,12 @@ export interface AgentOptions {
|
|
|
100
103
|
|
|
101
104
|
export interface AgentCallbacks
|
|
102
105
|
extends MessageManagerCallbacks,
|
|
103
|
-
|
|
106
|
+
BackgroundTaskManagerCallbacks,
|
|
104
107
|
McpManagerCallbacks,
|
|
105
108
|
SubagentManagerCallbacks {
|
|
109
|
+
onTasksChange?: (tasks: BackgroundTask[]) => void;
|
|
106
110
|
onPermissionModeChange?: (mode: PermissionMode) => void;
|
|
111
|
+
onBackgroundCurrentTask?: () => void;
|
|
107
112
|
}
|
|
108
113
|
|
|
109
114
|
export class Agent {
|
|
@@ -111,7 +116,7 @@ export class Agent {
|
|
|
111
116
|
private aiManager: AIManager;
|
|
112
117
|
|
|
113
118
|
private bashManager: BashManager | null = null;
|
|
114
|
-
private
|
|
119
|
+
private backgroundTaskManager: BackgroundTaskManager;
|
|
115
120
|
private logger?: Logger; // Add optional logger property
|
|
116
121
|
private toolManager: ToolManager; // Add tool registry instance
|
|
117
122
|
private mcpManager: McpManager; // Add MCP manager instance
|
|
@@ -126,6 +131,7 @@ export class Agent {
|
|
|
126
131
|
private reversionManager: ReversionManager;
|
|
127
132
|
private memoryRuleManager: MemoryRuleManager; // Add memory rule manager instance
|
|
128
133
|
private liveConfigManager: LiveConfigManager; // Add live configuration manager
|
|
134
|
+
private foregroundTaskManager: ForegroundTaskManager;
|
|
129
135
|
private configurationService: ConfigurationService; // Add configuration service
|
|
130
136
|
private workdir: string; // Working directory
|
|
131
137
|
private systemPrompt?: string; // Custom system prompt
|
|
@@ -200,8 +206,15 @@ export class Agent {
|
|
|
200
206
|
// Store options for dynamic configuration resolution
|
|
201
207
|
this.options = options;
|
|
202
208
|
|
|
203
|
-
this.
|
|
204
|
-
|
|
209
|
+
this.foregroundTaskManager = new ForegroundTaskManager();
|
|
210
|
+
|
|
211
|
+
this.backgroundTaskManager = new BackgroundTaskManager({
|
|
212
|
+
callbacks: {
|
|
213
|
+
...callbacks,
|
|
214
|
+
onTasksChange: (tasks) => {
|
|
215
|
+
callbacks.onTasksChange?.(tasks);
|
|
216
|
+
},
|
|
217
|
+
},
|
|
205
218
|
workdir: this.workdir,
|
|
206
219
|
});
|
|
207
220
|
this.mcpManager = new McpManager({ callbacks, logger: this.logger }); // Initialize MCP manager
|
|
@@ -230,11 +243,17 @@ export class Agent {
|
|
|
230
243
|
workdir: this.workdir,
|
|
231
244
|
});
|
|
232
245
|
|
|
246
|
+
// Initialize memory rule manager
|
|
247
|
+
this.memoryRuleManager = new MemoryRuleManager({
|
|
248
|
+
workdir: this.workdir,
|
|
249
|
+
});
|
|
250
|
+
|
|
233
251
|
// Initialize MessageManager
|
|
234
252
|
this.messageManager = new MessageManager({
|
|
235
253
|
callbacks,
|
|
236
254
|
workdir: this.workdir,
|
|
237
255
|
logger: this.logger,
|
|
256
|
+
memoryRuleManager: this.memoryRuleManager,
|
|
238
257
|
});
|
|
239
258
|
|
|
240
259
|
// Initialize ReversionManager
|
|
@@ -242,11 +261,6 @@ export class Agent {
|
|
|
242
261
|
new ReversionService(this.messageManager.getTranscriptPath()),
|
|
243
262
|
);
|
|
244
263
|
|
|
245
|
-
// Initialize memory rule manager
|
|
246
|
-
this.memoryRuleManager = new MemoryRuleManager({
|
|
247
|
-
workdir: this.workdir,
|
|
248
|
-
});
|
|
249
|
-
|
|
250
264
|
// Create a wrapper for canUseTool that triggers notification hooks
|
|
251
265
|
const canUseToolWithNotification: PermissionCallback | undefined =
|
|
252
266
|
options.canUseTool
|
|
@@ -298,6 +312,8 @@ export class Agent {
|
|
|
298
312
|
reversionManager: this.reversionManager,
|
|
299
313
|
permissionMode: options.permissionMode, // Let PermissionManager handle defaultMode resolution
|
|
300
314
|
canUseToolCallback: canUseToolWithNotification,
|
|
315
|
+
backgroundTaskManager: this.backgroundTaskManager,
|
|
316
|
+
foregroundTaskManager: this.foregroundTaskManager,
|
|
301
317
|
}); // Initialize tool registry with permission support
|
|
302
318
|
this.liveConfigManager = new LiveConfigManager({
|
|
303
319
|
workdir: this.workdir,
|
|
@@ -331,6 +347,8 @@ export class Agent {
|
|
|
331
347
|
getLanguage: () => this.getLanguage(),
|
|
332
348
|
hookManager: this.hookManager,
|
|
333
349
|
onUsageAdded: (usage) => this.addUsage(usage),
|
|
350
|
+
backgroundTaskManager: this.backgroundTaskManager,
|
|
351
|
+
memoryRuleManager: this.memoryRuleManager,
|
|
334
352
|
});
|
|
335
353
|
|
|
336
354
|
// Initialize AI manager with resolved configuration
|
|
@@ -338,7 +356,7 @@ export class Agent {
|
|
|
338
356
|
messageManager: this.messageManager,
|
|
339
357
|
toolManager: this.toolManager,
|
|
340
358
|
logger: this.logger,
|
|
341
|
-
|
|
359
|
+
backgroundTaskManager: this.backgroundTaskManager,
|
|
342
360
|
hookManager: this.hookManager,
|
|
343
361
|
permissionManager: this.permissionManager,
|
|
344
362
|
callbacks: {
|
|
@@ -362,6 +380,7 @@ export class Agent {
|
|
|
362
380
|
this.slashCommandManager = new SlashCommandManager({
|
|
363
381
|
messageManager: this.messageManager,
|
|
364
382
|
aiManager: this.aiManager,
|
|
383
|
+
backgroundTaskManager: this.backgroundTaskManager,
|
|
365
384
|
workdir: this.workdir,
|
|
366
385
|
logger: this.logger,
|
|
367
386
|
});
|
|
@@ -456,34 +475,8 @@ export class Agent {
|
|
|
456
475
|
}
|
|
457
476
|
|
|
458
477
|
/** Get combined memory content (project + user + modular rules) */
|
|
459
|
-
public
|
|
460
|
-
|
|
461
|
-
if (this._projectMemoryContent.trim()) {
|
|
462
|
-
combined += this._projectMemoryContent;
|
|
463
|
-
}
|
|
464
|
-
if (this._userMemoryContent.trim()) {
|
|
465
|
-
if (combined) {
|
|
466
|
-
combined += "\n\n";
|
|
467
|
-
}
|
|
468
|
-
combined += this._userMemoryContent;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
// Add modular memory rules
|
|
472
|
-
const filesInContext = this.messageManager.getFilesInContext();
|
|
473
|
-
const activeRules = this.memoryRuleManager.getActiveRules(filesInContext);
|
|
474
|
-
if (activeRules.length > 0) {
|
|
475
|
-
this.logger?.debug(
|
|
476
|
-
`Active modular rules (${activeRules.length}): ${activeRules.map((r) => r.id).join(", ")}`,
|
|
477
|
-
);
|
|
478
|
-
if (combined) {
|
|
479
|
-
combined += "\n\n";
|
|
480
|
-
}
|
|
481
|
-
combined += activeRules.map((r) => r.content).join("\n\n");
|
|
482
|
-
} else {
|
|
483
|
-
this.logger?.debug("No active modular rules for current context");
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
return combined;
|
|
478
|
+
public async getCombinedMemory(): Promise<string> {
|
|
479
|
+
return this.messageManager.getCombinedMemory();
|
|
487
480
|
}
|
|
488
481
|
|
|
489
482
|
/** Get AI loading status */
|
|
@@ -506,12 +499,25 @@ export class Agent {
|
|
|
506
499
|
id: string,
|
|
507
500
|
filter?: string,
|
|
508
501
|
): { stdout: string; stderr: string; status: string } | null {
|
|
509
|
-
return this.
|
|
502
|
+
return this.backgroundTaskManager.getOutput(id, filter);
|
|
510
503
|
}
|
|
511
504
|
|
|
512
505
|
/** Kill background bash shell */
|
|
513
506
|
public killBackgroundShell(id: string): boolean {
|
|
514
|
-
return this.
|
|
507
|
+
return this.backgroundTaskManager.stopTask(id);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/** Get background task output */
|
|
511
|
+
public getBackgroundTaskOutput(
|
|
512
|
+
id: string,
|
|
513
|
+
filter?: string,
|
|
514
|
+
): { stdout: string; stderr: string; status: string } | null {
|
|
515
|
+
return this.backgroundTaskManager.getOutput(id, filter);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/** Stop background task */
|
|
519
|
+
public stopBackgroundTask(id: string): boolean {
|
|
520
|
+
return this.backgroundTaskManager.stopTask(id);
|
|
515
521
|
}
|
|
516
522
|
|
|
517
523
|
/**
|
|
@@ -938,14 +944,42 @@ export class Agent {
|
|
|
938
944
|
this.slashCommandManager.abortCurrentCommand();
|
|
939
945
|
}
|
|
940
946
|
|
|
947
|
+
/**
|
|
948
|
+
* Register a foreground task that can be backgrounded
|
|
949
|
+
*/
|
|
950
|
+
public registerForegroundTask(task: ForegroundTask): void {
|
|
951
|
+
this.foregroundTaskManager.registerForegroundTask(task);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Unregister a foreground task
|
|
956
|
+
*/
|
|
957
|
+
public unregisterForegroundTask(id: string): void {
|
|
958
|
+
this.foregroundTaskManager.unregisterForegroundTask(id);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* Background the current foreground task
|
|
963
|
+
*/
|
|
964
|
+
public async backgroundCurrentTask(): Promise<void> {
|
|
965
|
+
await this.foregroundTaskManager.backgroundCurrentTask();
|
|
966
|
+
this.options.callbacks?.onBackgroundCurrentTask?.();
|
|
967
|
+
|
|
968
|
+
// If there was no foreground task (e.g. a tool that doesn't register one),
|
|
969
|
+
// or even if there was, we should stop the AI recursion loop.
|
|
970
|
+
if (!this.foregroundTaskManager.hasActiveTasks()) {
|
|
971
|
+
this.aiManager.abortRecursion();
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
|
|
941
975
|
/** Destroy managers, clean up resources */
|
|
942
976
|
public async destroy(): Promise<void> {
|
|
943
977
|
await this.messageManager.saveSession();
|
|
944
978
|
this.abortAIMessage(); // This will abort tools including Task tool (subagents)
|
|
945
979
|
this.abortBashCommand();
|
|
946
980
|
this.abortSlashCommand();
|
|
947
|
-
// Cleanup background
|
|
948
|
-
this.
|
|
981
|
+
// Cleanup background task manager
|
|
982
|
+
this.backgroundTaskManager.cleanup();
|
|
949
983
|
// Cleanup MCP connections
|
|
950
984
|
await this.mcpManager.cleanup();
|
|
951
985
|
// Cleanup LSP connections
|
package/src/constants/tools.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
|
|
2
2
|
export const BASH_TOOL_NAME = "Bash";
|
|
3
|
-
export const
|
|
4
|
-
export const
|
|
3
|
+
export const TASK_OUTPUT_TOOL_NAME = "TaskOutput";
|
|
4
|
+
export const TASK_STOP_TOOL_NAME = "TaskStop";
|
|
5
5
|
export const DELETE_FILE_TOOL_NAME = "Delete";
|
|
6
6
|
export const EDIT_TOOL_NAME = "Edit";
|
|
7
7
|
export const EXIT_PLAN_MODE_TOOL_NAME = "ExitPlanMode";
|
|
@@ -148,7 +148,7 @@ export class MemoryRuleManager {
|
|
|
148
148
|
getActiveRules(filesInContext: string[]): MemoryRule[] {
|
|
149
149
|
const activeRules: MemoryRule[] = [];
|
|
150
150
|
for (const rule of Object.values(this.state.rules)) {
|
|
151
|
-
if (this.service.isRuleActive(rule, filesInContext)) {
|
|
151
|
+
if (this.service.isRuleActive(rule, filesInContext, this.workdir)) {
|
|
152
152
|
activeRules.push(rule);
|
|
153
153
|
}
|
|
154
154
|
}
|
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
import { getMessagesToCompress } from "../utils/messageOperations.js";
|
|
7
7
|
import { convertMessagesForAPI } from "../utils/convertMessagesForAPI.js";
|
|
8
8
|
import { calculateComprehensiveTotalTokens } from "../utils/tokenCalculation.js";
|
|
9
|
-
import * as memory from "../services/memory.js";
|
|
10
9
|
import * as fs from "node:fs/promises";
|
|
11
10
|
import type {
|
|
12
11
|
Logger,
|
|
@@ -17,7 +16,7 @@ import type {
|
|
|
17
16
|
import type { ToolManager } from "./toolManager.js";
|
|
18
17
|
import type { ToolContext, ToolResult } from "../tools/types.js";
|
|
19
18
|
import type { MessageManager } from "./messageManager.js";
|
|
20
|
-
import type {
|
|
19
|
+
import type { BackgroundTaskManager } from "./backgroundTaskManager.js";
|
|
21
20
|
import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
22
21
|
import type { HookManager } from "./hookManager.js";
|
|
23
22
|
import type { ExtendedHookExecutionContext } from "../types/hooks.js";
|
|
@@ -36,7 +35,7 @@ export interface AIManagerOptions {
|
|
|
36
35
|
messageManager: MessageManager;
|
|
37
36
|
toolManager: ToolManager;
|
|
38
37
|
logger?: Logger;
|
|
39
|
-
|
|
38
|
+
backgroundTaskManager?: BackgroundTaskManager;
|
|
40
39
|
hookManager?: HookManager;
|
|
41
40
|
permissionManager?: PermissionManager;
|
|
42
41
|
callbacks?: AIManagerCallbacks;
|
|
@@ -61,7 +60,7 @@ export class AIManager {
|
|
|
61
60
|
private logger?: Logger;
|
|
62
61
|
private toolManager: ToolManager;
|
|
63
62
|
private messageManager: MessageManager;
|
|
64
|
-
private
|
|
63
|
+
private backgroundTaskManager?: BackgroundTaskManager;
|
|
65
64
|
private hookManager?: HookManager;
|
|
66
65
|
private reversionManager?: import("./reversionManager.js").ReversionManager;
|
|
67
66
|
private permissionManager?: PermissionManager;
|
|
@@ -80,7 +79,7 @@ export class AIManager {
|
|
|
80
79
|
constructor(options: AIManagerOptions) {
|
|
81
80
|
this.messageManager = options.messageManager;
|
|
82
81
|
this.toolManager = options.toolManager;
|
|
83
|
-
this.
|
|
82
|
+
this.backgroundTaskManager = options.backgroundTaskManager;
|
|
84
83
|
this.hookManager = options.hookManager;
|
|
85
84
|
this.reversionManager = options.reversionManager;
|
|
86
85
|
this.permissionManager = options.permissionManager;
|
|
@@ -160,6 +159,15 @@ export class AIManager {
|
|
|
160
159
|
this.setIsLoading(false);
|
|
161
160
|
}
|
|
162
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Abort the AI recursion loop immediately.
|
|
164
|
+
* This is used when a tool is backgrounded via Ctrl-B, even if no foreground task was active.
|
|
165
|
+
*/
|
|
166
|
+
public abortRecursion(): void {
|
|
167
|
+
this.logger?.info("Aborting AI recursion loop");
|
|
168
|
+
this.abortAIMessage();
|
|
169
|
+
}
|
|
170
|
+
|
|
163
171
|
// Helper method to generate compactParams
|
|
164
172
|
private generateCompactParams(
|
|
165
173
|
toolName: string,
|
|
@@ -297,9 +305,6 @@ export class AIManager {
|
|
|
297
305
|
return;
|
|
298
306
|
}
|
|
299
307
|
|
|
300
|
-
// Save session in each recursion to ensure message persistence
|
|
301
|
-
await this.messageManager.saveSession();
|
|
302
|
-
|
|
303
308
|
// Only create new AbortControllers for the initial call (recursionDepth === 0)
|
|
304
309
|
// For recursive calls, reuse existing controllers to maintain abort signal
|
|
305
310
|
let abortController: AbortController;
|
|
@@ -314,10 +319,14 @@ export class AIManager {
|
|
|
314
319
|
this.toolAbortController = toolAbortController;
|
|
315
320
|
} else {
|
|
316
321
|
// Reuse existing controllers for recursive calls
|
|
317
|
-
|
|
318
|
-
|
|
322
|
+
// Fallback to new controllers if they were cleared (should not happen in normal flow but good for tests)
|
|
323
|
+
abortController = this.abortController || new AbortController();
|
|
324
|
+
toolAbortController = this.toolAbortController || new AbortController();
|
|
319
325
|
}
|
|
320
326
|
|
|
327
|
+
// Save session in each recursion to ensure message persistence
|
|
328
|
+
await this.messageManager.saveSession();
|
|
329
|
+
|
|
321
330
|
// Only set loading state for the initial call
|
|
322
331
|
if (recursionDepth === 0) {
|
|
323
332
|
this.setIsLoading(true);
|
|
@@ -333,9 +342,7 @@ export class AIManager {
|
|
|
333
342
|
|
|
334
343
|
try {
|
|
335
344
|
// Get combined memory content
|
|
336
|
-
const combinedMemory = await
|
|
337
|
-
this.workdir,
|
|
338
|
-
);
|
|
345
|
+
const combinedMemory = await this.messageManager.getCombinedMemory();
|
|
339
346
|
|
|
340
347
|
// Track if assistant message has been created
|
|
341
348
|
let assistantMessageCreated = false;
|
|
@@ -618,7 +625,7 @@ export class AIManager {
|
|
|
618
625
|
// Create tool execution context
|
|
619
626
|
const context: ToolContext = {
|
|
620
627
|
abortSignal: toolAbortController.signal,
|
|
621
|
-
|
|
628
|
+
backgroundTaskManager: this.backgroundTaskManager,
|
|
622
629
|
workdir: this.workdir,
|
|
623
630
|
messageId: this.messageManager.getMessages().slice(-1)[0]?.id,
|
|
624
631
|
};
|
|
@@ -630,6 +637,23 @@ export class AIManager {
|
|
|
630
637
|
context,
|
|
631
638
|
);
|
|
632
639
|
|
|
640
|
+
// Check if the tool was backgrounded via Ctrl-B
|
|
641
|
+
// If it was backgrounded, we should abort the AI recursion
|
|
642
|
+
if (
|
|
643
|
+
toolResult.success &&
|
|
644
|
+
toolResult.content.includes(
|
|
645
|
+
"Command was manually backgrounded by user",
|
|
646
|
+
)
|
|
647
|
+
) {
|
|
648
|
+
this.logger?.info(
|
|
649
|
+
`Tool ${toolName} was backgrounded via Ctrl-B, aborting AI recursion`,
|
|
650
|
+
);
|
|
651
|
+
// Use abortAIMessage directly instead of abortRecursion to avoid double logging
|
|
652
|
+
// and ensure we don't trigger the "Request was aborted" error block
|
|
653
|
+
this.abortAIMessage();
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
|
|
633
657
|
// Update message state - tool execution completed
|
|
634
658
|
this.messageManager.updateToolBlock({
|
|
635
659
|
id: toolId,
|
|
@@ -709,9 +733,18 @@ export class AIManager {
|
|
|
709
733
|
}
|
|
710
734
|
}
|
|
711
735
|
} catch (error) {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
736
|
+
// Check if the error is an abort error
|
|
737
|
+
// Use the local variables to avoid null reference if this.abortController was cleared
|
|
738
|
+
const isCurrentlyAborted =
|
|
739
|
+
abortController.signal.aborted || toolAbortController.signal.aborted;
|
|
740
|
+
|
|
741
|
+
if (isCurrentlyAborted) {
|
|
742
|
+
this.logger?.info("AI message processing was aborted");
|
|
743
|
+
} else {
|
|
744
|
+
this.messageManager.addErrorBlock(
|
|
745
|
+
error instanceof Error ? error.message : "Unknown error occurred",
|
|
746
|
+
);
|
|
747
|
+
}
|
|
715
748
|
} finally {
|
|
716
749
|
// Only execute cleanup and hooks for the initial call
|
|
717
750
|
if (recursionDepth === 0) {
|