wave-agent-sdk 1.0.0 → 1.0.1
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 +9 -20
- package/dist/agent.js +23 -97
- package/dist/managers/aiManager.d.ts +63 -8
- package/dist/managers/aiManager.js +270 -80
- package/dist/managers/messageManager.d.ts +9 -5
- package/dist/managers/messageManager.js +36 -12
- package/dist/managers/subagentManager.d.ts +6 -0
- package/dist/managers/subagentManager.js +33 -22
- package/dist/prompts/index.d.ts +0 -1
- package/dist/prompts/index.js +0 -4
- package/dist/services/aiService.d.ts +1 -34
- package/dist/services/aiService.js +18 -130
- package/dist/services/autoMemoryService.d.ts +27 -2
- package/dist/services/autoMemoryService.js +124 -36
- package/dist/services/configurationService.js +14 -1
- package/dist/services/session.d.ts +13 -0
- package/dist/services/session.js +64 -0
- package/dist/types/agent.d.ts +0 -2
- package/dist/types/config.d.ts +7 -0
- package/dist/types/core.d.ts +1 -1
- package/dist/utils/containerSetup.js +12 -3
- package/package.json +1 -1
- package/src/agent.ts +36 -110
- package/src/managers/aiManager.ts +366 -105
- package/src/managers/messageManager.ts +51 -23
- package/src/managers/subagentManager.ts +36 -25
- package/src/prompts/index.ts +0 -4
- package/src/services/aiService.ts +25 -203
- package/src/services/autoMemoryService.ts +145 -39
- package/src/services/configurationService.ts +16 -1
- package/src/services/session.ts +68 -0
- package/src/types/agent.ts +0 -6
- package/src/types/config.ts +7 -0
- package/src/types/core.ts +1 -1
- package/src/utils/containerSetup.ts +12 -4
- package/dist/constants/goalPrompts.d.ts +0 -1
- package/dist/constants/goalPrompts.js +0 -10
- package/dist/managers/goalManager.d.ts +0 -42
- package/dist/managers/goalManager.js +0 -177
- package/src/constants/goalPrompts.ts +0 -10
- package/src/managers/goalManager.ts +0 -232
package/dist/agent.d.ts
CHANGED
|
@@ -19,7 +19,6 @@ export declare class Agent {
|
|
|
19
19
|
private pluginManager;
|
|
20
20
|
private skillManager;
|
|
21
21
|
private cronManager;
|
|
22
|
-
private goalManager;
|
|
23
22
|
private hookManager;
|
|
24
23
|
private reversionManager;
|
|
25
24
|
private messageQueue;
|
|
@@ -92,10 +91,6 @@ export declare class Agent {
|
|
|
92
91
|
get isCommandRunning(): boolean;
|
|
93
92
|
/** Get queued user-facing messages (excludes background notifications) */
|
|
94
93
|
get queuedMessages(): QueuedMessage[];
|
|
95
|
-
/** Get goal status string */
|
|
96
|
-
get goalStatus(): string;
|
|
97
|
-
/** Check if a goal is active */
|
|
98
|
-
get isGoalActive(): boolean;
|
|
99
94
|
/**
|
|
100
95
|
* Remove a queued message by index
|
|
101
96
|
* @param index - The index of the message to remove
|
|
@@ -231,19 +226,6 @@ export declare class Agent {
|
|
|
231
226
|
* @param customInstructions - Optional custom instructions for compaction
|
|
232
227
|
*/
|
|
233
228
|
compact(customInstructions?: string): Promise<void>;
|
|
234
|
-
/**
|
|
235
|
-
* Set an autonomous goal for the session
|
|
236
|
-
* @param condition - The goal condition to achieve
|
|
237
|
-
*/
|
|
238
|
-
setGoal(condition: string): Promise<void>;
|
|
239
|
-
/**
|
|
240
|
-
* Clear the current autonomous goal
|
|
241
|
-
*/
|
|
242
|
-
clearGoal(): Promise<void>;
|
|
243
|
-
/**
|
|
244
|
-
* Show the current goal status
|
|
245
|
-
*/
|
|
246
|
-
showGoalStatus(): Promise<void>;
|
|
247
229
|
/** Unified interrupt method, interrupts both AI messages and command execution */
|
|
248
230
|
abortMessage(): void;
|
|
249
231
|
/** Interrupt bash command execution */
|
|
@@ -275,11 +257,18 @@ export declare class Agent {
|
|
|
275
257
|
*/
|
|
276
258
|
triggerShowRewind(): void;
|
|
277
259
|
/**
|
|
278
|
-
* Ask a side question without
|
|
260
|
+
* Ask a side question without interrupting the main agent.
|
|
261
|
+
*
|
|
262
|
+
* Runs a single-turn fork of the conversation that reuses the main loop's
|
|
263
|
+
* system prompt, tools, and memory injection (prompt-cache friendly) and
|
|
264
|
+
* never executes tools. The abort signal lets the UI cancel a pending
|
|
265
|
+
* question (loading dismiss); aborts propagate as thrown errors.
|
|
266
|
+
*
|
|
279
267
|
* @param question - The side question to ask
|
|
268
|
+
* @param abortSignal - Optional signal to abort the pending request
|
|
280
269
|
* @returns Promise that resolves to the AI's answer
|
|
281
270
|
*/
|
|
282
|
-
askBtw(question: string): Promise<string>;
|
|
271
|
+
askBtw(question: string, abortSignal?: AbortSignal, onContent?: (content: string) => void, onReasoning?: (content: string) => void): Promise<string>;
|
|
283
272
|
/**
|
|
284
273
|
* Send a message to the AI agent with optional images
|
|
285
274
|
*
|
package/dist/agent.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { LspManager } from "./managers/lspManager.js";
|
|
2
2
|
import { configValidator } from "./utils/configValidator.js";
|
|
3
|
-
import { btw } from "./services/aiService.js";
|
|
4
|
-
import { convertMessagesForAPI } from "./utils/convertMessagesForAPI.js";
|
|
5
|
-
import { supportsVision } from "./utils/modelCapabilities.js";
|
|
6
3
|
import { parseTaskNotificationXml } from "./utils/notificationXml.js";
|
|
7
4
|
import { InitializationService } from "./services/initializationService.js";
|
|
8
5
|
import { InteractionService } from "./services/interactionService.js";
|
|
@@ -114,7 +111,6 @@ export class Agent {
|
|
|
114
111
|
this.pluginManager = this.container.get("PluginManager");
|
|
115
112
|
this.bangManager = this.container.get("BangManager");
|
|
116
113
|
this.cronManager = this.container.get("CronManager");
|
|
117
|
-
this.goalManager = this.container.get("GoalManager");
|
|
118
114
|
this.messageQueue = this.container.get("MessageQueue");
|
|
119
115
|
// Wire up CWD change callback from AIManager to sync Agent's workdir
|
|
120
116
|
this.aiManager.setOnCwdChange((newCwd) => {
|
|
@@ -141,14 +137,6 @@ export class Agent {
|
|
|
141
137
|
if (options.permissionMode) {
|
|
142
138
|
this.setPermissionMode(options.permissionMode);
|
|
143
139
|
}
|
|
144
|
-
// Wire up goal state change callback
|
|
145
|
-
this.goalManager.setOnGoalStateChange((active, condition, elapsed) => {
|
|
146
|
-
this.options.callbacks?.onGoalStateChange?.(active, condition, elapsed);
|
|
147
|
-
});
|
|
148
|
-
// Wire up goal evaluating callback
|
|
149
|
-
this.goalManager.setOnGoalEvaluating((evaluating) => {
|
|
150
|
-
this.options.callbacks?.onGoalEvaluating?.(evaluating);
|
|
151
|
-
});
|
|
152
140
|
}
|
|
153
141
|
// Public getter methods
|
|
154
142
|
get sessionId() {
|
|
@@ -219,14 +207,6 @@ export class Agent {
|
|
|
219
207
|
.getQueue()
|
|
220
208
|
.filter((m) => m.type !== "notification");
|
|
221
209
|
}
|
|
222
|
-
/** Get goal status string */
|
|
223
|
-
get goalStatus() {
|
|
224
|
-
return this.goalManager.getStatusString();
|
|
225
|
-
}
|
|
226
|
-
/** Check if a goal is active */
|
|
227
|
-
get isGoalActive() {
|
|
228
|
-
return this.goalManager.isGoalActive();
|
|
229
|
-
}
|
|
230
210
|
/**
|
|
231
211
|
* Remove a queued message by index
|
|
232
212
|
* @param index - The index of the message to remove
|
|
@@ -524,8 +504,6 @@ export class Agent {
|
|
|
524
504
|
}
|
|
525
505
|
async clearMessages() {
|
|
526
506
|
this.aiManager.abortAIMessage();
|
|
527
|
-
// Clear any active goal
|
|
528
|
-
this.goalManager.clearGoal();
|
|
529
507
|
// Capture old session info before clearing
|
|
530
508
|
const oldSessionId = this.messageManager.getSessionId();
|
|
531
509
|
const transcriptPath = this.messageManager.getTranscriptPath();
|
|
@@ -574,68 +552,6 @@ export class Agent {
|
|
|
574
552
|
});
|
|
575
553
|
await this.messageManager.saveSession();
|
|
576
554
|
}
|
|
577
|
-
/**
|
|
578
|
-
* Set an autonomous goal for the session
|
|
579
|
-
* @param condition - The goal condition to achieve
|
|
580
|
-
*/
|
|
581
|
-
async setGoal(condition) {
|
|
582
|
-
// Check plan mode
|
|
583
|
-
if (this.getPermissionMode() === "plan") {
|
|
584
|
-
this.messageManager.addUserMessage({
|
|
585
|
-
content: "<system-reminder>Cannot set a goal in plan mode. Exit plan mode first.</system-reminder>",
|
|
586
|
-
isMeta: true,
|
|
587
|
-
});
|
|
588
|
-
return;
|
|
589
|
-
}
|
|
590
|
-
this.goalManager.setGoal(condition);
|
|
591
|
-
this.messageManager.addUserMessage({
|
|
592
|
-
content: `<system-reminder>Goal set: ${condition}. The agent will work autonomously until this goal is achieved.</system-reminder>`,
|
|
593
|
-
isMeta: true,
|
|
594
|
-
});
|
|
595
|
-
// Add the goal as a user directive to start working
|
|
596
|
-
this.messageManager.addUserMessage({
|
|
597
|
-
content: condition,
|
|
598
|
-
});
|
|
599
|
-
this.aiManager.sendAIMessage();
|
|
600
|
-
await this.messageManager.saveSession();
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* Clear the current autonomous goal
|
|
604
|
-
*/
|
|
605
|
-
async clearGoal() {
|
|
606
|
-
if (this.goalManager.isGoalActive()) {
|
|
607
|
-
this.goalManager.clearGoal();
|
|
608
|
-
this.messageManager.addUserMessage({
|
|
609
|
-
content: "<system-reminder>Goal cleared.</system-reminder>",
|
|
610
|
-
isMeta: true,
|
|
611
|
-
});
|
|
612
|
-
}
|
|
613
|
-
else {
|
|
614
|
-
this.messageManager.addUserMessage({
|
|
615
|
-
content: "<system-reminder>No active goal to clear.</system-reminder>",
|
|
616
|
-
isMeta: true,
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
await this.messageManager.saveSession();
|
|
620
|
-
}
|
|
621
|
-
/**
|
|
622
|
-
* Show the current goal status
|
|
623
|
-
*/
|
|
624
|
-
async showGoalStatus() {
|
|
625
|
-
if (this.goalManager.isGoalActive()) {
|
|
626
|
-
this.messageManager.addUserMessage({
|
|
627
|
-
content: `<system-reminder>${this.goalManager.getStatusString()}</system-reminder>`,
|
|
628
|
-
isMeta: true,
|
|
629
|
-
});
|
|
630
|
-
}
|
|
631
|
-
else {
|
|
632
|
-
this.messageManager.addUserMessage({
|
|
633
|
-
content: "<system-reminder>No active goal. Use /goal <condition> to set one.</system-reminder>",
|
|
634
|
-
isMeta: true,
|
|
635
|
-
});
|
|
636
|
-
}
|
|
637
|
-
await this.messageManager.saveSession();
|
|
638
|
-
}
|
|
639
555
|
/** Unified interrupt method, interrupts both AI messages and command execution */
|
|
640
556
|
abortMessage() {
|
|
641
557
|
// Guard: prevent tryDispatch (triggered by abortAIMessage → setIsLoading(false))
|
|
@@ -757,6 +673,17 @@ export class Agent {
|
|
|
757
673
|
this.subagentManager.cleanup();
|
|
758
674
|
// Cleanup forked agent manager
|
|
759
675
|
await this.forkedAgentManager.cleanup();
|
|
676
|
+
// Drain an in-flight auto-memory extraction fork so the process doesn't
|
|
677
|
+
// exit mid-extraction
|
|
678
|
+
try {
|
|
679
|
+
const autoMemoryService = this.container.get("AutoMemoryService");
|
|
680
|
+
if (autoMemoryService) {
|
|
681
|
+
await autoMemoryService.drain();
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
catch (error) {
|
|
685
|
+
this.logger?.warn(`Auto-memory extraction drain failed: ${error.message}`);
|
|
686
|
+
}
|
|
760
687
|
// Cleanup skill manager
|
|
761
688
|
await this.skillManager.destroy();
|
|
762
689
|
// Cleanup live configuration reload
|
|
@@ -777,21 +704,20 @@ export class Agent {
|
|
|
777
704
|
this.messageManager.triggerShowRewind();
|
|
778
705
|
}
|
|
779
706
|
/**
|
|
780
|
-
* Ask a side question without
|
|
707
|
+
* Ask a side question without interrupting the main agent.
|
|
708
|
+
*
|
|
709
|
+
* Runs a single-turn fork of the conversation that reuses the main loop's
|
|
710
|
+
* system prompt, tools, and memory injection (prompt-cache friendly) and
|
|
711
|
+
* never executes tools. The abort signal lets the UI cancel a pending
|
|
712
|
+
* question (loading dismiss); aborts propagate as thrown errors.
|
|
713
|
+
*
|
|
781
714
|
* @param question - The side question to ask
|
|
715
|
+
* @param abortSignal - Optional signal to abort the pending request
|
|
782
716
|
* @returns Promise that resolves to the AI's answer
|
|
783
717
|
*/
|
|
784
|
-
async askBtw(question) {
|
|
785
|
-
const
|
|
786
|
-
|
|
787
|
-
});
|
|
788
|
-
const result = await btw({
|
|
789
|
-
gatewayConfig: this.getGatewayConfig(),
|
|
790
|
-
modelConfig: this.getModelConfig(),
|
|
791
|
-
messages,
|
|
792
|
-
question,
|
|
793
|
-
});
|
|
794
|
-
return result.content;
|
|
718
|
+
async askBtw(question, abortSignal, onContent, onReasoning) {
|
|
719
|
+
const result = await this.aiManager.runBtwFork(question, abortSignal, onContent, onReasoning);
|
|
720
|
+
return result.content ?? result.error ?? "No response received";
|
|
795
721
|
}
|
|
796
722
|
/**
|
|
797
723
|
* Send a message to the AI agent with optional images
|
|
@@ -821,7 +747,7 @@ export class Agent {
|
|
|
821
747
|
*/
|
|
822
748
|
async sendMessage(content, images) {
|
|
823
749
|
// If the agent is busy, enqueue the message — unless it's an immediate
|
|
824
|
-
// slash command (e.g., /
|
|
750
|
+
// slash command (e.g., /clear, /compact) that should execute
|
|
825
751
|
// right away even while AI is processing
|
|
826
752
|
if (this.aiManager.isLoading || this.isCommandRunning) {
|
|
827
753
|
const trimmed = content.trim();
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
-
import type { GatewayConfig, ModelConfig, Usage } from "../types/index.js";
|
|
1
|
+
import type { GatewayConfig, ModelConfig, Usage, Message } from "../types/index.js";
|
|
2
2
|
import { Container } from "../utils/container.js";
|
|
3
3
|
import type { WorktreeSession } from "../utils/worktreeSession.js";
|
|
4
|
+
/** Result of a fork-path agent loop (compaction or auto-memory extraction). */
|
|
5
|
+
interface ForkLoopResult {
|
|
6
|
+
content?: string;
|
|
7
|
+
usage?: {
|
|
8
|
+
prompt_tokens: number;
|
|
9
|
+
completion_tokens: number;
|
|
10
|
+
total_tokens: number;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
4
13
|
export interface AIManagerCallbacks {
|
|
5
14
|
onCompactionStateChange?: (isCompacting: boolean) => void;
|
|
6
15
|
onUsageAdded?: (usage: Usage) => void;
|
|
@@ -119,15 +128,60 @@ export declare class AIManager {
|
|
|
119
128
|
private buildMainSystemPrompt;
|
|
120
129
|
private resolveFilteredTools;
|
|
121
130
|
/**
|
|
122
|
-
* Fork-path
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
* another turn. Returns undefined content when the model never
|
|
128
|
-
* text; the caller treats that as a
|
|
131
|
+
* Fork-path loop: run a bounded agent loop over a copy of the conversation
|
|
132
|
+
* using the same system prompt, tools, model, and generation params as the
|
|
133
|
+
* main loop, so the forked request prefix matches exactly and the prompt
|
|
134
|
+
* cache is reused. A `canUseTool` gate decides whether each tool call
|
|
135
|
+
* executes locally (with a stripped context) or is denied and fed back to
|
|
136
|
+
* the model for another turn. Returns undefined content when the model never
|
|
137
|
+
* produces text; the caller treats that as a failure.
|
|
138
|
+
*/
|
|
139
|
+
private runForkLoop;
|
|
140
|
+
/**
|
|
141
|
+
* Fork-path compaction: deny all tool calls locally (the model is told to
|
|
142
|
+
* summarize, not act) and feed the rejections back for another turn.
|
|
129
143
|
*/
|
|
130
144
|
private runCompactFork;
|
|
145
|
+
/**
|
|
146
|
+
* Auto-memory extraction via the perfect fork: the extraction prompt is run
|
|
147
|
+
* against the same request prefix as the main conversation (same system
|
|
148
|
+
* prompt, tools, model, and message history) so the prompt cache is reused.
|
|
149
|
+
* Gate-approved tools execute locally in a stripped context; everything else
|
|
150
|
+
* is denied. Usage is reported with operation_type "agent" so extraction
|
|
151
|
+
* token costs stay visible in session accounting.
|
|
152
|
+
*/
|
|
153
|
+
runAutoMemoryFork(messages: Message[], prompt: string, options: {
|
|
154
|
+
canUseTool: (name: string, args: Record<string, unknown>) => boolean;
|
|
155
|
+
deniedToolMessage?: string;
|
|
156
|
+
maxTurns?: number;
|
|
157
|
+
}, abortSignal?: AbortSignal): Promise<ForkLoopResult>;
|
|
158
|
+
/**
|
|
159
|
+
* Parse a fork tool call's JSON arguments, recovering truncated JSON the
|
|
160
|
+
* same way the main loop does. Unparseable arguments fall back to `{}` and
|
|
161
|
+
* are rejected by the gate or the tool's own parameter validation.
|
|
162
|
+
*/
|
|
163
|
+
private parseForkToolArgs;
|
|
164
|
+
/**
|
|
165
|
+
* Execute a single tool call inside a fork with a stripped context: no
|
|
166
|
+
* permission manager (never prompts the user), no message manager (no
|
|
167
|
+
* conditional-rule triggering), no messageId (no file-history snapshots),
|
|
168
|
+
* and no background task manager (commands run in the foreground). Only
|
|
169
|
+
* gate-approved tool names reach this path.
|
|
170
|
+
*/
|
|
171
|
+
private executeForkTool;
|
|
172
|
+
/**
|
|
173
|
+
* Fork-path side question ("/btw"): run a single-turn fork of the
|
|
174
|
+
* conversation using the same system prompt, tools, model, and generation
|
|
175
|
+
* params as the main loop, so the forked request prefix matches exactly and
|
|
176
|
+
* the prompt cache is reused. The in-progress assistant message (if any) is
|
|
177
|
+
* stripped so the fork starts from the last completed request prefix. Tools
|
|
178
|
+
* are never executed — the wrapped question instructs the model to answer
|
|
179
|
+
* directly; an attempted tool call is surfaced as an error string.
|
|
180
|
+
*/
|
|
181
|
+
runBtwFork(question: string, abortSignal?: AbortSignal, onContent?: (content: string) => void, onReasoning?: (content: string) => void): Promise<{
|
|
182
|
+
content?: string;
|
|
183
|
+
error?: string;
|
|
184
|
+
}>;
|
|
131
185
|
/**
|
|
132
186
|
* Build post-compact context restoration content.
|
|
133
187
|
* Restores file reads, working directory, plan mode, skills, and background tasks.
|
|
@@ -166,3 +220,4 @@ export declare class AIManager {
|
|
|
166
220
|
*/
|
|
167
221
|
private executePostToolUseHooks;
|
|
168
222
|
}
|
|
223
|
+
export {};
|