wave-agent-sdk 0.13.2 → 0.13.4
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 +7 -0
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +37 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +65 -33
- package/dist/managers/backgroundTaskManager.d.ts +1 -0
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
- package/dist/managers/backgroundTaskManager.js +49 -0
- package/dist/managers/forkedAgentManager.d.ts +49 -0
- package/dist/managers/forkedAgentManager.d.ts.map +1 -0
- package/dist/managers/forkedAgentManager.js +111 -0
- package/dist/managers/messageManager.d.ts +8 -1
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +14 -1
- package/dist/managers/notificationQueue.d.ts +8 -0
- package/dist/managers/notificationQueue.d.ts.map +1 -0
- package/dist/managers/notificationQueue.js +17 -0
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +2 -0
- package/dist/managers/subagentManager.d.ts +0 -10
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +60 -20
- package/dist/services/autoMemoryService.d.ts +1 -1
- package/dist/services/autoMemoryService.d.ts.map +1 -1
- package/dist/services/autoMemoryService.js +7 -9
- package/dist/services/interactionService.d.ts.map +1 -1
- package/dist/services/interactionService.js +12 -0
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +0 -9
- package/dist/types/agent.d.ts +1 -0
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/messaging.d.ts +9 -1
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/utils/containerSetup.d.ts.map +1 -1
- package/dist/utils/containerSetup.js +6 -0
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +8 -0
- package/dist/utils/messageOperations.d.ts +9 -0
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +17 -0
- package/dist/utils/notificationXml.d.ts +4 -0
- package/dist/utils/notificationXml.d.ts.map +1 -0
- package/dist/utils/notificationXml.js +40 -0
- package/dist/utils/pathEncoder.d.ts +0 -1
- package/dist/utils/pathEncoder.d.ts.map +1 -1
- package/dist/utils/pathEncoder.js +1 -5
- package/package.json +1 -1
- package/src/agent.ts +44 -0
- package/src/index.ts +1 -0
- package/src/managers/aiManager.ts +76 -41
- package/src/managers/backgroundTaskManager.ts +72 -1
- package/src/managers/forkedAgentManager.ts +193 -0
- package/src/managers/messageManager.ts +25 -0
- package/src/managers/notificationQueue.ts +19 -0
- package/src/managers/permissionManager.ts +2 -0
- package/src/managers/subagentManager.ts +86 -42
- package/src/services/autoMemoryService.ts +11 -18
- package/src/services/interactionService.ts +18 -0
- package/src/tools/bashTool.ts +0 -9
- package/src/types/agent.ts +1 -0
- package/src/types/messaging.ts +11 -1
- package/src/utils/containerSetup.ts +8 -0
- package/src/utils/convertMessagesForAPI.ts +9 -0
- package/src/utils/messageOperations.ts +42 -1
- package/src/utils/notificationXml.ts +52 -0
- package/src/utils/pathEncoder.ts +1 -6
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class NotificationQueue {
|
|
2
|
+
private queue: string[] = [];
|
|
3
|
+
onNotificationsEnqueued?: () => void;
|
|
4
|
+
|
|
5
|
+
enqueue(notification: string): void {
|
|
6
|
+
this.queue.push(notification);
|
|
7
|
+
this.onNotificationsEnqueued?.();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
dequeueAll(): string[] {
|
|
11
|
+
const items = [...this.queue];
|
|
12
|
+
this.queue = [];
|
|
13
|
+
return items;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
hasPending(): boolean {
|
|
17
|
+
return this.queue.length > 0;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -50,6 +50,7 @@ const SAFE_COMMANDS = [
|
|
|
50
50
|
"wc",
|
|
51
51
|
"sleep",
|
|
52
52
|
"find",
|
|
53
|
+
"sort",
|
|
53
54
|
];
|
|
54
55
|
|
|
55
56
|
const DEFAULT_ALLOWED_RULES = [
|
|
@@ -867,6 +868,7 @@ export class PermissionManager {
|
|
|
867
868
|
cmd === "tail" ||
|
|
868
869
|
cmd === "wc" ||
|
|
869
870
|
cmd === "sleep" ||
|
|
871
|
+
cmd === "sort" ||
|
|
870
872
|
(cmd === "find" && !isDangerousFind(part))
|
|
871
873
|
) {
|
|
872
874
|
return true;
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
createAbortPromise,
|
|
14
14
|
} from "../utils/abortUtils.js";
|
|
15
15
|
import { BackgroundTaskManager } from "./backgroundTaskManager.js";
|
|
16
|
+
import { NotificationQueue } from "./notificationQueue.js";
|
|
16
17
|
import { logger } from "../utils/globalLogger.js";
|
|
17
18
|
import {
|
|
18
19
|
UserMessageParams,
|
|
@@ -220,6 +221,23 @@ export class SubagentManager {
|
|
|
220
221
|
// Create a child container for the subagent to isolate its managers
|
|
221
222
|
const subagentContainer = this.container.createChild();
|
|
222
223
|
|
|
224
|
+
// Register a modified AgentOptions without onLoadingChange to prevent subagent loading
|
|
225
|
+
// from affecting the parent agent's loading state
|
|
226
|
+
const parentOptions =
|
|
227
|
+
this.container.get<import("../types/agent.js").AgentOptions>(
|
|
228
|
+
"AgentOptions",
|
|
229
|
+
);
|
|
230
|
+
if (parentOptions) {
|
|
231
|
+
const subagentOptions: import("../types/agent.js").AgentOptions = {
|
|
232
|
+
...parentOptions,
|
|
233
|
+
callbacks: {
|
|
234
|
+
...parentOptions.callbacks,
|
|
235
|
+
onLoadingChange: undefined,
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
subagentContainer.register("AgentOptions", subagentOptions);
|
|
239
|
+
}
|
|
240
|
+
|
|
223
241
|
// Create isolated PermissionManager for the subagent
|
|
224
242
|
const { PermissionManager } = await import("./permissionManager.js");
|
|
225
243
|
const parentPermissionManager =
|
|
@@ -289,6 +307,22 @@ export class SubagentManager {
|
|
|
289
307
|
});
|
|
290
308
|
subagentContainer.register("AIManager", aiManager);
|
|
291
309
|
|
|
310
|
+
// Create isolated NotificationQueue for the subagent/forked agent
|
|
311
|
+
const subagentNotificationQueue = new NotificationQueue();
|
|
312
|
+
subagentContainer.register("NotificationQueue", subagentNotificationQueue);
|
|
313
|
+
|
|
314
|
+
// Create isolated BackgroundTaskManager for the subagent/forked agent
|
|
315
|
+
const subagentBackgroundTaskManager = new BackgroundTaskManager(
|
|
316
|
+
subagentContainer,
|
|
317
|
+
{
|
|
318
|
+
workdir: this.workdir,
|
|
319
|
+
},
|
|
320
|
+
);
|
|
321
|
+
subagentContainer.register(
|
|
322
|
+
"BackgroundTaskManager",
|
|
323
|
+
subagentBackgroundTaskManager,
|
|
324
|
+
);
|
|
325
|
+
|
|
292
326
|
const instance: SubagentInstance = {
|
|
293
327
|
subagentId,
|
|
294
328
|
configuration,
|
|
@@ -310,43 +344,6 @@ export class SubagentManager {
|
|
|
310
344
|
return instance;
|
|
311
345
|
}
|
|
312
346
|
|
|
313
|
-
/**
|
|
314
|
-
* Create a new subagent instance initialized with a copy of the current message history.
|
|
315
|
-
* This is used for background tasks like auto-memory extraction.
|
|
316
|
-
*/
|
|
317
|
-
async forkAgent(
|
|
318
|
-
subagentType: string,
|
|
319
|
-
messages: Message[],
|
|
320
|
-
parameters: {
|
|
321
|
-
description: string;
|
|
322
|
-
allowedTools?: string[];
|
|
323
|
-
model?: string;
|
|
324
|
-
permissionModeOverride?: PermissionMode;
|
|
325
|
-
},
|
|
326
|
-
onUpdate?: () => void,
|
|
327
|
-
): Promise<SubagentInstance> {
|
|
328
|
-
const configuration = await this.findSubagent(subagentType);
|
|
329
|
-
if (!configuration) {
|
|
330
|
-
throw new Error(`Subagent type ${subagentType} not found`);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const instance = await this.createInstance(
|
|
334
|
-
configuration,
|
|
335
|
-
{
|
|
336
|
-
...parameters,
|
|
337
|
-
subagent_type: subagentType,
|
|
338
|
-
prompt: "", // Forked agents start with history
|
|
339
|
-
},
|
|
340
|
-
false,
|
|
341
|
-
onUpdate,
|
|
342
|
-
);
|
|
343
|
-
|
|
344
|
-
// Initialize the message manager with provided messages
|
|
345
|
-
instance.messageManager.setMessages(messages);
|
|
346
|
-
|
|
347
|
-
return instance;
|
|
348
|
-
}
|
|
349
|
-
|
|
350
347
|
/**
|
|
351
348
|
* Execute agent using subagent instance
|
|
352
349
|
*
|
|
@@ -416,6 +413,17 @@ export class SubagentManager {
|
|
|
416
413
|
task.endTime = Date.now();
|
|
417
414
|
task.runtime = task.endTime - startTime;
|
|
418
415
|
}
|
|
416
|
+
|
|
417
|
+
// Enqueue completion notification
|
|
418
|
+
const notificationQueue = this.container.has("NotificationQueue")
|
|
419
|
+
? this.container.get<NotificationQueue>("NotificationQueue")
|
|
420
|
+
: undefined;
|
|
421
|
+
if (notificationQueue) {
|
|
422
|
+
const summary = `Agent task "${instance.description}" completed`;
|
|
423
|
+
notificationQueue.enqueue(
|
|
424
|
+
`<task-notification>\n<task-id>${taskId}</task-id>\n<task-type>agent</task-type>\n<status>completed</status>\n<summary>${summary}</summary>\n</task-notification>`,
|
|
425
|
+
);
|
|
426
|
+
}
|
|
419
427
|
} catch (error) {
|
|
420
428
|
const task = backgroundTaskManager?.getTask(taskId);
|
|
421
429
|
if (task) {
|
|
@@ -425,6 +433,19 @@ export class SubagentManager {
|
|
|
425
433
|
task.endTime = Date.now();
|
|
426
434
|
task.runtime = task.endTime - startTime;
|
|
427
435
|
}
|
|
436
|
+
|
|
437
|
+
// Enqueue error notification
|
|
438
|
+
const notificationQueue = this.container.has("NotificationQueue")
|
|
439
|
+
? this.container.get<NotificationQueue>("NotificationQueue")
|
|
440
|
+
: undefined;
|
|
441
|
+
if (notificationQueue) {
|
|
442
|
+
const errorMsg =
|
|
443
|
+
error instanceof Error ? error.message : String(error);
|
|
444
|
+
const summary = `Agent task "${instance.description}" failed: ${errorMsg}`;
|
|
445
|
+
notificationQueue.enqueue(
|
|
446
|
+
`<task-notification>\n<task-id>${taskId}</task-id>\n<task-type>agent</task-type>\n<status>failed</status>\n<summary>${summary}</summary>\n</task-notification>`,
|
|
447
|
+
);
|
|
448
|
+
}
|
|
428
449
|
}
|
|
429
450
|
})();
|
|
430
451
|
|
|
@@ -568,6 +589,17 @@ export class SubagentManager {
|
|
|
568
589
|
task.runtime = task.endTime - task.startTime;
|
|
569
590
|
}
|
|
570
591
|
}
|
|
592
|
+
|
|
593
|
+
// Enqueue completion notification
|
|
594
|
+
const notificationQueue = this.container.has("NotificationQueue")
|
|
595
|
+
? this.container.get<NotificationQueue>("NotificationQueue")
|
|
596
|
+
: undefined;
|
|
597
|
+
if (notificationQueue) {
|
|
598
|
+
const summary = `Agent task "${instance.description}" completed`;
|
|
599
|
+
notificationQueue.enqueue(
|
|
600
|
+
`<task-notification>\n<task-id>${instance.backgroundTaskId}</task-id>\n<task-type>agent</task-type>\n<status>completed</status>\n<summary>${summary}</summary>\n</task-notification>`,
|
|
601
|
+
);
|
|
602
|
+
}
|
|
571
603
|
}
|
|
572
604
|
|
|
573
605
|
return response || "Agent completed with no text response";
|
|
@@ -592,6 +624,19 @@ export class SubagentManager {
|
|
|
592
624
|
task.runtime = task.endTime - task.startTime;
|
|
593
625
|
}
|
|
594
626
|
}
|
|
627
|
+
|
|
628
|
+
// Enqueue error notification
|
|
629
|
+
const notificationQueue = this.container.has("NotificationQueue")
|
|
630
|
+
? this.container.get<NotificationQueue>("NotificationQueue")
|
|
631
|
+
: undefined;
|
|
632
|
+
if (notificationQueue) {
|
|
633
|
+
const errorMsg =
|
|
634
|
+
error instanceof Error ? error.message : String(error);
|
|
635
|
+
const summary = `Agent task "${instance.description}" failed: ${errorMsg}`;
|
|
636
|
+
notificationQueue.enqueue(
|
|
637
|
+
`<task-notification>\n<task-id>${instance.backgroundTaskId}</task-id>\n<task-type>agent</task-type>\n<status>failed</status>\n<summary>${summary}</summary>\n</task-notification>`,
|
|
638
|
+
);
|
|
639
|
+
}
|
|
595
640
|
}
|
|
596
641
|
throw error;
|
|
597
642
|
} finally {
|
|
@@ -721,12 +766,11 @@ export class SubagentManager {
|
|
|
721
766
|
|
|
722
767
|
// Log tool execution to file
|
|
723
768
|
if (instance.logStream) {
|
|
724
|
-
const
|
|
725
|
-
|
|
726
|
-
100
|
|
727
|
-
);
|
|
769
|
+
const displayParams =
|
|
770
|
+
params.compactParams ||
|
|
771
|
+
(params.parameters || "{}").substring(0, 100);
|
|
728
772
|
instance.logStream.write(
|
|
729
|
-
`[${new Date().toISOString()}]
|
|
773
|
+
`[${new Date().toISOString()}] ${params.name}${displayParams ? ` ${displayParams}` : ""}\n`,
|
|
730
774
|
);
|
|
731
775
|
}
|
|
732
776
|
}
|
|
@@ -2,7 +2,7 @@ import * as path from "node:path";
|
|
|
2
2
|
import * as fs from "node:fs/promises";
|
|
3
3
|
import { Container } from "../utils/container.js";
|
|
4
4
|
import { MessageManager } from "../managers/messageManager.js";
|
|
5
|
-
import {
|
|
5
|
+
import { ForkedAgentManager } from "../managers/forkedAgentManager.js";
|
|
6
6
|
import { MemoryService } from "./memory.js";
|
|
7
7
|
import { ConfigurationService } from "./configurationService.js";
|
|
8
8
|
import { logger } from "../utils/globalLogger.js";
|
|
@@ -24,8 +24,8 @@ export class AutoMemoryService {
|
|
|
24
24
|
return this.container.get<MessageManager>("MessageManager")!;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
private get
|
|
28
|
-
return this.container.get<
|
|
27
|
+
private get forkedAgentManager(): ForkedAgentManager {
|
|
28
|
+
return this.container.get<ForkedAgentManager>("ForkedAgentManager")!;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
private get memoryService(): MemoryService {
|
|
@@ -143,8 +143,13 @@ export class AutoMemoryService {
|
|
|
143
143
|
}
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
const prompt = buildAutoMemoryExtractionPrompt(
|
|
147
|
+
newMessageCount,
|
|
148
|
+
existingMemoriesManifest,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Execute the forked agent in background (fire-and-forget, decoupled from BackgroundTaskManager)
|
|
152
|
+
await this.forkedAgentManager.forkAndExecute(
|
|
148
153
|
"general-purpose",
|
|
149
154
|
messages,
|
|
150
155
|
{
|
|
@@ -157,21 +162,9 @@ export class AutoMemoryService {
|
|
|
157
162
|
`Edit(${memoryDir}/**/*)`,
|
|
158
163
|
],
|
|
159
164
|
model: "fastModel", // Use fast model for background tasks to reduce latency and cost
|
|
160
|
-
permissionModeOverride: "
|
|
165
|
+
permissionModeOverride: "dontAsk", // Auto-deny out-of-scope writes without prompting user
|
|
161
166
|
},
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
const prompt = buildAutoMemoryExtractionPrompt(
|
|
165
|
-
newMessageCount,
|
|
166
|
-
existingMemoriesManifest,
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
// Execute in background so it doesn't block the main conversation flow
|
|
170
|
-
await this.subagentManager.executeAgent(
|
|
171
|
-
instance,
|
|
172
167
|
`${prompt}\n\nThe memory directory for this project is: ${memoryDir}`,
|
|
173
|
-
undefined,
|
|
174
|
-
true, // runInBackground
|
|
175
168
|
);
|
|
176
169
|
|
|
177
170
|
logger.debug("Auto-memory extraction started in background.");
|
|
@@ -7,6 +7,7 @@ import type { ConfigurationService } from "./configurationService.js";
|
|
|
7
7
|
import type { AIManager } from "../managers/aiManager.js";
|
|
8
8
|
import type { SubagentManager } from "../managers/subagentManager.js";
|
|
9
9
|
import type { TaskManager } from "./taskManager.js";
|
|
10
|
+
import type { NotificationQueue } from "../managers/notificationQueue.js";
|
|
10
11
|
|
|
11
12
|
export interface InteractionContext {
|
|
12
13
|
messageManager: MessageManager;
|
|
@@ -58,6 +59,23 @@ export class InteractionService {
|
|
|
58
59
|
// Don't add to history, let normal message processing logic below handle it
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
// Inject pending notifications from background tasks
|
|
63
|
+
const notificationQueue = context.aiManager["container"].has(
|
|
64
|
+
"NotificationQueue",
|
|
65
|
+
)
|
|
66
|
+
? context.aiManager["container"].get<NotificationQueue>(
|
|
67
|
+
"NotificationQueue",
|
|
68
|
+
)
|
|
69
|
+
: undefined;
|
|
70
|
+
if (notificationQueue && notificationQueue.hasPending()) {
|
|
71
|
+
const notifications = notificationQueue.dequeueAll();
|
|
72
|
+
for (const notification of notifications) {
|
|
73
|
+
messageManager.addUserMessage({
|
|
74
|
+
content: notification,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
61
79
|
// Handle normal AI message
|
|
62
80
|
// Add user message first, will automatically sync to UI
|
|
63
81
|
messageManager.addUserMessage({
|
package/src/tools/bashTool.ts
CHANGED
|
@@ -118,16 +118,7 @@ Usage notes:
|
|
|
118
118
|
- If the commands depend on each other and must run sequentially, use a single ${BASH_TOOL_NAME} call with '&&' to chain them together (e.g., \`git add . && git commit -m "message" && git push\`). For instance, if one operation must complete before another starts (like mkdir before cp, ${WRITE_TOOL_NAME} before ${BASH_TOOL_NAME} for git operations, or git add before git commit), run these operations sequentially instead.
|
|
119
119
|
- Use ';' only when you need to run commands sequentially but don't care if earlier commands fail
|
|
120
120
|
- DO NOT use newlines to separate commands (newlines are ok in quoted strings)
|
|
121
|
-
- Try to maintain your current working directory throughout the session by using absolute paths and avoiding usage of \`cd\`. You may use \`cd\` if the User explicitly requests it.
|
|
122
|
-
<good-example>
|
|
123
|
-
pytest /foo/bar/tests
|
|
124
|
-
</good-example>
|
|
125
|
-
<bad-example>
|
|
126
|
-
cd /foo/bar && pytest tests
|
|
127
|
-
</bad-example>
|
|
128
|
-
|
|
129
121
|
- Reserve bash tools exclusively for actual system commands and terminal operations that require shell execution. NEVER use bash echo or other command-line tools to communicate thoughts, explanations, or instructions to the user. Output all communication directly in your response text instead.
|
|
130
|
-
- 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 in parallel.
|
|
131
122
|
|
|
132
123
|
# Git operations
|
|
133
124
|
Git Safety Protocol:
|
package/src/types/agent.ts
CHANGED
package/src/types/messaging.ts
CHANGED
|
@@ -27,7 +27,8 @@ export type MessageBlock =
|
|
|
27
27
|
| BangBlock
|
|
28
28
|
| CompressBlock
|
|
29
29
|
| ReasoningBlock
|
|
30
|
-
| FileHistoryBlock
|
|
30
|
+
| FileHistoryBlock
|
|
31
|
+
| TaskNotificationBlock;
|
|
31
32
|
|
|
32
33
|
export interface TextBlock {
|
|
33
34
|
type: "text";
|
|
@@ -99,3 +100,12 @@ export interface FileHistoryBlock {
|
|
|
99
100
|
type: "file_history";
|
|
100
101
|
snapshots: import("./reversion.js").FileSnapshot[];
|
|
101
102
|
}
|
|
103
|
+
|
|
104
|
+
export interface TaskNotificationBlock {
|
|
105
|
+
type: "task_notification";
|
|
106
|
+
taskId: string;
|
|
107
|
+
taskType: "shell" | "agent";
|
|
108
|
+
status: "completed" | "failed" | "killed";
|
|
109
|
+
summary: string;
|
|
110
|
+
outputFile?: string;
|
|
111
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Container } from "./container.js";
|
|
2
2
|
import { ForegroundTaskManager } from "../managers/foregroundTaskManager.js";
|
|
3
3
|
import { BackgroundTaskManager } from "../managers/backgroundTaskManager.js";
|
|
4
|
+
import { NotificationQueue } from "../managers/notificationQueue.js";
|
|
4
5
|
import { TaskManager } from "../services/taskManager.js";
|
|
5
6
|
import { MessageManager } from "../managers/messageManager.js";
|
|
6
7
|
import { AIManager } from "../managers/aiManager.js";
|
|
@@ -18,6 +19,7 @@ import { CronManager } from "../managers/cronManager.js";
|
|
|
18
19
|
import { MemoryRuleManager } from "../managers/MemoryRuleManager.js";
|
|
19
20
|
import { ReversionManager } from "../managers/reversionManager.js";
|
|
20
21
|
import { SubagentManager } from "../managers/subagentManager.js";
|
|
22
|
+
import { ForkedAgentManager } from "../managers/forkedAgentManager.js";
|
|
21
23
|
import { LiveConfigManager } from "../managers/liveConfigManager.js";
|
|
22
24
|
import { ConfigurationService } from "../services/configurationService.js";
|
|
23
25
|
import { ReversionService } from "../services/reversionService.js";
|
|
@@ -75,6 +77,9 @@ export function setupAgentContainer(
|
|
|
75
77
|
const container = new Container();
|
|
76
78
|
container.register("AgentOptions", options);
|
|
77
79
|
|
|
80
|
+
const notificationQueue = new NotificationQueue();
|
|
81
|
+
container.register("NotificationQueue", notificationQueue);
|
|
82
|
+
|
|
78
83
|
const foregroundTaskManager = new ForegroundTaskManager(container);
|
|
79
84
|
container.register("ForegroundTaskManager", foregroundTaskManager);
|
|
80
85
|
container.register("ConfigurationService", configurationService);
|
|
@@ -283,6 +288,9 @@ export function setupAgentContainer(
|
|
|
283
288
|
});
|
|
284
289
|
container.register("SubagentManager", subagentManager);
|
|
285
290
|
|
|
291
|
+
const forkedAgentManager = new ForkedAgentManager(container);
|
|
292
|
+
container.register("ForkedAgentManager", forkedAgentManager);
|
|
293
|
+
|
|
286
294
|
const aiManager = new AIManager(container, {
|
|
287
295
|
callbacks: {
|
|
288
296
|
...callbacks,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Message } from "../types/index.js";
|
|
2
2
|
import { convertImageToBase64 } from "./messageOperations.js";
|
|
3
|
+
import { taskNotificationToXml } from "./notificationXml.js";
|
|
3
4
|
import { ChatCompletionMessageToolCall } from "openai/resources";
|
|
4
5
|
import { stripAnsiColors } from "./stringUtils.js";
|
|
5
6
|
import {
|
|
@@ -239,6 +240,14 @@ export function convertMessagesForAPI(
|
|
|
239
240
|
text: `<local-command-stdout>\n${stripAnsiColors(block.result)}\n</local-command-stdout>`,
|
|
240
241
|
});
|
|
241
242
|
}
|
|
243
|
+
|
|
244
|
+
// If there is a task notification block, convert it back to XML
|
|
245
|
+
if (block.type === "task_notification") {
|
|
246
|
+
contentParts.push({
|
|
247
|
+
type: "text",
|
|
248
|
+
text: taskNotificationToXml(block),
|
|
249
|
+
});
|
|
250
|
+
}
|
|
242
251
|
});
|
|
243
252
|
|
|
244
253
|
// Only add user message if there is meaningful content
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
Message,
|
|
4
|
+
Usage,
|
|
5
|
+
ToolBlock,
|
|
6
|
+
TaskNotificationBlock,
|
|
7
|
+
} from "../types/index.js";
|
|
3
8
|
import { MessageSource } from "../types/index.js";
|
|
4
9
|
import { readFileSync } from "fs";
|
|
5
10
|
import { extname } from "path";
|
|
@@ -135,6 +140,7 @@ export const addUserMessageToMessages = ({
|
|
|
135
140
|
const textBlock = {
|
|
136
141
|
type: "text" as const,
|
|
137
142
|
content,
|
|
143
|
+
stage: "end" as const,
|
|
138
144
|
...(customCommandContent && { customCommandContent }),
|
|
139
145
|
...(source && { source }),
|
|
140
146
|
};
|
|
@@ -584,3 +590,38 @@ export function getMessageContent(message: Message): string {
|
|
|
584
590
|
|
|
585
591
|
return "";
|
|
586
592
|
}
|
|
593
|
+
|
|
594
|
+
export interface AddNotificationMessageParams {
|
|
595
|
+
messages: Message[];
|
|
596
|
+
taskId: string;
|
|
597
|
+
taskType: "shell" | "agent";
|
|
598
|
+
status: "completed" | "failed" | "killed";
|
|
599
|
+
summary: string;
|
|
600
|
+
outputFile?: string;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
export const addNotificationMessageToMessages = ({
|
|
604
|
+
messages,
|
|
605
|
+
taskId,
|
|
606
|
+
taskType,
|
|
607
|
+
status,
|
|
608
|
+
summary,
|
|
609
|
+
outputFile,
|
|
610
|
+
}: AddNotificationMessageParams): Message[] => {
|
|
611
|
+
const block: TaskNotificationBlock = {
|
|
612
|
+
type: "task_notification",
|
|
613
|
+
taskId,
|
|
614
|
+
taskType,
|
|
615
|
+
status,
|
|
616
|
+
summary,
|
|
617
|
+
...(outputFile !== undefined && { outputFile }),
|
|
618
|
+
};
|
|
619
|
+
|
|
620
|
+
const notificationMessage: Message = {
|
|
621
|
+
id: generateMessageId(),
|
|
622
|
+
role: "user",
|
|
623
|
+
blocks: [block],
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
return [...messages, notificationMessage];
|
|
627
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { TaskNotificationBlock } from "../types/messaging.js";
|
|
2
|
+
|
|
3
|
+
export function taskNotificationToXml(block: TaskNotificationBlock): string {
|
|
4
|
+
let xml = `<task-notification>\n`;
|
|
5
|
+
xml += `<task-id>${block.taskId}</task-id>\n`;
|
|
6
|
+
xml += `<task-type>${block.taskType}</task-type>\n`;
|
|
7
|
+
if (block.outputFile) {
|
|
8
|
+
xml += `<output-file>${block.outputFile}</output-file>\n`;
|
|
9
|
+
}
|
|
10
|
+
xml += `<status>${block.status}</status>\n`;
|
|
11
|
+
xml += `<summary>${block.summary}</summary>\n`;
|
|
12
|
+
xml += `</task-notification>`;
|
|
13
|
+
return xml;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function extractTag(xml: string, tag: string): string | null {
|
|
17
|
+
const regex = new RegExp(`<${tag}>(.*?)</${tag}>`, "s");
|
|
18
|
+
const match = xml.match(regex);
|
|
19
|
+
return match ? match[1] : null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function parseTaskNotificationXml(
|
|
23
|
+
xml: string,
|
|
24
|
+
): TaskNotificationBlock | null {
|
|
25
|
+
try {
|
|
26
|
+
const taskId = extractTag(xml, "task-id");
|
|
27
|
+
const taskType = extractTag(xml, "task-type") as "shell" | "agent" | null;
|
|
28
|
+
const status = extractTag(xml, "status") as
|
|
29
|
+
| "completed"
|
|
30
|
+
| "failed"
|
|
31
|
+
| "killed"
|
|
32
|
+
| null;
|
|
33
|
+
const summary = extractTag(xml, "summary");
|
|
34
|
+
|
|
35
|
+
if (!taskId || !taskType || !status || !summary) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const outputFile = extractTag(xml, "output-file") || undefined;
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
type: "task_notification",
|
|
43
|
+
taskId,
|
|
44
|
+
taskType,
|
|
45
|
+
status,
|
|
46
|
+
summary,
|
|
47
|
+
...(outputFile && { outputFile }),
|
|
48
|
+
};
|
|
49
|
+
} catch {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
package/src/utils/pathEncoder.ts
CHANGED
|
@@ -27,7 +27,6 @@ export interface PathEncodingOptions {
|
|
|
27
27
|
pathSeparatorReplacement?: string; // Default: '-'
|
|
28
28
|
spaceReplacement?: string; // Default: '_'
|
|
29
29
|
invalidCharReplacement?: string; // Default: '_'
|
|
30
|
-
preserveCase?: boolean; // Default: false (convert to lowercase)
|
|
31
30
|
hashLength?: number; // Default: 8 characters
|
|
32
31
|
}
|
|
33
32
|
|
|
@@ -65,7 +64,6 @@ export class PathEncoder {
|
|
|
65
64
|
pathSeparatorReplacement: options.pathSeparatorReplacement ?? "-",
|
|
66
65
|
spaceReplacement: options.spaceReplacement ?? "_",
|
|
67
66
|
invalidCharReplacement: options.invalidCharReplacement ?? "_",
|
|
68
|
-
preserveCase: options.preserveCase ?? false,
|
|
69
67
|
hashLength: options.hashLength ?? 8,
|
|
70
68
|
};
|
|
71
69
|
this.constraints = this.getFilesystemConstraints();
|
|
@@ -109,10 +107,7 @@ export class PathEncoder {
|
|
|
109
107
|
this.options.invalidCharReplacement,
|
|
110
108
|
);
|
|
111
109
|
|
|
112
|
-
//
|
|
113
|
-
if (!this.options.preserveCase) {
|
|
114
|
-
encoded = encoded.toLowerCase();
|
|
115
|
-
}
|
|
110
|
+
// Case is preserved
|
|
116
111
|
|
|
117
112
|
// Handle length limit with hash
|
|
118
113
|
if (encoded.length > this.options.maxLength) {
|