wave-agent-sdk 0.0.5 → 0.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 +3 -6
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +21 -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 +84 -47
- 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} +26 -7
- package/dist/managers/hookManager.d.ts.map +1 -0
- package/dist/{hooks/manager.js → managers/hookManager.js} +107 -17
- package/dist/managers/mcpManager.d.ts +1 -1
- package/dist/managers/mcpManager.d.ts.map +1 -1
- package/dist/managers/messageManager.d.ts +17 -4
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +13 -5
- 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/subagentManager.d.ts +7 -12
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +39 -45
- 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/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 +5 -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/customCommands.d.ts +1 -1
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/{hooks/matcher.d.ts → utils/hookMatcher.d.ts} +1 -1
- 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 +6 -1
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +16 -0
- 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 +240 -158
- package/src/managers/backgroundBashManager.ts +1 -1
- package/src/{hooks/manager.ts → managers/hookManager.ts} +159 -26
- package/src/managers/mcpManager.ts +1 -1
- package/src/managers/messageManager.ts +36 -6
- package/src/managers/skillManager.ts +1 -1
- package/src/managers/slashCommandManager.ts +5 -1
- package/src/managers/subagentManager.ts +46 -53
- 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/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 +103 -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 +1 -1
- package/src/utils/customCommands.ts +1 -1
- package/src/utils/markdownParser.ts +1 -1
- package/src/utils/mcpUtils.ts +1 -1
- package/src/utils/messageOperations.ts +20 -1
- 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/dist/{hooks/types.js → types/hooks.js} +0 -0
- /package/dist/{hooks/matcher.js → utils/hookMatcher.js} +0 -0
- /package/src/{types.ts → types/index.ts.backup} +0 -0
- /package/src/{hooks/matcher.ts → utils/hookMatcher.ts} +0 -0
|
@@ -17,11 +17,15 @@ import {
|
|
|
17
17
|
HookConfigurationError,
|
|
18
18
|
isValidHookEvent,
|
|
19
19
|
isValidHookEventConfig,
|
|
20
|
-
} from "
|
|
21
|
-
import { type IHookMatcher, HookMatcher } from "
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
} from "../types/hooks.js";
|
|
21
|
+
import { type IHookMatcher, 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 type { MessageManager } from "./messageManager.js";
|
|
25
29
|
|
|
26
30
|
export interface IHookManager {
|
|
27
31
|
// Load configuration from settings
|
|
@@ -52,22 +56,16 @@ export interface IHookManager {
|
|
|
52
56
|
export class HookManager implements IHookManager {
|
|
53
57
|
private configuration: PartialHookConfiguration | undefined;
|
|
54
58
|
private readonly matcher: IHookMatcher;
|
|
55
|
-
private readonly executor: IHookExecutor;
|
|
56
59
|
private readonly logger?: Logger;
|
|
57
60
|
private readonly workdir: string;
|
|
58
61
|
|
|
59
62
|
constructor(
|
|
60
63
|
workdir: string,
|
|
61
64
|
matcher: IHookMatcher = new HookMatcher(),
|
|
62
|
-
executor?: IHookExecutor,
|
|
63
65
|
logger?: Logger,
|
|
64
66
|
) {
|
|
65
67
|
this.workdir = workdir;
|
|
66
68
|
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
69
|
this.logger = logger;
|
|
72
70
|
}
|
|
73
71
|
|
|
@@ -112,19 +110,21 @@ export class HookManager implements IHookManager {
|
|
|
112
110
|
this.logger?.debug(`[HookManager] Loading configuration...`);
|
|
113
111
|
const mergedConfig = loadMergedHooksConfig(this.workdir);
|
|
114
112
|
this.logger?.debug(`[HookManager] Merged config result:`, mergedConfig);
|
|
115
|
-
this.configuration = mergedConfig;
|
|
116
|
-
|
|
117
|
-
// Validate the loaded configuration
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
113
|
+
this.configuration = mergedConfig || undefined;
|
|
114
|
+
|
|
115
|
+
// Validate the loaded configuration if it exists
|
|
116
|
+
if (mergedConfig) {
|
|
117
|
+
const validation = this.validatePartialConfiguration(mergedConfig);
|
|
118
|
+
if (!validation.valid) {
|
|
119
|
+
throw new HookConfigurationError(
|
|
120
|
+
"filesystem settings",
|
|
121
|
+
validation.errors,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
this.logger?.debug(
|
|
127
|
-
`[HookManager] Configuration loaded successfully with ${Object.keys(mergedConfig).length} event types`,
|
|
127
|
+
`[HookManager] Configuration loaded successfully with ${Object.keys(mergedConfig || {}).length} event types`,
|
|
128
128
|
);
|
|
129
129
|
} catch (error) {
|
|
130
130
|
// If loading fails, start with undefined configuration (no hooks)
|
|
@@ -219,10 +219,7 @@ export class HookManager implements IHookManager {
|
|
|
219
219
|
`[HookManager] Executing command ${commandIndex + 1}/${config.hooks.length} in configuration ${configIndex + 1}`,
|
|
220
220
|
);
|
|
221
221
|
|
|
222
|
-
const result = await
|
|
223
|
-
hookCommand.command,
|
|
224
|
-
context,
|
|
225
|
-
);
|
|
222
|
+
const result = await executeCommand(hookCommand.command, context);
|
|
226
223
|
results.push(result);
|
|
227
224
|
|
|
228
225
|
// Report individual command result
|
|
@@ -268,6 +265,142 @@ export class HookManager implements IHookManager {
|
|
|
268
265
|
return results;
|
|
269
266
|
}
|
|
270
267
|
|
|
268
|
+
/**
|
|
269
|
+
* Process hook execution results and determine appropriate actions
|
|
270
|
+
* based on exit codes and hook event type
|
|
271
|
+
*/
|
|
272
|
+
processHookResults(
|
|
273
|
+
event: HookEvent,
|
|
274
|
+
results: HookExecutionResult[],
|
|
275
|
+
messageManager?: MessageManager,
|
|
276
|
+
toolId?: string,
|
|
277
|
+
originalToolResult?: string,
|
|
278
|
+
): {
|
|
279
|
+
shouldBlock: boolean;
|
|
280
|
+
errorMessage?: string;
|
|
281
|
+
} {
|
|
282
|
+
if (!messageManager || results.length === 0) {
|
|
283
|
+
return { shouldBlock: false };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// First pass: Check for any blocking errors (exit code 2)
|
|
287
|
+
// Blocking errors take precedence and stop all processing
|
|
288
|
+
for (const result of results) {
|
|
289
|
+
if (result.exitCode === 2) {
|
|
290
|
+
// Handle blocking error immediately and return
|
|
291
|
+
return this.handleBlockingError(
|
|
292
|
+
event,
|
|
293
|
+
result,
|
|
294
|
+
messageManager,
|
|
295
|
+
toolId,
|
|
296
|
+
originalToolResult,
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// Second pass: Process all non-blocking results
|
|
302
|
+
for (const result of results) {
|
|
303
|
+
if (result.exitCode === undefined) {
|
|
304
|
+
continue; // Skip results without exit codes
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Handle exit code interpretation
|
|
308
|
+
if (result.exitCode === 0) {
|
|
309
|
+
// Success case - handle stdout based on hook type
|
|
310
|
+
this.handleHookSuccess(event, result, messageManager);
|
|
311
|
+
} else {
|
|
312
|
+
// Non-blocking error case (any exit code except 0 and 2)
|
|
313
|
+
this.handleNonBlockingError(result, messageManager);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
return { shouldBlock: false };
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Handle successful hook execution (exit code 0)
|
|
322
|
+
*/
|
|
323
|
+
private handleHookSuccess(
|
|
324
|
+
event: HookEvent,
|
|
325
|
+
result: HookExecutionResult,
|
|
326
|
+
messageManager: MessageManager,
|
|
327
|
+
): void {
|
|
328
|
+
if (event === "UserPromptSubmit" && result.stdout?.trim()) {
|
|
329
|
+
// Inject stdout as user message context for UserPromptSubmit
|
|
330
|
+
messageManager.addUserMessage(result.stdout.trim());
|
|
331
|
+
}
|
|
332
|
+
// For other hook types (PreToolUse, PostToolUse, Stop), ignore stdout
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Handle blocking error (exit code 2) - behavior varies by hook type
|
|
337
|
+
*/
|
|
338
|
+
private handleBlockingError(
|
|
339
|
+
event: HookEvent,
|
|
340
|
+
result: HookExecutionResult,
|
|
341
|
+
messageManager: MessageManager,
|
|
342
|
+
toolId?: string,
|
|
343
|
+
originalToolResult?: string,
|
|
344
|
+
): {
|
|
345
|
+
shouldBlock: boolean;
|
|
346
|
+
errorMessage?: string;
|
|
347
|
+
} {
|
|
348
|
+
const errorMessage = result.stderr?.trim() || "Hook execution failed";
|
|
349
|
+
|
|
350
|
+
switch (event) {
|
|
351
|
+
case "UserPromptSubmit":
|
|
352
|
+
// Block prompt processing, show error to user, erase prompt
|
|
353
|
+
messageManager.addErrorBlock(errorMessage);
|
|
354
|
+
messageManager.removeLastUserMessage();
|
|
355
|
+
return {
|
|
356
|
+
shouldBlock: true,
|
|
357
|
+
errorMessage,
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
case "PreToolUse":
|
|
361
|
+
// Block tool execution and show error to Wave Agent via tool block
|
|
362
|
+
if (toolId) {
|
|
363
|
+
messageManager.updateToolBlock({
|
|
364
|
+
toolId,
|
|
365
|
+
result: errorMessage,
|
|
366
|
+
success: false,
|
|
367
|
+
error: "Hook blocked tool execution",
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
return { shouldBlock: true };
|
|
371
|
+
|
|
372
|
+
case "PostToolUse":
|
|
373
|
+
// Show error to Wave Agent via tool block, execution continues
|
|
374
|
+
if (toolId && originalToolResult !== undefined) {
|
|
375
|
+
messageManager.updateToolBlock({
|
|
376
|
+
toolId,
|
|
377
|
+
result: `${originalToolResult}\n\nHook feedback: ${errorMessage}`,
|
|
378
|
+
success: false,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
return { shouldBlock: false };
|
|
382
|
+
|
|
383
|
+
case "Stop":
|
|
384
|
+
// Show error to Wave Agent via user message and block stopping to continue conversation
|
|
385
|
+
messageManager.addUserMessage(errorMessage);
|
|
386
|
+
return { shouldBlock: true, errorMessage };
|
|
387
|
+
|
|
388
|
+
default:
|
|
389
|
+
return { shouldBlock: false };
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Handle non-blocking error (other exit codes)
|
|
395
|
+
*/
|
|
396
|
+
private handleNonBlockingError(
|
|
397
|
+
result: HookExecutionResult,
|
|
398
|
+
messageManager: MessageManager,
|
|
399
|
+
): void {
|
|
400
|
+
const errorMessage = result.stderr?.trim() || "Hook execution failed";
|
|
401
|
+
messageManager.addErrorBlock(errorMessage);
|
|
402
|
+
}
|
|
403
|
+
|
|
271
404
|
/**
|
|
272
405
|
* Check if hooks are configured for an event/tool combination
|
|
273
406
|
*/
|
|
@@ -556,7 +689,7 @@ export class HookManager implements IHookManager {
|
|
|
556
689
|
|
|
557
690
|
// Validate commands
|
|
558
691
|
config.hooks.forEach((hookCommand, cmdIndex) => {
|
|
559
|
-
if (!
|
|
692
|
+
if (!isCommandSafe(hookCommand.command)) {
|
|
560
693
|
errors.push(
|
|
561
694
|
`${prefix}.hooks[${cmdIndex}]: Command may be unsafe: ${hookCommand.command}`,
|
|
562
695
|
);
|
|
@@ -12,11 +12,12 @@ import {
|
|
|
12
12
|
completeCommandInMessage,
|
|
13
13
|
addSubagentBlockToMessage,
|
|
14
14
|
updateSubagentBlockInMessage,
|
|
15
|
+
removeLastUserMessage,
|
|
15
16
|
type AddSubagentBlockParams,
|
|
16
17
|
type UpdateSubagentBlockParams,
|
|
17
18
|
type AgentToolBlockUpdateParams,
|
|
18
19
|
} from "../utils/messageOperations.js";
|
|
19
|
-
import type { Logger, Message, Usage } from "../types.js";
|
|
20
|
+
import type { Logger, Message, Usage } from "../types/index.js";
|
|
20
21
|
import {
|
|
21
22
|
cleanupExpiredSessions,
|
|
22
23
|
getLatestSession,
|
|
@@ -64,8 +65,19 @@ export interface MessageManagerCallbacks {
|
|
|
64
65
|
onUpdateCommandOutputMessage?: (command: string, output: string) => void;
|
|
65
66
|
onCompleteCommandMessage?: (command: string, exitCode: number) => void;
|
|
66
67
|
// Subagent callbacks
|
|
67
|
-
onSubAgentBlockAdded?: (
|
|
68
|
-
|
|
68
|
+
onSubAgentBlockAdded?: (
|
|
69
|
+
subagentId: string,
|
|
70
|
+
parameters: {
|
|
71
|
+
description: string;
|
|
72
|
+
prompt: string;
|
|
73
|
+
subagent_type: string;
|
|
74
|
+
},
|
|
75
|
+
) => void;
|
|
76
|
+
onSubAgentBlockUpdated?: (
|
|
77
|
+
subagentId: string,
|
|
78
|
+
messages: Message[],
|
|
79
|
+
status: "active" | "completed" | "error" | "aborted",
|
|
80
|
+
) => void;
|
|
69
81
|
}
|
|
70
82
|
|
|
71
83
|
export interface MessageManagerOptions {
|
|
@@ -168,7 +180,7 @@ export class MessageManager {
|
|
|
168
180
|
try {
|
|
169
181
|
await cleanupExpiredSessions(this.workdir, this.sessionDir);
|
|
170
182
|
} catch (error) {
|
|
171
|
-
|
|
183
|
+
this.logger?.warn("Failed to cleanup expired sessions:", error);
|
|
172
184
|
}
|
|
173
185
|
|
|
174
186
|
if (!restoreSessionId && !continueLastSession) {
|
|
@@ -448,6 +460,11 @@ export class MessageManager {
|
|
|
448
460
|
subagentName: string,
|
|
449
461
|
status: "active" | "completed" | "error" = "active",
|
|
450
462
|
subagentMessages: Message[] = [],
|
|
463
|
+
parameters: {
|
|
464
|
+
description: string;
|
|
465
|
+
prompt: string;
|
|
466
|
+
subagent_type: string;
|
|
467
|
+
},
|
|
451
468
|
): void {
|
|
452
469
|
const params: AddSubagentBlockParams = {
|
|
453
470
|
messages: this.messages,
|
|
@@ -458,7 +475,7 @@ export class MessageManager {
|
|
|
458
475
|
};
|
|
459
476
|
const updatedMessages = addSubagentBlockToMessage(params);
|
|
460
477
|
this.setMessages(updatedMessages);
|
|
461
|
-
this.callbacks.onSubAgentBlockAdded?.(params.subagentId);
|
|
478
|
+
this.callbacks.onSubAgentBlockAdded?.(params.subagentId, parameters);
|
|
462
479
|
}
|
|
463
480
|
|
|
464
481
|
public updateSubagentBlock(
|
|
@@ -480,7 +497,11 @@ export class MessageManager {
|
|
|
480
497
|
status: updates.status || "active",
|
|
481
498
|
subagentMessages: updates.messages || [],
|
|
482
499
|
};
|
|
483
|
-
this.callbacks.onSubAgentBlockUpdated?.(
|
|
500
|
+
this.callbacks.onSubAgentBlockUpdated?.(
|
|
501
|
+
params.subagentId,
|
|
502
|
+
params.messages,
|
|
503
|
+
params.status,
|
|
504
|
+
);
|
|
484
505
|
}
|
|
485
506
|
|
|
486
507
|
/**
|
|
@@ -495,4 +516,13 @@ export class MessageManager {
|
|
|
495
516
|
}
|
|
496
517
|
this.callbacks.onUsagesChange?.(usages);
|
|
497
518
|
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Remove the last user message from the conversation
|
|
522
|
+
* Used for hook error handling when the user prompt needs to be erased
|
|
523
|
+
*/
|
|
524
|
+
public removeLastUserMessage(): void {
|
|
525
|
+
const newMessages = removeLastUserMessage(this.messages);
|
|
526
|
+
this.setMessages(newMessages);
|
|
527
|
+
}
|
|
498
528
|
}
|
|
@@ -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 {
|
|
@@ -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,14 +206,31 @@ 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
235
|
instance.messageManager.addUserMessage(prompt);
|
|
216
236
|
|
|
@@ -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
|
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
ChatCompletionMessageParam,
|
|
6
6
|
ChatCompletionFunctionTool,
|
|
7
7
|
} from "openai/resources.js";
|
|
8
|
-
import type { GatewayConfig, ModelConfig } from "../types.js";
|
|
8
|
+
import type { GatewayConfig, ModelConfig } from "../types/index.js";
|
|
9
9
|
import * as os from "os";
|
|
10
10
|
import * as fs from "fs";
|
|
11
11
|
import * as path from "path";
|
|
@@ -116,7 +116,14 @@ export async function callAgent(
|
|
|
116
116
|
// Build system prompt content
|
|
117
117
|
let systemContent =
|
|
118
118
|
systemPrompt ||
|
|
119
|
-
`You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user
|
|
119
|
+
`You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
|
120
|
+
|
|
121
|
+
# Tool usage policy
|
|
122
|
+
- When doing file search, prefer to use the Task tool in order to reduce context usage.
|
|
123
|
+
- You should proactively use the Task tool with specialized agents when the task at hand matches the agent's description.
|
|
124
|
+
- You have the capability to call multiple tools in a single response. When multiple independent pieces of information are requested, batch your tool calls together for optimal performance. When making multiple bash tool calls, you MUST send a single message with multiple tools calls to run the calls in parallel. For example, if you need to run "git status" and "git diff", send a single message with two tool calls to run the calls in parallel.
|
|
125
|
+
|
|
126
|
+
`;
|
|
120
127
|
|
|
121
128
|
// Always add environment information
|
|
122
129
|
systemContent += `
|