wave-agent-sdk 0.0.5 → 0.0.7
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 +3 -6
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +24 -21
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/managers/aiManager.d.ts +4 -2
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +91 -53
- package/dist/managers/backgroundBashManager.d.ts +1 -1
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/{hooks/manager.d.ts → managers/hookManager.d.ts} +27 -16
- package/dist/managers/hookManager.d.ts.map +1 -0
- package/dist/{hooks/manager.js → managers/hookManager.js} +112 -17
- package/dist/managers/mcpManager.d.ts +1 -1
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/messageManager.d.ts +20 -15
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +19 -25
- package/dist/managers/skillManager.d.ts +1 -1
- package/dist/managers/skillManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.d.ts +1 -1
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +5 -2
- package/dist/managers/subagentManager.d.ts +7 -12
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +40 -46
- package/dist/managers/toolManager.d.ts +1 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/services/aiService.d.ts +1 -1
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +8 -1
- package/dist/services/hook.d.ts +56 -0
- package/dist/services/hook.d.ts.map +1 -0
- package/dist/services/hook.js +276 -0
- package/dist/services/session.d.ts +1 -1
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +5 -4
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +7 -3
- package/dist/tools/todoWriteTool.d.ts.map +1 -1
- package/dist/tools/todoWriteTool.js +3 -10
- package/dist/types/commands.d.ts +24 -0
- package/dist/types/commands.d.ts.map +1 -0
- package/dist/types/commands.js +5 -0
- package/dist/types/config.d.ts +13 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +5 -0
- package/dist/types/core.d.ts +38 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/{types.js → types/core.js} +4 -13
- package/dist/{hooks/types.d.ts → types/hooks.d.ts} +2 -1
- package/dist/types/hooks.d.ts.map +1 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +21 -0
- package/dist/types/mcp.d.ts +28 -0
- package/dist/types/mcp.d.ts.map +1 -0
- package/dist/types/mcp.js +5 -0
- package/dist/types/messaging.d.ts +80 -0
- package/dist/types/messaging.d.ts.map +1 -0
- package/dist/types/messaging.js +9 -0
- package/dist/types/processes.d.ts +17 -0
- package/dist/types/processes.d.ts.map +1 -0
- package/dist/types/processes.js +5 -0
- package/dist/types/skills.d.ts +78 -0
- package/dist/types/skills.d.ts.map +1 -0
- package/dist/types/skills.js +17 -0
- package/dist/utils/configResolver.d.ts +1 -1
- package/dist/utils/configResolver.d.ts.map +1 -1
- package/dist/utils/configResolver.js +1 -1
- package/dist/utils/configValidator.d.ts +1 -1
- package/dist/utils/configValidator.d.ts.map +1 -1
- package/dist/utils/configValidator.js +1 -1
- package/dist/utils/convertMessagesForAPI.d.ts +1 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +1 -8
- package/dist/utils/customCommands.d.ts +1 -1
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/{hooks/matcher.d.ts → utils/hookMatcher.d.ts} +2 -7
- package/dist/utils/hookMatcher.d.ts.map +1 -0
- package/dist/utils/markdownParser.d.ts +1 -1
- package/dist/utils/markdownParser.d.ts.map +1 -1
- package/dist/utils/mcpUtils.d.ts +1 -1
- package/dist/utils/mcpUtils.d.ts.map +1 -1
- package/dist/utils/messageOperations.d.ts +14 -21
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +37 -20
- package/dist/utils/skillParser.d.ts +1 -1
- package/dist/utils/skillParser.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agent.ts +49 -43
- package/src/index.ts +3 -4
- package/src/managers/aiManager.ts +241 -160
- package/src/managers/backgroundBashManager.ts +1 -1
- package/src/{hooks/manager.ts → managers/hookManager.ts} +168 -56
- package/src/managers/mcpManager.ts +1 -1
- package/src/managers/messageManager.ts +44 -44
- package/src/managers/skillManager.ts +1 -1
- package/src/managers/slashCommandManager.ts +10 -7
- package/src/managers/subagentManager.ts +47 -54
- package/src/managers/toolManager.ts +1 -1
- package/src/services/aiService.ts +9 -2
- package/src/services/hook.ts +360 -0
- package/src/services/session.ts +6 -7
- package/src/tools/taskTool.ts +13 -5
- package/src/tools/todoWriteTool.ts +3 -11
- package/src/types/commands.ts +26 -0
- package/src/types/config.ts +14 -0
- package/src/types/core.ts +49 -0
- package/src/{hooks/types.ts → types/hooks.ts} +1 -0
- package/src/types/index.ts +23 -0
- package/src/types/mcp.ts +31 -0
- package/src/types/messaging.ts +102 -0
- package/src/types/processes.ts +18 -0
- package/src/types/skills.ts +91 -0
- package/src/utils/configResolver.ts +1 -1
- package/src/utils/configValidator.ts +5 -1
- package/src/utils/convertMessagesForAPI.ts +2 -10
- package/src/utils/customCommands.ts +1 -1
- package/src/{hooks/matcher.ts → utils/hookMatcher.ts} +1 -12
- package/src/utils/markdownParser.ts +1 -1
- package/src/utils/mcpUtils.ts +1 -1
- package/src/utils/messageOperations.ts +56 -42
- package/src/utils/skillParser.ts +1 -1
- package/dist/hooks/executor.d.ts +0 -56
- package/dist/hooks/executor.d.ts.map +0 -1
- package/dist/hooks/executor.js +0 -312
- package/dist/hooks/index.d.ts +0 -17
- package/dist/hooks/index.d.ts.map +0 -1
- package/dist/hooks/index.js +0 -14
- package/dist/hooks/manager.d.ts.map +0 -1
- package/dist/hooks/matcher.d.ts.map +0 -1
- package/dist/hooks/settings.d.ts +0 -46
- package/dist/hooks/settings.d.ts.map +0 -1
- package/dist/hooks/settings.js +0 -100
- package/dist/hooks/types.d.ts.map +0 -1
- package/dist/types.d.ts +0 -288
- package/dist/types.d.ts.map +0 -1
- package/src/hooks/executor.ts +0 -440
- package/src/hooks/index.ts +0 -52
- package/src/hooks/settings.ts +0 -129
- package/src/types.ts +0 -357
- /package/dist/{hooks/types.js → types/hooks.js} +0 -0
- /package/dist/{hooks/matcher.js → utils/hookMatcher.js} +0 -0
|
@@ -17,57 +17,30 @@ import {
|
|
|
17
17
|
HookConfigurationError,
|
|
18
18
|
isValidHookEvent,
|
|
19
19
|
isValidHookEventConfig,
|
|
20
|
-
} from "
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// Load configuration from filesystem settings
|
|
34
|
-
loadConfigurationFromSettings(): void;
|
|
35
|
-
|
|
36
|
-
// Execute hooks for specific event
|
|
37
|
-
executeHooks(
|
|
38
|
-
event: HookEvent,
|
|
39
|
-
context: HookExecutionContext | ExtendedHookExecutionContext,
|
|
40
|
-
): Promise<HookExecutionResult[]>;
|
|
41
|
-
|
|
42
|
-
// Check if hooks are configured for event
|
|
43
|
-
hasHooks(event: HookEvent, toolName?: string): boolean;
|
|
44
|
-
|
|
45
|
-
// Validate hook configuration
|
|
46
|
-
validateConfiguration(config: HookConfiguration): ValidationResult;
|
|
47
|
-
|
|
48
|
-
// Get current configuration
|
|
49
|
-
getConfiguration(): PartialHookConfiguration | undefined;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export class HookManager implements IHookManager {
|
|
20
|
+
} from "../types/hooks.js";
|
|
21
|
+
import { HookMatcher } from "../utils/hookMatcher.js";
|
|
22
|
+
import {
|
|
23
|
+
executeCommand,
|
|
24
|
+
isCommandSafe,
|
|
25
|
+
loadMergedHooksConfig,
|
|
26
|
+
} from "../services/hook.js";
|
|
27
|
+
import type { Logger } from "../types/index.js";
|
|
28
|
+
import { MessageSource } from "../types/index.js";
|
|
29
|
+
import type { MessageManager } from "./messageManager.js";
|
|
30
|
+
|
|
31
|
+
export class HookManager {
|
|
53
32
|
private configuration: PartialHookConfiguration | undefined;
|
|
54
|
-
private readonly matcher:
|
|
55
|
-
private readonly executor: IHookExecutor;
|
|
33
|
+
private readonly matcher: HookMatcher;
|
|
56
34
|
private readonly logger?: Logger;
|
|
57
35
|
private readonly workdir: string;
|
|
58
36
|
|
|
59
37
|
constructor(
|
|
60
38
|
workdir: string,
|
|
61
|
-
matcher:
|
|
62
|
-
executor?: IHookExecutor,
|
|
39
|
+
matcher: HookMatcher = new HookMatcher(),
|
|
63
40
|
logger?: Logger,
|
|
64
41
|
) {
|
|
65
42
|
this.workdir = workdir;
|
|
66
43
|
this.matcher = matcher;
|
|
67
|
-
// Create executor with logger if provided, or use passed executor, or create default
|
|
68
|
-
this.executor = logger
|
|
69
|
-
? new HookExecutor(logger)
|
|
70
|
-
: executor || new HookExecutor();
|
|
71
44
|
this.logger = logger;
|
|
72
45
|
}
|
|
73
46
|
|
|
@@ -112,19 +85,21 @@ export class HookManager implements IHookManager {
|
|
|
112
85
|
this.logger?.debug(`[HookManager] Loading configuration...`);
|
|
113
86
|
const mergedConfig = loadMergedHooksConfig(this.workdir);
|
|
114
87
|
this.logger?.debug(`[HookManager] Merged config result:`, mergedConfig);
|
|
115
|
-
this.configuration = mergedConfig;
|
|
116
|
-
|
|
117
|
-
// Validate the loaded configuration
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
88
|
+
this.configuration = mergedConfig || undefined;
|
|
89
|
+
|
|
90
|
+
// Validate the loaded configuration if it exists
|
|
91
|
+
if (mergedConfig) {
|
|
92
|
+
const validation = this.validatePartialConfiguration(mergedConfig);
|
|
93
|
+
if (!validation.valid) {
|
|
94
|
+
throw new HookConfigurationError(
|
|
95
|
+
"filesystem settings",
|
|
96
|
+
validation.errors,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
124
99
|
}
|
|
125
100
|
|
|
126
101
|
this.logger?.debug(
|
|
127
|
-
`[HookManager] Configuration loaded successfully with ${Object.keys(mergedConfig).length} event types`,
|
|
102
|
+
`[HookManager] Configuration loaded successfully with ${Object.keys(mergedConfig || {}).length} event types`,
|
|
128
103
|
);
|
|
129
104
|
} catch (error) {
|
|
130
105
|
// If loading fails, start with undefined configuration (no hooks)
|
|
@@ -219,10 +194,7 @@ export class HookManager implements IHookManager {
|
|
|
219
194
|
`[HookManager] Executing command ${commandIndex + 1}/${config.hooks.length} in configuration ${configIndex + 1}`,
|
|
220
195
|
);
|
|
221
196
|
|
|
222
|
-
const result = await
|
|
223
|
-
hookCommand.command,
|
|
224
|
-
context,
|
|
225
|
-
);
|
|
197
|
+
const result = await executeCommand(hookCommand.command, context);
|
|
226
198
|
results.push(result);
|
|
227
199
|
|
|
228
200
|
// Report individual command result
|
|
@@ -268,6 +240,146 @@ export class HookManager implements IHookManager {
|
|
|
268
240
|
return results;
|
|
269
241
|
}
|
|
270
242
|
|
|
243
|
+
/**
|
|
244
|
+
* Process hook execution results and determine appropriate actions
|
|
245
|
+
* based on exit codes and hook event type
|
|
246
|
+
*/
|
|
247
|
+
processHookResults(
|
|
248
|
+
event: HookEvent,
|
|
249
|
+
results: HookExecutionResult[],
|
|
250
|
+
messageManager?: MessageManager,
|
|
251
|
+
toolId?: string,
|
|
252
|
+
toolParameters?: string,
|
|
253
|
+
): {
|
|
254
|
+
shouldBlock: boolean;
|
|
255
|
+
errorMessage?: string;
|
|
256
|
+
} {
|
|
257
|
+
if (!messageManager || results.length === 0) {
|
|
258
|
+
return { shouldBlock: false };
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// First pass: Check for any blocking errors (exit code 2)
|
|
262
|
+
// Blocking errors take precedence and stop all processing
|
|
263
|
+
for (const result of results) {
|
|
264
|
+
if (result.exitCode === 2) {
|
|
265
|
+
// Handle blocking error immediately and return
|
|
266
|
+
return this.handleBlockingError(
|
|
267
|
+
event,
|
|
268
|
+
result,
|
|
269
|
+
messageManager,
|
|
270
|
+
toolId,
|
|
271
|
+
toolParameters,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Second pass: Process all non-blocking results
|
|
277
|
+
for (const result of results) {
|
|
278
|
+
if (result.exitCode === undefined) {
|
|
279
|
+
continue; // Skip results without exit codes
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Handle exit code interpretation
|
|
283
|
+
if (result.exitCode === 0) {
|
|
284
|
+
// Success case - handle stdout based on hook type
|
|
285
|
+
this.handleHookSuccess(event, result, messageManager);
|
|
286
|
+
} else {
|
|
287
|
+
// Non-blocking error case (any exit code except 0 and 2)
|
|
288
|
+
this.handleNonBlockingError(result, messageManager);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
return { shouldBlock: false };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Handle successful hook execution (exit code 0)
|
|
297
|
+
*/
|
|
298
|
+
private handleHookSuccess(
|
|
299
|
+
event: HookEvent,
|
|
300
|
+
result: HookExecutionResult,
|
|
301
|
+
messageManager: MessageManager,
|
|
302
|
+
): void {
|
|
303
|
+
if (event === "UserPromptSubmit" && result.stdout?.trim()) {
|
|
304
|
+
// Inject stdout as user message context for UserPromptSubmit
|
|
305
|
+
messageManager.addUserMessage({
|
|
306
|
+
content: result.stdout.trim(),
|
|
307
|
+
source: MessageSource.HOOK,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
// For other hook types (PreToolUse, PostToolUse, Stop), ignore stdout
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Handle blocking error (exit code 2) - behavior varies by hook type
|
|
315
|
+
*/
|
|
316
|
+
private handleBlockingError(
|
|
317
|
+
event: HookEvent,
|
|
318
|
+
result: HookExecutionResult,
|
|
319
|
+
messageManager: MessageManager,
|
|
320
|
+
toolId?: string,
|
|
321
|
+
toolParameters?: string,
|
|
322
|
+
): {
|
|
323
|
+
shouldBlock: boolean;
|
|
324
|
+
errorMessage?: string;
|
|
325
|
+
} {
|
|
326
|
+
const errorMessage = result.stderr?.trim() || "Hook execution failed";
|
|
327
|
+
|
|
328
|
+
switch (event) {
|
|
329
|
+
case "UserPromptSubmit":
|
|
330
|
+
// Block prompt processing, show error to user, erase prompt
|
|
331
|
+
messageManager.addErrorBlock(errorMessage);
|
|
332
|
+
messageManager.removeLastUserMessage();
|
|
333
|
+
return {
|
|
334
|
+
shouldBlock: true,
|
|
335
|
+
errorMessage,
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
case "PreToolUse":
|
|
339
|
+
// Block tool execution and show error to Wave Agent via tool block
|
|
340
|
+
if (toolId) {
|
|
341
|
+
messageManager.updateToolBlock({
|
|
342
|
+
id: toolId,
|
|
343
|
+
parameters: toolParameters || "",
|
|
344
|
+
result: errorMessage,
|
|
345
|
+
success: false,
|
|
346
|
+
error: "Hook blocked tool execution",
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
return { shouldBlock: true };
|
|
350
|
+
|
|
351
|
+
case "PostToolUse":
|
|
352
|
+
// Show error to Wave Agent via user message and allow AI to continue
|
|
353
|
+
messageManager.addUserMessage({
|
|
354
|
+
content: errorMessage,
|
|
355
|
+
source: MessageSource.HOOK,
|
|
356
|
+
});
|
|
357
|
+
return { shouldBlock: false };
|
|
358
|
+
|
|
359
|
+
case "Stop":
|
|
360
|
+
// Show error to Wave Agent via user message and block stopping to continue conversation
|
|
361
|
+
messageManager.addUserMessage({
|
|
362
|
+
content: errorMessage,
|
|
363
|
+
source: MessageSource.HOOK,
|
|
364
|
+
});
|
|
365
|
+
return { shouldBlock: true, errorMessage };
|
|
366
|
+
|
|
367
|
+
default:
|
|
368
|
+
return { shouldBlock: false };
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Handle non-blocking error (other exit codes)
|
|
374
|
+
*/
|
|
375
|
+
private handleNonBlockingError(
|
|
376
|
+
result: HookExecutionResult,
|
|
377
|
+
messageManager: MessageManager,
|
|
378
|
+
): void {
|
|
379
|
+
const errorMessage = result.stderr?.trim() || "Hook execution failed";
|
|
380
|
+
messageManager.addErrorBlock(errorMessage);
|
|
381
|
+
}
|
|
382
|
+
|
|
271
383
|
/**
|
|
272
384
|
* Check if hooks are configured for an event/tool combination
|
|
273
385
|
*/
|
|
@@ -556,7 +668,7 @@ export class HookManager implements IHookManager {
|
|
|
556
668
|
|
|
557
669
|
// Validate commands
|
|
558
670
|
config.hooks.forEach((hookCommand, cmdIndex) => {
|
|
559
|
-
if (!
|
|
671
|
+
if (!isCommandSafe(hookCommand.command)) {
|
|
560
672
|
errors.push(
|
|
561
673
|
`${prefix}.hooks[${cmdIndex}]: Command may be unsafe: ${hookCommand.command}`,
|
|
562
674
|
);
|
|
@@ -12,11 +12,13 @@ import {
|
|
|
12
12
|
completeCommandInMessage,
|
|
13
13
|
addSubagentBlockToMessage,
|
|
14
14
|
updateSubagentBlockInMessage,
|
|
15
|
+
removeLastUserMessage,
|
|
16
|
+
UserMessageParams,
|
|
15
17
|
type AddSubagentBlockParams,
|
|
16
18
|
type UpdateSubagentBlockParams,
|
|
17
19
|
type AgentToolBlockUpdateParams,
|
|
18
20
|
} from "../utils/messageOperations.js";
|
|
19
|
-
import type { Logger, Message, Usage } from "../types.js";
|
|
21
|
+
import type { Logger, Message, Usage } from "../types/index.js";
|
|
20
22
|
import {
|
|
21
23
|
cleanupExpiredSessions,
|
|
22
24
|
getLatestSession,
|
|
@@ -34,10 +36,7 @@ export interface MessageManagerCallbacks {
|
|
|
34
36
|
onUserInputHistoryChange?: (history: string[]) => void;
|
|
35
37
|
onUsagesChange?: (usages: Usage[]) => void;
|
|
36
38
|
// Incremental callback
|
|
37
|
-
onUserMessageAdded?: (
|
|
38
|
-
content: string,
|
|
39
|
-
images?: Array<{ path: string; mimeType: string }>,
|
|
40
|
-
) => void;
|
|
39
|
+
onUserMessageAdded?: (params: UserMessageParams) => void;
|
|
41
40
|
onAssistantMessageAdded?: (
|
|
42
41
|
content?: string,
|
|
43
42
|
toolCalls?: ChatCompletionMessageFunctionToolCall[],
|
|
@@ -53,19 +52,24 @@ export interface MessageManagerCallbacks {
|
|
|
53
52
|
type: "project" | "user",
|
|
54
53
|
storagePath: string,
|
|
55
54
|
) => void;
|
|
56
|
-
// Custom command callback
|
|
57
|
-
onCustomCommandAdded?: (
|
|
58
|
-
commandName: string,
|
|
59
|
-
content: string,
|
|
60
|
-
originalInput?: string,
|
|
61
|
-
) => void;
|
|
62
55
|
// Bash command callback
|
|
63
56
|
onAddCommandOutputMessage?: (command: string) => void;
|
|
64
57
|
onUpdateCommandOutputMessage?: (command: string, output: string) => void;
|
|
65
58
|
onCompleteCommandMessage?: (command: string, exitCode: number) => void;
|
|
66
59
|
// Subagent callbacks
|
|
67
|
-
onSubAgentBlockAdded?: (
|
|
68
|
-
|
|
60
|
+
onSubAgentBlockAdded?: (
|
|
61
|
+
subagentId: string,
|
|
62
|
+
parameters: {
|
|
63
|
+
description: string;
|
|
64
|
+
prompt: string;
|
|
65
|
+
subagent_type: string;
|
|
66
|
+
},
|
|
67
|
+
) => void;
|
|
68
|
+
onSubAgentBlockUpdated?: (
|
|
69
|
+
subagentId: string,
|
|
70
|
+
messages: Message[],
|
|
71
|
+
status: "active" | "completed" | "error" | "aborted",
|
|
72
|
+
) => void;
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
export interface MessageManagerOptions {
|
|
@@ -168,7 +172,7 @@ export class MessageManager {
|
|
|
168
172
|
try {
|
|
169
173
|
await cleanupExpiredSessions(this.workdir, this.sessionDir);
|
|
170
174
|
} catch (error) {
|
|
171
|
-
|
|
175
|
+
this.logger?.warn("Failed to cleanup expired sessions:", error);
|
|
172
176
|
}
|
|
173
177
|
|
|
174
178
|
if (!restoreSessionId && !continueLastSession) {
|
|
@@ -269,36 +273,13 @@ export class MessageManager {
|
|
|
269
273
|
}
|
|
270
274
|
|
|
271
275
|
// Encapsulated message operation functions
|
|
272
|
-
public addUserMessage(
|
|
273
|
-
content: string,
|
|
274
|
-
images?: Array<{ path: string; mimeType: string }>,
|
|
275
|
-
): void {
|
|
276
|
-
const newMessages = addUserMessageToMessages({
|
|
277
|
-
messages: this.messages,
|
|
278
|
-
content,
|
|
279
|
-
images,
|
|
280
|
-
});
|
|
281
|
-
this.setMessages(newMessages);
|
|
282
|
-
this.callbacks.onUserMessageAdded?.(content, images);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
public addCustomCommandMessage(
|
|
286
|
-
commandName: string,
|
|
287
|
-
content: string,
|
|
288
|
-
originalInput?: string,
|
|
289
|
-
): void {
|
|
276
|
+
public addUserMessage(params: UserMessageParams): void {
|
|
290
277
|
const newMessages = addUserMessageToMessages({
|
|
291
278
|
messages: this.messages,
|
|
292
|
-
|
|
293
|
-
customCommandBlock: {
|
|
294
|
-
type: "custom_command",
|
|
295
|
-
commandName,
|
|
296
|
-
content,
|
|
297
|
-
originalInput,
|
|
298
|
-
},
|
|
279
|
+
...params,
|
|
299
280
|
});
|
|
300
281
|
this.setMessages(newMessages);
|
|
301
|
-
this.callbacks.
|
|
282
|
+
this.callbacks.onUserMessageAdded?.(params);
|
|
302
283
|
}
|
|
303
284
|
|
|
304
285
|
public addAssistantMessage(
|
|
@@ -319,14 +300,15 @@ export class MessageManager {
|
|
|
319
300
|
public updateToolBlock(params: AgentToolBlockUpdateParams): void {
|
|
320
301
|
const newMessages = updateToolBlockInMessage({
|
|
321
302
|
messages: this.messages,
|
|
322
|
-
id: params.
|
|
323
|
-
parameters: params.
|
|
303
|
+
id: params.id,
|
|
304
|
+
parameters: params.parameters,
|
|
324
305
|
result: params.result,
|
|
325
306
|
success: params.success,
|
|
326
307
|
error: params.error,
|
|
327
308
|
isRunning: params.isRunning,
|
|
328
309
|
name: params.name,
|
|
329
310
|
shortResult: params.shortResult,
|
|
311
|
+
images: params.images,
|
|
330
312
|
compactParams: params.compactParams,
|
|
331
313
|
});
|
|
332
314
|
this.setMessages(newMessages);
|
|
@@ -448,6 +430,11 @@ export class MessageManager {
|
|
|
448
430
|
subagentName: string,
|
|
449
431
|
status: "active" | "completed" | "error" = "active",
|
|
450
432
|
subagentMessages: Message[] = [],
|
|
433
|
+
parameters: {
|
|
434
|
+
description: string;
|
|
435
|
+
prompt: string;
|
|
436
|
+
subagent_type: string;
|
|
437
|
+
},
|
|
451
438
|
): void {
|
|
452
439
|
const params: AddSubagentBlockParams = {
|
|
453
440
|
messages: this.messages,
|
|
@@ -458,7 +445,7 @@ export class MessageManager {
|
|
|
458
445
|
};
|
|
459
446
|
const updatedMessages = addSubagentBlockToMessage(params);
|
|
460
447
|
this.setMessages(updatedMessages);
|
|
461
|
-
this.callbacks.onSubAgentBlockAdded?.(params.subagentId);
|
|
448
|
+
this.callbacks.onSubAgentBlockAdded?.(params.subagentId, parameters);
|
|
462
449
|
}
|
|
463
450
|
|
|
464
451
|
public updateSubagentBlock(
|
|
@@ -480,7 +467,11 @@ export class MessageManager {
|
|
|
480
467
|
status: updates.status || "active",
|
|
481
468
|
subagentMessages: updates.messages || [],
|
|
482
469
|
};
|
|
483
|
-
this.callbacks.onSubAgentBlockUpdated?.(
|
|
470
|
+
this.callbacks.onSubAgentBlockUpdated?.(
|
|
471
|
+
params.subagentId,
|
|
472
|
+
params.messages,
|
|
473
|
+
params.status,
|
|
474
|
+
);
|
|
484
475
|
}
|
|
485
476
|
|
|
486
477
|
/**
|
|
@@ -495,4 +486,13 @@ export class MessageManager {
|
|
|
495
486
|
}
|
|
496
487
|
this.callbacks.onUsagesChange?.(usages);
|
|
497
488
|
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Remove the last user message from the conversation
|
|
492
|
+
* Used for hook error handling when the user prompt needs to be erased
|
|
493
|
+
*/
|
|
494
|
+
public removeLastUserMessage(): void {
|
|
495
|
+
const newMessages = removeLastUserMessage(this.messages);
|
|
496
|
+
this.setMessages(newMessages);
|
|
497
|
+
}
|
|
498
498
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import type { MessageManager } from "./messageManager.js";
|
|
2
2
|
import type { AIManager } from "./aiManager.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
SlashCommand,
|
|
5
|
+
CustomSlashCommand,
|
|
6
|
+
Logger,
|
|
7
|
+
} from "../types/index.js";
|
|
4
8
|
import { loadCustomSlashCommands } from "../utils/customCommands.js";
|
|
5
9
|
|
|
6
10
|
import {
|
|
@@ -253,15 +257,14 @@ export class SlashCommandManager {
|
|
|
253
257
|
? replaceBashCommandsWithOutput(processedContent, bashResults)
|
|
254
258
|
: processedContent;
|
|
255
259
|
|
|
256
|
-
// Add custom command
|
|
260
|
+
// Add custom command message to show the command being executed
|
|
257
261
|
const originalInput = args
|
|
258
262
|
? `/${commandName} ${args}`
|
|
259
263
|
: `/${commandName}`;
|
|
260
|
-
this.messageManager.
|
|
261
|
-
|
|
262
|
-
finalContent,
|
|
263
|
-
|
|
264
|
-
);
|
|
264
|
+
this.messageManager.addUserMessage({
|
|
265
|
+
content: originalInput,
|
|
266
|
+
customCommandContent: finalContent,
|
|
267
|
+
});
|
|
265
268
|
|
|
266
269
|
// Execute the AI conversation with custom configuration
|
|
267
270
|
await this.aiManager.sendAIMessage({
|
|
@@ -6,7 +6,7 @@ import type {
|
|
|
6
6
|
GatewayConfig,
|
|
7
7
|
ModelConfig,
|
|
8
8
|
Usage,
|
|
9
|
-
} from "../types.js";
|
|
9
|
+
} from "../types/index.js";
|
|
10
10
|
import { AIManager } from "./aiManager.js";
|
|
11
11
|
import {
|
|
12
12
|
MessageManager,
|
|
@@ -21,7 +21,6 @@ export interface SubagentInstance {
|
|
|
21
21
|
messageManager: MessageManager;
|
|
22
22
|
toolManager: ToolManager;
|
|
23
23
|
status: "initializing" | "active" | "completed" | "error" | "aborted";
|
|
24
|
-
taskDescription: string;
|
|
25
24
|
messages: Message[];
|
|
26
25
|
}
|
|
27
26
|
|
|
@@ -107,7 +106,11 @@ export class SubagentManager {
|
|
|
107
106
|
*/
|
|
108
107
|
async createInstance(
|
|
109
108
|
configuration: SubagentConfiguration,
|
|
110
|
-
|
|
109
|
+
parameters: {
|
|
110
|
+
description: string;
|
|
111
|
+
prompt: string;
|
|
112
|
+
subagent_type: string;
|
|
113
|
+
},
|
|
111
114
|
): Promise<SubagentInstance> {
|
|
112
115
|
if (
|
|
113
116
|
!this.parentToolManager ||
|
|
@@ -177,7 +180,6 @@ export class SubagentManager {
|
|
|
177
180
|
messageManager,
|
|
178
181
|
toolManager,
|
|
179
182
|
status: "initializing",
|
|
180
|
-
taskDescription,
|
|
181
183
|
messages: [],
|
|
182
184
|
};
|
|
183
185
|
|
|
@@ -189,6 +191,7 @@ export class SubagentManager {
|
|
|
189
191
|
configuration.name,
|
|
190
192
|
"active",
|
|
191
193
|
[],
|
|
194
|
+
parameters,
|
|
192
195
|
);
|
|
193
196
|
|
|
194
197
|
return instance;
|
|
@@ -203,16 +206,33 @@ export class SubagentManager {
|
|
|
203
206
|
async executeTask(
|
|
204
207
|
instance: SubagentInstance,
|
|
205
208
|
prompt: string,
|
|
209
|
+
abortSignal?: AbortSignal,
|
|
206
210
|
): Promise<string> {
|
|
207
211
|
try {
|
|
212
|
+
// Check if already aborted before starting
|
|
213
|
+
if (abortSignal?.aborted) {
|
|
214
|
+
throw new Error("Task was aborted before execution started");
|
|
215
|
+
}
|
|
216
|
+
|
|
208
217
|
// Set status to active and update parent
|
|
209
218
|
this.updateInstanceStatus(instance.subagentId, "active");
|
|
210
219
|
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
211
220
|
status: "active",
|
|
212
221
|
});
|
|
213
222
|
|
|
223
|
+
// Set up abort handler
|
|
224
|
+
if (abortSignal) {
|
|
225
|
+
abortSignal.addEventListener("abort", () => {
|
|
226
|
+
this.updateInstanceStatus(instance.subagentId, "aborted");
|
|
227
|
+
this.parentMessageManager.updateSubagentBlock(instance.subagentId, {
|
|
228
|
+
status: "aborted",
|
|
229
|
+
messages: instance.messages,
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
214
234
|
// Add the user's prompt as a message
|
|
215
|
-
instance.messageManager.addUserMessage(prompt);
|
|
235
|
+
instance.messageManager.addUserMessage({ content: prompt });
|
|
216
236
|
|
|
217
237
|
// Create allowed tools list - always exclude Task tool to prevent subagent recursion
|
|
218
238
|
let allowedTools = instance.configuration.tools;
|
|
@@ -227,7 +247,9 @@ export class SubagentManager {
|
|
|
227
247
|
}
|
|
228
248
|
|
|
229
249
|
// Execute the AI request with tool restrictions
|
|
230
|
-
|
|
250
|
+
// The AIManager will handle abort signals through its own abort controllers
|
|
251
|
+
// We need to abort the AI execution if the external abort signal is triggered
|
|
252
|
+
const executeAI = instance.aiManager.sendAIMessage({
|
|
231
253
|
allowedTools,
|
|
232
254
|
model:
|
|
233
255
|
instance.configuration.model !== "inherit"
|
|
@@ -235,6 +257,25 @@ export class SubagentManager {
|
|
|
235
257
|
: undefined,
|
|
236
258
|
});
|
|
237
259
|
|
|
260
|
+
// If we have an abort signal, race against it
|
|
261
|
+
if (abortSignal) {
|
|
262
|
+
await Promise.race([
|
|
263
|
+
executeAI,
|
|
264
|
+
new Promise<never>((_, reject) => {
|
|
265
|
+
if (abortSignal.aborted) {
|
|
266
|
+
reject(new Error("Task was aborted"));
|
|
267
|
+
}
|
|
268
|
+
abortSignal.addEventListener("abort", () => {
|
|
269
|
+
// Abort the AI execution
|
|
270
|
+
instance.aiManager.abortAIMessage();
|
|
271
|
+
reject(new Error("Task was aborted"));
|
|
272
|
+
});
|
|
273
|
+
}),
|
|
274
|
+
]);
|
|
275
|
+
} else {
|
|
276
|
+
await executeAI;
|
|
277
|
+
}
|
|
278
|
+
|
|
238
279
|
// Get the latest messages to extract the response
|
|
239
280
|
const messages = instance.messageManager.getMessages();
|
|
240
281
|
const lastAssistantMessage = messages
|
|
@@ -298,52 +339,6 @@ export class SubagentManager {
|
|
|
298
339
|
}
|
|
299
340
|
}
|
|
300
341
|
|
|
301
|
-
/**
|
|
302
|
-
* Abort a running subagent instance
|
|
303
|
-
*/
|
|
304
|
-
abortInstance(subagentId: string): boolean {
|
|
305
|
-
const instance = this.instances.get(subagentId);
|
|
306
|
-
if (!instance) {
|
|
307
|
-
return false;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
// Only abort active or initializing instances
|
|
311
|
-
if (instance.status !== "active" && instance.status !== "initializing") {
|
|
312
|
-
return false;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
try {
|
|
316
|
-
// Abort the AI manager operations
|
|
317
|
-
instance.aiManager.abortAIMessage();
|
|
318
|
-
|
|
319
|
-
// Update status
|
|
320
|
-
this.updateInstanceStatus(subagentId, "aborted");
|
|
321
|
-
this.parentMessageManager.updateSubagentBlock(subagentId, {
|
|
322
|
-
status: "aborted",
|
|
323
|
-
messages: instance.messages,
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
this.logger?.debug(`Aborted subagent instance: ${subagentId}`);
|
|
327
|
-
return true;
|
|
328
|
-
} catch (error) {
|
|
329
|
-
this.logger?.error(
|
|
330
|
-
`Failed to abort subagent instance ${subagentId}:`,
|
|
331
|
-
error,
|
|
332
|
-
);
|
|
333
|
-
return false;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Abort all active subagent instances
|
|
339
|
-
*/
|
|
340
|
-
abortAllInstances(): void {
|
|
341
|
-
const activeInstances = this.getActiveInstances();
|
|
342
|
-
for (const instance of activeInstances) {
|
|
343
|
-
this.abortInstance(instance.subagentId);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
|
|
347
342
|
/**
|
|
348
343
|
* Clean up completed, errored, or aborted instances
|
|
349
344
|
*/
|
|
@@ -373,8 +368,6 @@ export class SubagentManager {
|
|
|
373
368
|
* Clean up all instances (for session end)
|
|
374
369
|
*/
|
|
375
370
|
cleanup(): void {
|
|
376
|
-
// Abort all active instances before cleanup
|
|
377
|
-
this.abortAllInstances();
|
|
378
371
|
this.instances.clear();
|
|
379
372
|
}
|
|
380
373
|
}
|
|
@@ -14,7 +14,7 @@ import { createTaskTool } from "../tools/taskTool.js";
|
|
|
14
14
|
import { createSkillTool } from "../tools/skillTool.js";
|
|
15
15
|
import { McpManager } from "./mcpManager.js";
|
|
16
16
|
import { ChatCompletionFunctionTool } from "openai/resources.js";
|
|
17
|
-
import type { Logger } from "../types.js";
|
|
17
|
+
import type { Logger } from "../types/index.js";
|
|
18
18
|
import type { SubagentManager } from "./subagentManager.js";
|
|
19
19
|
import type { SkillManager } from "./skillManager.js";
|
|
20
20
|
|