wave-agent-sdk 0.6.1 → 0.6.2
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 +0 -5
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +3 -67
- package/dist/constants/subagents.d.ts +5 -0
- package/dist/constants/subagents.d.ts.map +1 -0
- package/dist/constants/subagents.js +4 -0
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +9 -25
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +4 -0
- package/dist/managers/messageManager.d.ts +0 -18
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +1 -36
- package/dist/managers/reversionManager.d.ts.map +1 -1
- package/dist/managers/reversionManager.js +23 -2
- package/dist/managers/slashCommandManager.js +1 -1
- package/dist/managers/subagentManager.d.ts +4 -14
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +35 -109
- package/dist/{constants/prompts.d.ts → prompts/index.d.ts} +4 -6
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/{constants/prompts.js → prompts/index.js} +124 -9
- package/dist/services/aiService.js +1 -1
- package/dist/services/taskManager.d.ts +5 -1
- package/dist/services/taskManager.d.ts.map +1 -1
- package/dist/services/taskManager.js +6 -0
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +6 -2
- package/dist/tools/exitPlanMode.js +1 -1
- package/dist/tools/taskManagementTools.d.ts.map +1 -1
- package/dist/tools/taskManagementTools.js +8 -0
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +32 -2
- package/dist/tools/types.d.ts +2 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/types/messaging.d.ts +1 -11
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/processes.d.ts +5 -0
- package/dist/types/processes.d.ts.map +1 -1
- package/dist/utils/builtinSubagents.d.ts.map +1 -1
- package/dist/utils/builtinSubagents.js +28 -50
- package/dist/utils/editUtils.d.ts.map +1 -1
- package/dist/utils/editUtils.js +2 -2
- package/dist/utils/gitUtils.d.ts +7 -0
- package/dist/utils/gitUtils.d.ts.map +1 -0
- package/dist/utils/gitUtils.js +24 -0
- package/dist/utils/messageOperations.d.ts +1 -23
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +0 -49
- package/package.json +1 -1
- package/src/agent.ts +3 -89
- package/src/constants/subagents.ts +4 -0
- package/src/managers/aiManager.ts +9 -25
- package/src/managers/backgroundTaskManager.ts +5 -0
- package/src/managers/messageManager.ts +0 -80
- package/src/managers/reversionManager.ts +26 -2
- package/src/managers/slashCommandManager.ts +1 -1
- package/src/managers/subagentManager.ts +42 -145
- package/src/{constants/prompts.ts → prompts/index.ts} +132 -12
- package/src/services/aiService.ts +1 -1
- package/src/services/taskManager.ts +8 -1
- package/src/tools/bashTool.ts +6 -2
- package/src/tools/exitPlanMode.ts +1 -1
- package/src/tools/taskManagementTools.ts +18 -0
- package/src/tools/taskTool.ts +39 -1
- package/src/tools/types.ts +2 -0
- package/src/types/messaging.ts +0 -12
- package/src/types/processes.ts +5 -0
- package/src/utils/builtinSubagents.ts +41 -51
- package/src/utils/editUtils.ts +2 -6
- package/src/utils/gitUtils.ts +24 -0
- package/src/utils/messageOperations.ts +1 -93
- package/dist/constants/prompts.d.ts.map +0 -1
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import * as os from "node:os";
|
|
2
|
-
import * as path from "node:path";
|
|
3
1
|
import {
|
|
4
2
|
callAgent,
|
|
5
3
|
compressMessages,
|
|
@@ -7,7 +5,6 @@ import {
|
|
|
7
5
|
} from "../services/aiService.js";
|
|
8
6
|
import { convertMessagesForAPI } from "../utils/convertMessagesForAPI.js";
|
|
9
7
|
import { calculateComprehensiveTotalTokens } from "../utils/tokenCalculation.js";
|
|
10
|
-
import * as fsSync from "node:fs";
|
|
11
8
|
import * as fs from "node:fs/promises";
|
|
12
9
|
import type {
|
|
13
10
|
Logger,
|
|
@@ -23,24 +20,7 @@ import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
|
23
20
|
import type { HookManager } from "./hookManager.js";
|
|
24
21
|
import type { ExtendedHookExecutionContext } from "../types/hooks.js";
|
|
25
22
|
import type { PermissionManager } from "./permissionManager.js";
|
|
26
|
-
import { buildSystemPrompt } from "../
|
|
27
|
-
|
|
28
|
-
function isGitRepository(dirPath: string): string {
|
|
29
|
-
try {
|
|
30
|
-
// Check if .git directory exists in current directory or any parent directory
|
|
31
|
-
let currentPath = path.resolve(dirPath);
|
|
32
|
-
while (currentPath !== path.dirname(currentPath)) {
|
|
33
|
-
const gitPath = path.join(currentPath, ".git");
|
|
34
|
-
if (fsSync.existsSync(gitPath)) {
|
|
35
|
-
return "Yes";
|
|
36
|
-
}
|
|
37
|
-
currentPath = path.dirname(currentPath);
|
|
38
|
-
}
|
|
39
|
-
return "No";
|
|
40
|
-
} catch {
|
|
41
|
-
return "No";
|
|
42
|
-
}
|
|
43
|
-
}
|
|
23
|
+
import { buildSystemPrompt } from "../prompts/index.js";
|
|
44
24
|
|
|
45
25
|
export interface AIManagerCallbacks {
|
|
46
26
|
onCompressionStateChange?: (isCompressing: boolean) => void;
|
|
@@ -399,12 +379,9 @@ export class AIManager {
|
|
|
399
379
|
filteredToolPlugins,
|
|
400
380
|
{
|
|
401
381
|
workdir: this.workdir,
|
|
402
|
-
isGitRepo: isGitRepository(this.workdir),
|
|
403
|
-
platform: os.platform(),
|
|
404
|
-
osVersion: `${os.type()} ${os.release()}`,
|
|
405
|
-
today: new Date().toISOString().split("T")[0],
|
|
406
382
|
memory: combinedMemory,
|
|
407
383
|
language: this.getLanguage(),
|
|
384
|
+
isSubagent: !!this.subagentType,
|
|
408
385
|
planMode: planModeOptions,
|
|
409
386
|
},
|
|
410
387
|
), // Pass custom system prompt
|
|
@@ -643,6 +620,13 @@ export class AIManager {
|
|
|
643
620
|
messageId: this.messageManager.getMessages().slice(-1)[0]?.id,
|
|
644
621
|
sessionId: this.messageManager.getSessionId(),
|
|
645
622
|
taskManager: this.taskManager,
|
|
623
|
+
onShortResultUpdate: (shortResult: string) => {
|
|
624
|
+
this.messageManager.updateToolBlock({
|
|
625
|
+
id: toolId,
|
|
626
|
+
shortResult,
|
|
627
|
+
stage: "running", // Keep it in running stage while updating shortResult
|
|
628
|
+
});
|
|
629
|
+
},
|
|
646
630
|
};
|
|
647
631
|
|
|
648
632
|
// Execute tool
|
|
@@ -285,6 +285,11 @@ export class BackgroundTaskManager {
|
|
|
285
285
|
}
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
+
// If it's a subagent task, we should also notify the subagent manager to cleanup
|
|
289
|
+
// However, to avoid circular dependency, we rely on the onStop callback
|
|
290
|
+
// which is already set to instance.aiManager.abortAIMessage()
|
|
291
|
+
// The subagentManager.cleanupInstance will be called by the tool or by status change.
|
|
292
|
+
|
|
288
293
|
task.status = "killed";
|
|
289
294
|
task.endTime = Date.now();
|
|
290
295
|
task.runtime = task.endTime - task.startTime;
|
|
@@ -6,15 +6,10 @@ import {
|
|
|
6
6
|
addCommandOutputMessage,
|
|
7
7
|
updateCommandOutputInMessage,
|
|
8
8
|
completeCommandInMessage,
|
|
9
|
-
addSubagentBlockToMessage,
|
|
10
|
-
updateSubagentBlockInMessage,
|
|
11
9
|
removeLastUserMessage,
|
|
12
10
|
UserMessageParams,
|
|
13
|
-
type AddSubagentBlockParams,
|
|
14
|
-
type UpdateSubagentBlockParams,
|
|
15
11
|
type AgentToolBlockUpdateParams,
|
|
16
12
|
} from "../utils/messageOperations.js";
|
|
17
|
-
import type { SubagentConfiguration } from "../utils/subagentParser.js";
|
|
18
13
|
import type { Logger, Message, Usage, SlashCommand } from "../types/index.js";
|
|
19
14
|
import { join } from "path";
|
|
20
15
|
import {
|
|
@@ -59,23 +54,9 @@ export interface MessageManagerCallbacks {
|
|
|
59
54
|
onInfoBlockAdded?: (content: string) => void;
|
|
60
55
|
// Rewind callbacks
|
|
61
56
|
onShowRewind?: () => void;
|
|
62
|
-
// Subagent callbacks
|
|
63
|
-
onSubAgentBlockAdded?: (
|
|
64
|
-
subagentId: string,
|
|
65
|
-
parameters: {
|
|
66
|
-
description: string;
|
|
67
|
-
prompt: string;
|
|
68
|
-
subagent_type: string;
|
|
69
|
-
},
|
|
70
|
-
) => void;
|
|
71
|
-
onSubAgentBlockUpdated?: (
|
|
72
|
-
subagentId: string,
|
|
73
|
-
status: "active" | "completed" | "error" | "aborted",
|
|
74
|
-
) => void;
|
|
75
57
|
onFileHistoryBlockAdded?: (
|
|
76
58
|
snapshots: import("../types/reversion.js").FileSnapshot[],
|
|
77
59
|
) => void;
|
|
78
|
-
onSubagentTaskStopRequested?: (subagentId: string) => void;
|
|
79
60
|
}
|
|
80
61
|
|
|
81
62
|
export interface MessageManagerOptions {
|
|
@@ -505,58 +486,6 @@ export class MessageManager {
|
|
|
505
486
|
this.callbacks.onCompleteCommandMessage?.(command, exitCode);
|
|
506
487
|
}
|
|
507
488
|
|
|
508
|
-
// Subagent block methods
|
|
509
|
-
public addSubagentBlock(
|
|
510
|
-
subagentId: string,
|
|
511
|
-
subagentName: string,
|
|
512
|
-
sessionId: string,
|
|
513
|
-
configuration: SubagentConfiguration,
|
|
514
|
-
status: "active" | "completed" | "error" | "aborted" = "active",
|
|
515
|
-
parameters: {
|
|
516
|
-
description: string;
|
|
517
|
-
prompt: string;
|
|
518
|
-
subagent_type: string;
|
|
519
|
-
},
|
|
520
|
-
runInBackground?: boolean,
|
|
521
|
-
): void {
|
|
522
|
-
const params: AddSubagentBlockParams = {
|
|
523
|
-
messages: this.messages,
|
|
524
|
-
subagentId,
|
|
525
|
-
subagentName,
|
|
526
|
-
sessionId,
|
|
527
|
-
status,
|
|
528
|
-
configuration,
|
|
529
|
-
runInBackground,
|
|
530
|
-
};
|
|
531
|
-
const updatedMessages = addSubagentBlockToMessage(params);
|
|
532
|
-
this.setMessages(updatedMessages);
|
|
533
|
-
this.callbacks.onSubAgentBlockAdded?.(params.subagentId, parameters);
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
public updateSubagentBlock(
|
|
537
|
-
subagentId: string,
|
|
538
|
-
updates: Partial<{
|
|
539
|
-
status: "active" | "completed" | "error" | "aborted";
|
|
540
|
-
sessionId: string;
|
|
541
|
-
runInBackground: boolean;
|
|
542
|
-
}>,
|
|
543
|
-
): void {
|
|
544
|
-
const updatedMessages = updateSubagentBlockInMessage(
|
|
545
|
-
this.messages,
|
|
546
|
-
subagentId,
|
|
547
|
-
updates,
|
|
548
|
-
);
|
|
549
|
-
this.setMessages(updatedMessages);
|
|
550
|
-
const params: UpdateSubagentBlockParams = {
|
|
551
|
-
messages: this.messages,
|
|
552
|
-
subagentId,
|
|
553
|
-
status: updates.status || "active",
|
|
554
|
-
};
|
|
555
|
-
if (updates.status) {
|
|
556
|
-
this.callbacks.onSubAgentBlockUpdated?.(params.subagentId, params.status);
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
|
|
560
489
|
/**
|
|
561
490
|
* Trigger usage change callback with all usage data from assistant messages
|
|
562
491
|
*/
|
|
@@ -773,15 +702,6 @@ export class MessageManager {
|
|
|
773
702
|
targetIndexInSession,
|
|
774
703
|
);
|
|
775
704
|
|
|
776
|
-
// Identify subagent tasks to stop
|
|
777
|
-
for (const message of messagesToRemove) {
|
|
778
|
-
for (const block of message.blocks) {
|
|
779
|
-
if (block.type === "subagent" && block.subagentId) {
|
|
780
|
-
this.callbacks.onSubagentTaskStopRequested?.(block.subagentId);
|
|
781
|
-
}
|
|
782
|
-
}
|
|
783
|
-
}
|
|
784
|
-
|
|
785
705
|
// Update target session file
|
|
786
706
|
this.sessionId = targetSessionId;
|
|
787
707
|
this.rootSessionId = targetSessionData.rootSessionId || targetSessionId;
|
|
@@ -123,10 +123,15 @@ export class ReversionManager {
|
|
|
123
123
|
const sortedSnapshots = snapshots.sort((a, b) => b.timestamp - a.timestamp);
|
|
124
124
|
|
|
125
125
|
let revertedCount = 0;
|
|
126
|
+
const affectedTaskListIds = new Set<string>();
|
|
127
|
+
|
|
126
128
|
for (const snapshot of sortedSnapshots) {
|
|
127
129
|
try {
|
|
128
|
-
if (
|
|
129
|
-
//
|
|
130
|
+
if (snapshot.operation === "create") {
|
|
131
|
+
// For 'create' operations, we should hard delete the file upon reversion
|
|
132
|
+
await fs.rm(snapshot.filePath, { force: true });
|
|
133
|
+
} else if (!snapshot.snapshotPath) {
|
|
134
|
+
// Fallback for older snapshots or if snapshotPath is missing
|
|
130
135
|
await fs.rm(snapshot.filePath, { force: true });
|
|
131
136
|
} else {
|
|
132
137
|
// Restore previous content
|
|
@@ -141,12 +146,31 @@ export class ReversionManager {
|
|
|
141
146
|
await fs.rm(snapshot.filePath, { force: true });
|
|
142
147
|
}
|
|
143
148
|
}
|
|
149
|
+
|
|
150
|
+
// Check if this is a task file and track the task list ID
|
|
151
|
+
if (snapshot.filePath.includes("/.wave/tasks/")) {
|
|
152
|
+
const parts = snapshot.filePath.split("/.wave/tasks/");
|
|
153
|
+
if (parts.length > 1) {
|
|
154
|
+
const taskListId = parts[1].split("/")[0];
|
|
155
|
+
if (taskListId) {
|
|
156
|
+
affectedTaskListIds.add(taskListId);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
144
161
|
revertedCount++;
|
|
145
162
|
} catch (error) {
|
|
146
163
|
console.error(`Failed to revert file ${snapshot.filePath}:`, error);
|
|
147
164
|
}
|
|
148
165
|
}
|
|
149
166
|
|
|
167
|
+
// Notify TaskManager if any task lists were affected
|
|
168
|
+
// Note: In the current architecture, TaskManager is managed by Agent and
|
|
169
|
+
// listens for file changes if it's a foreground process, or we might need
|
|
170
|
+
// to explicitly trigger a refresh. Since ReversionManager doesn't have
|
|
171
|
+
// a direct reference to TaskManager, we rely on the fact that TaskManager
|
|
172
|
+
// will see the file system changes or be refreshed by the Agent/UI.
|
|
173
|
+
|
|
150
174
|
return revertedCount;
|
|
151
175
|
}
|
|
152
176
|
}
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from "../utils/markdownParser.js";
|
|
22
22
|
import { exec } from "child_process";
|
|
23
23
|
import { promisify } from "util";
|
|
24
|
-
import { INIT_PROMPT } from "../
|
|
24
|
+
import { INIT_PROMPT } from "../prompts/index.js";
|
|
25
25
|
|
|
26
26
|
const execAsync = promisify(exec);
|
|
27
27
|
|
|
@@ -8,20 +8,19 @@ import type {
|
|
|
8
8
|
ModelConfig,
|
|
9
9
|
Usage,
|
|
10
10
|
} from "../types/index.js";
|
|
11
|
-
import type { SessionData } from "../services/session.js";
|
|
12
11
|
import { AIManager } from "./aiManager.js";
|
|
13
12
|
import { MessageManager } from "./messageManager.js";
|
|
14
13
|
import { ToolManager } from "./toolManager.js";
|
|
15
14
|
import { HookManager } from "./hookManager.js";
|
|
16
|
-
import {
|
|
17
|
-
UserMessageParams,
|
|
18
|
-
type AgentToolBlockUpdateParams,
|
|
19
|
-
} from "../utils/messageOperations.js";
|
|
20
15
|
import {
|
|
21
16
|
addConsolidatedAbortListener,
|
|
22
17
|
createAbortPromise,
|
|
23
18
|
} from "../utils/abortUtils.js";
|
|
24
19
|
import { BackgroundTaskManager } from "./backgroundTaskManager.js";
|
|
20
|
+
import {
|
|
21
|
+
UserMessageParams,
|
|
22
|
+
type AgentToolBlockUpdateParams,
|
|
23
|
+
} from "../utils/messageOperations.js";
|
|
25
24
|
|
|
26
25
|
export interface SubagentManagerCallbacks {
|
|
27
26
|
// Granular subagent message callbacks (015-subagent-message-callbacks)
|
|
@@ -66,14 +65,15 @@ export interface SubagentInstance {
|
|
|
66
65
|
toolManager: ToolManager;
|
|
67
66
|
status: "initializing" | "active" | "completed" | "error" | "aborted";
|
|
68
67
|
messages: Message[];
|
|
68
|
+
lastTools: string[]; // Track last two tool names
|
|
69
69
|
subagentType: string; // Store the subagent type for hook context
|
|
70
70
|
backgroundTaskId?: string; // ID of the background task if transitioned
|
|
71
|
+
onUpdate?: () => void; // Optional callback for real-time updates
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
export interface SubagentManagerOptions {
|
|
74
75
|
workdir: string;
|
|
75
76
|
parentToolManager: ToolManager;
|
|
76
|
-
parentMessageManager: MessageManager;
|
|
77
77
|
taskManager: import("../services/taskManager.js").TaskManager;
|
|
78
78
|
callbacks?: SubagentManagerCallbacks; // Use SubagentManagerCallbacks instead of parentCallbacks
|
|
79
79
|
logger?: Logger;
|
|
@@ -93,7 +93,6 @@ export class SubagentManager {
|
|
|
93
93
|
|
|
94
94
|
private workdir: string;
|
|
95
95
|
private parentToolManager: ToolManager;
|
|
96
|
-
private parentMessageManager: MessageManager;
|
|
97
96
|
private taskManager: import("../services/taskManager.js").TaskManager;
|
|
98
97
|
private callbacks?: SubagentManagerCallbacks; // Use SubagentManagerCallbacks instead of parentCallbacks
|
|
99
98
|
private logger?: Logger;
|
|
@@ -109,7 +108,6 @@ export class SubagentManager {
|
|
|
109
108
|
constructor(options: SubagentManagerOptions) {
|
|
110
109
|
this.workdir = options.workdir;
|
|
111
110
|
this.parentToolManager = options.parentToolManager;
|
|
112
|
-
this.parentMessageManager = options.parentMessageManager;
|
|
113
111
|
this.taskManager = options.taskManager;
|
|
114
112
|
this.callbacks = options.callbacks; // Store SubagentManagerCallbacks
|
|
115
113
|
this.logger = options.logger;
|
|
@@ -176,6 +174,7 @@ export class SubagentManager {
|
|
|
176
174
|
subagent_type: string;
|
|
177
175
|
},
|
|
178
176
|
runInBackground?: boolean,
|
|
177
|
+
onUpdate?: () => void,
|
|
179
178
|
): Promise<SubagentInstance> {
|
|
180
179
|
if (!this.parentToolManager) {
|
|
181
180
|
throw new Error(
|
|
@@ -248,22 +247,13 @@ export class SubagentManager {
|
|
|
248
247
|
toolManager,
|
|
249
248
|
status: "initializing",
|
|
250
249
|
messages: [],
|
|
250
|
+
lastTools: [], // Initialize lastTools
|
|
251
251
|
subagentType: parameters.subagent_type, // Store the subagent type
|
|
252
|
+
onUpdate,
|
|
252
253
|
};
|
|
253
254
|
|
|
254
255
|
this.instances.set(subagentId, instance);
|
|
255
256
|
|
|
256
|
-
// Create subagent block in parent message manager
|
|
257
|
-
this.parentMessageManager.addSubagentBlock(
|
|
258
|
-
subagentId,
|
|
259
|
-
configuration.name,
|
|
260
|
-
messageManager.getSessionId(),
|
|
261
|
-
configuration,
|
|
262
|
-
"active",
|
|
263
|
-
parameters,
|
|
264
|
-
runInBackground,
|
|
265
|
-
);
|
|
266
|
-
|
|
267
257
|
return instance;
|
|
268
258
|
}
|
|
269
259
|
|
|
@@ -287,9 +277,6 @@ export class SubagentManager {
|
|
|
287
277
|
|
|
288
278
|
// Set status to active and update parent
|
|
289
279
|
this.updateInstanceStatus(instance.subagentId, "active");
|
|
290
|
-
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
291
|
-
status: "active",
|
|
292
|
-
});
|
|
293
280
|
|
|
294
281
|
if (runInBackground && this.backgroundTaskManager) {
|
|
295
282
|
const taskId = this.backgroundTaskManager.generateId();
|
|
@@ -303,7 +290,11 @@ export class SubagentManager {
|
|
|
303
290
|
description: instance.configuration.description,
|
|
304
291
|
stdout: "",
|
|
305
292
|
stderr: "",
|
|
306
|
-
|
|
293
|
+
subagentId: instance.subagentId,
|
|
294
|
+
onStop: () => {
|
|
295
|
+
instance.aiManager.abortAIMessage();
|
|
296
|
+
this.cleanupInstance(instance.subagentId);
|
|
297
|
+
},
|
|
307
298
|
});
|
|
308
299
|
|
|
309
300
|
instance.backgroundTaskId = taskId;
|
|
@@ -341,9 +332,6 @@ export class SubagentManager {
|
|
|
341
332
|
return await this.internalExecute(instance, prompt, abortSignal);
|
|
342
333
|
} catch (error) {
|
|
343
334
|
this.updateInstanceStatus(instance.subagentId, "error");
|
|
344
|
-
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
345
|
-
status: "error",
|
|
346
|
-
});
|
|
347
335
|
throw error;
|
|
348
336
|
}
|
|
349
337
|
}
|
|
@@ -369,16 +357,15 @@ export class SubagentManager {
|
|
|
369
357
|
description: instance.configuration.description,
|
|
370
358
|
stdout: "",
|
|
371
359
|
stderr: "",
|
|
372
|
-
|
|
360
|
+
subagentId: instance.subagentId,
|
|
361
|
+
onStop: () => {
|
|
362
|
+
instance.aiManager.abortAIMessage();
|
|
363
|
+
this.cleanupInstance(instance.subagentId);
|
|
364
|
+
},
|
|
373
365
|
});
|
|
374
366
|
|
|
375
367
|
instance.backgroundTaskId = taskId;
|
|
376
368
|
|
|
377
|
-
// Update parent message manager to reflect background status
|
|
378
|
-
this.parentMessageManager.updateSubagentBlock(subagentId, {
|
|
379
|
-
runInBackground: true,
|
|
380
|
-
});
|
|
381
|
-
|
|
382
369
|
return taskId;
|
|
383
370
|
}
|
|
384
371
|
|
|
@@ -395,9 +382,8 @@ export class SubagentManager {
|
|
|
395
382
|
() => {
|
|
396
383
|
// Update status to aborted
|
|
397
384
|
this.updateInstanceStatus(instance.subagentId, "aborted");
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
});
|
|
385
|
+
// Cleanup instance immediately on abort
|
|
386
|
+
this.cleanupInstance(instance.subagentId);
|
|
401
387
|
},
|
|
402
388
|
() => {
|
|
403
389
|
// Abort the AI execution
|
|
@@ -474,9 +460,6 @@ export class SubagentManager {
|
|
|
474
460
|
|
|
475
461
|
// Update status to completed and update parent
|
|
476
462
|
this.updateInstanceStatus(instance.subagentId, "completed");
|
|
477
|
-
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
478
|
-
status: "completed",
|
|
479
|
-
});
|
|
480
463
|
|
|
481
464
|
// If this was transitioned to background, update the background task
|
|
482
465
|
if (instance.backgroundTaskId && this.backgroundTaskManager) {
|
|
@@ -580,99 +563,6 @@ export class SubagentManager {
|
|
|
580
563
|
this.instances.clear();
|
|
581
564
|
}
|
|
582
565
|
|
|
583
|
-
/**
|
|
584
|
-
* Restore subagent instances from saved session data
|
|
585
|
-
* This method is called during agent initialization to restore previous subagent states
|
|
586
|
-
*/
|
|
587
|
-
async restoreSubagentSessions(
|
|
588
|
-
subagentSessions: Array<{
|
|
589
|
-
sessionData: SessionData;
|
|
590
|
-
subagentId: string;
|
|
591
|
-
configuration: SubagentConfiguration;
|
|
592
|
-
}>,
|
|
593
|
-
): Promise<void> {
|
|
594
|
-
for (const { sessionData, subagentId, configuration } of subagentSessions) {
|
|
595
|
-
try {
|
|
596
|
-
// Use the configuration from the SubagentBlock
|
|
597
|
-
|
|
598
|
-
// Create the subagent instance without executing - just restore the state
|
|
599
|
-
|
|
600
|
-
// Create MessageManager for the restored subagent
|
|
601
|
-
const subagentCallbacks = this.createSubagentCallbacks(subagentId);
|
|
602
|
-
const messageManager = new MessageManager({
|
|
603
|
-
callbacks: subagentCallbacks,
|
|
604
|
-
workdir: this.workdir,
|
|
605
|
-
logger: this.logger,
|
|
606
|
-
sessionType: "subagent",
|
|
607
|
-
subagentType: configuration.name, // Use configuration name for restored sessions
|
|
608
|
-
memoryRuleManager: this.memoryRuleManager,
|
|
609
|
-
});
|
|
610
|
-
|
|
611
|
-
// Use the parent tool manager
|
|
612
|
-
const toolManager = this.parentToolManager;
|
|
613
|
-
|
|
614
|
-
// Determine model to use
|
|
615
|
-
let modelToUse: string;
|
|
616
|
-
const parentModelConfig = this.getModelConfig();
|
|
617
|
-
|
|
618
|
-
if (!configuration.model || configuration.model === "inherit") {
|
|
619
|
-
modelToUse = parentModelConfig.agentModel;
|
|
620
|
-
} else if (configuration.model === "fastModel") {
|
|
621
|
-
modelToUse = parentModelConfig.fastModel;
|
|
622
|
-
} else {
|
|
623
|
-
modelToUse = configuration.model;
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
// Create AIManager for the restored subagent
|
|
627
|
-
const aiManager = new AIManager({
|
|
628
|
-
messageManager,
|
|
629
|
-
toolManager,
|
|
630
|
-
taskManager: this.taskManager,
|
|
631
|
-
logger: this.logger,
|
|
632
|
-
workdir: this.workdir,
|
|
633
|
-
systemPrompt: configuration.systemPrompt,
|
|
634
|
-
subagentType: configuration.name, // Use configuration name as subagent type for restored instances
|
|
635
|
-
hookManager: this.hookManager,
|
|
636
|
-
permissionManager: this.parentToolManager.getPermissionManager(),
|
|
637
|
-
getGatewayConfig: this.getGatewayConfig,
|
|
638
|
-
getModelConfig: () => ({
|
|
639
|
-
...parentModelConfig,
|
|
640
|
-
agentModel: modelToUse,
|
|
641
|
-
}),
|
|
642
|
-
getMaxInputTokens: this.getMaxInputTokens,
|
|
643
|
-
getLanguage: this.getLanguage,
|
|
644
|
-
callbacks: {
|
|
645
|
-
onUsageAdded: this.onUsageAdded,
|
|
646
|
-
},
|
|
647
|
-
});
|
|
648
|
-
|
|
649
|
-
// Create restored instance
|
|
650
|
-
const instance: SubagentInstance = {
|
|
651
|
-
subagentId,
|
|
652
|
-
configuration,
|
|
653
|
-
aiManager,
|
|
654
|
-
messageManager,
|
|
655
|
-
toolManager,
|
|
656
|
-
status: "completed", // Restored sessions are considered completed
|
|
657
|
-
messages: sessionData.messages,
|
|
658
|
-
subagentType: configuration.name, // Use configuration name as subagent type for restored instances
|
|
659
|
-
};
|
|
660
|
-
|
|
661
|
-
// IMPORTANT: Store instance in map BEFORE calling setMessages
|
|
662
|
-
// This ensures the callback can find the instance
|
|
663
|
-
this.instances.set(subagentId, instance);
|
|
664
|
-
|
|
665
|
-
messageManager.initializeFromSession(sessionData);
|
|
666
|
-
} catch (error) {
|
|
667
|
-
this.logger?.warn(
|
|
668
|
-
`Failed to restore subagent session ${subagentId}:`,
|
|
669
|
-
error,
|
|
670
|
-
);
|
|
671
|
-
// Continue with other sessions even if one fails
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
566
|
/**
|
|
677
567
|
* Create subagent callbacks for a specific subagent ID
|
|
678
568
|
* Extracted to reuse in both create and restore flows
|
|
@@ -715,6 +605,20 @@ export class SubagentManager {
|
|
|
715
605
|
},
|
|
716
606
|
|
|
717
607
|
onToolBlockUpdated: (params: AgentToolBlockUpdateParams) => {
|
|
608
|
+
// Track last two tool names when a tool starts running
|
|
609
|
+
if (params.stage === "running" && params.name) {
|
|
610
|
+
const instance = this.instances.get(subagentId);
|
|
611
|
+
if (instance) {
|
|
612
|
+
// Add to lastTools if it's different from the last one or we want to show duplicates
|
|
613
|
+
// Based on "ToolA, ToolB" requirement, we'll just keep the last two
|
|
614
|
+
instance.lastTools.push(params.name);
|
|
615
|
+
if (instance.lastTools.length > 2) {
|
|
616
|
+
instance.lastTools.shift();
|
|
617
|
+
}
|
|
618
|
+
instance.onUpdate?.();
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
|
|
718
622
|
// Forward tool block updates to parent via SubagentManager callbacks
|
|
719
623
|
if (this.callbacks?.onSubagentToolBlockUpdated) {
|
|
720
624
|
this.callbacks.onSubagentToolBlockUpdated(subagentId, params);
|
|
@@ -726,6 +630,8 @@ export class SubagentManager {
|
|
|
726
630
|
const instance = this.instances.get(subagentId);
|
|
727
631
|
if (instance) {
|
|
728
632
|
instance.messages = messages;
|
|
633
|
+
// Trigger the onUpdate callback if provided
|
|
634
|
+
instance.onUpdate?.();
|
|
729
635
|
// Forward subagent message changes to parent via callbacks
|
|
730
636
|
if (this.callbacks?.onSubagentMessagesChange) {
|
|
731
637
|
this.callbacks.onSubagentMessagesChange(subagentId, messages);
|
|
@@ -733,26 +639,17 @@ export class SubagentManager {
|
|
|
733
639
|
}
|
|
734
640
|
},
|
|
735
641
|
|
|
736
|
-
onSessionIdChange: (newSessionId: string) => {
|
|
737
|
-
// Update the subagent block with the new session ID
|
|
738
|
-
this.parentMessageManager.updateSubagentBlock(subagentId, {
|
|
739
|
-
sessionId: newSessionId,
|
|
740
|
-
});
|
|
741
|
-
},
|
|
742
|
-
|
|
743
642
|
onLatestTotalTokensChange: (tokens: number) => {
|
|
643
|
+
const instance = this.instances.get(subagentId);
|
|
644
|
+
if (instance) {
|
|
645
|
+
// Trigger the onUpdate callback if provided
|
|
646
|
+
instance.onUpdate?.();
|
|
647
|
+
}
|
|
744
648
|
// Forward latest total tokens to parent via SubagentManager callbacks
|
|
745
649
|
if (this.callbacks?.onSubagentLatestTotalTokensChange) {
|
|
746
650
|
this.callbacks.onSubagentLatestTotalTokensChange(subagentId, tokens);
|
|
747
651
|
}
|
|
748
652
|
},
|
|
749
|
-
|
|
750
|
-
onFileHistoryBlockAdded: (
|
|
751
|
-
snapshots: import("../types/reversion.js").FileSnapshot[],
|
|
752
|
-
) => {
|
|
753
|
-
// Forward file history blocks to parent MessageManager
|
|
754
|
-
this.parentMessageManager.addFileHistoryBlock(snapshots);
|
|
755
|
-
},
|
|
756
653
|
};
|
|
757
654
|
}
|
|
758
655
|
}
|