wave-agent-sdk 0.0.6 → 0.0.8
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 +32 -20
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +209 -24
- package/dist/constants/events.d.ts +28 -0
- package/dist/constants/events.d.ts.map +1 -0
- package/dist/constants/events.js +27 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/managers/aiManager.d.ts +34 -1
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +248 -132
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +7 -6
- package/dist/managers/hookManager.d.ts +13 -16
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +81 -44
- package/dist/managers/liveConfigManager.d.ts +58 -0
- package/dist/managers/liveConfigManager.d.ts.map +1 -0
- package/dist/managers/liveConfigManager.js +160 -0
- package/dist/managers/messageManager.d.ts +41 -24
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +168 -49
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +9 -3
- package/dist/managers/subagentManager.d.ts +51 -0
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +190 -19
- package/dist/services/aiService.d.ts +13 -5
- package/dist/services/aiService.d.ts.map +1 -1
- package/dist/services/aiService.js +350 -74
- package/dist/services/configurationWatcher.d.ts +120 -0
- package/dist/services/configurationWatcher.d.ts.map +1 -0
- package/dist/services/configurationWatcher.js +439 -0
- package/dist/services/fileWatcher.d.ts +69 -0
- package/dist/services/fileWatcher.d.ts.map +1 -0
- package/dist/services/fileWatcher.js +213 -0
- package/dist/services/hook.d.ts +91 -9
- package/dist/services/hook.d.ts.map +1 -1
- package/dist/services/hook.js +393 -43
- package/dist/services/jsonlHandler.d.ts +62 -0
- package/dist/services/jsonlHandler.d.ts.map +1 -0
- package/dist/services/jsonlHandler.js +257 -0
- package/dist/services/memory.d.ts +9 -0
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +81 -12
- package/dist/services/memoryStore.d.ts +81 -0
- package/dist/services/memoryStore.d.ts.map +1 -0
- package/dist/services/memoryStore.js +200 -0
- package/dist/services/session.d.ts +64 -49
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +310 -132
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +5 -4
- package/dist/tools/deleteFileTool.d.ts.map +1 -1
- package/dist/tools/deleteFileTool.js +2 -1
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +3 -2
- package/dist/tools/multiEditTool.d.ts.map +1 -1
- package/dist/tools/multiEditTool.js +4 -3
- package/dist/tools/readTool.d.ts.map +1 -1
- package/dist/tools/readTool.js +2 -1
- package/dist/tools/todoWriteTool.d.ts.map +1 -1
- package/dist/tools/todoWriteTool.js +3 -10
- package/dist/tools/writeTool.d.ts.map +1 -1
- package/dist/tools/writeTool.js +5 -6
- package/dist/types/commands.d.ts +4 -0
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/core.d.ts +35 -0
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/environment.d.ts +42 -0
- package/dist/types/environment.d.ts.map +1 -0
- package/dist/types/environment.js +21 -0
- package/dist/types/hooks.d.ts +8 -2
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +8 -2
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +2 -0
- package/dist/types/memoryStore.d.ts +82 -0
- package/dist/types/memoryStore.d.ts.map +1 -0
- package/dist/types/memoryStore.js +7 -0
- package/dist/types/messaging.d.ts +21 -9
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/messaging.js +5 -1
- package/dist/types/session.d.ts +20 -0
- package/dist/types/session.d.ts.map +1 -0
- package/dist/types/session.js +7 -0
- package/dist/utils/bashHistory.d.ts.map +1 -1
- package/dist/utils/bashHistory.js +27 -26
- package/dist/utils/cacheControlUtils.d.ts +121 -0
- package/dist/utils/cacheControlUtils.d.ts.map +1 -0
- package/dist/utils/cacheControlUtils.js +367 -0
- package/dist/utils/commandPathResolver.d.ts +52 -0
- package/dist/utils/commandPathResolver.d.ts.map +1 -0
- package/dist/utils/commandPathResolver.js +145 -0
- package/dist/utils/configPaths.d.ts +85 -0
- package/dist/utils/configPaths.d.ts.map +1 -0
- package/dist/utils/configPaths.js +121 -0
- package/dist/utils/configResolver.d.ts +37 -10
- package/dist/utils/configResolver.d.ts.map +1 -1
- package/dist/utils/configResolver.js +127 -23
- package/dist/utils/constants.d.ts +1 -1
- package/dist/utils/constants.js +1 -1
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
- package/dist/utils/convertMessagesForAPI.js +8 -13
- package/dist/utils/customCommands.d.ts.map +1 -1
- package/dist/utils/customCommands.js +66 -21
- package/dist/utils/fileUtils.d.ts +15 -0
- package/dist/utils/fileUtils.d.ts.map +1 -0
- package/dist/utils/fileUtils.js +61 -0
- package/dist/utils/globalLogger.d.ts +102 -0
- package/dist/utils/globalLogger.d.ts.map +1 -0
- package/dist/utils/globalLogger.js +136 -0
- package/dist/utils/hookMatcher.d.ts +1 -6
- package/dist/utils/hookMatcher.d.ts.map +1 -1
- package/dist/utils/mcpUtils.d.ts.map +1 -1
- package/dist/utils/mcpUtils.js +25 -3
- package/dist/utils/messageOperations.d.ts +27 -27
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +46 -36
- package/dist/utils/pathEncoder.d.ts +104 -0
- package/dist/utils/pathEncoder.d.ts.map +1 -0
- package/dist/utils/pathEncoder.js +272 -0
- package/dist/utils/subagentParser.d.ts.map +1 -1
- package/dist/utils/subagentParser.js +2 -1
- package/dist/utils/tokenCalculation.d.ts +26 -0
- package/dist/utils/tokenCalculation.d.ts.map +1 -0
- package/dist/utils/tokenCalculation.js +36 -0
- package/package.json +6 -3
- package/src/agent.ts +301 -37
- package/src/constants/events.ts +38 -0
- package/src/index.ts +2 -0
- package/src/managers/aiManager.ts +325 -173
- package/src/managers/backgroundBashManager.ts +7 -6
- package/src/managers/hookManager.ts +106 -84
- package/src/managers/liveConfigManager.ts +248 -0
- package/src/managers/messageManager.ts +237 -100
- package/src/managers/slashCommandManager.ts +9 -7
- package/src/managers/subagentManager.ts +284 -22
- package/src/services/aiService.ts +474 -83
- package/src/services/configurationWatcher.ts +622 -0
- package/src/services/fileWatcher.ts +301 -0
- package/src/services/hook.ts +538 -47
- package/src/services/jsonlHandler.ts +319 -0
- package/src/services/memory.ts +92 -12
- package/src/services/memoryStore.ts +279 -0
- package/src/services/session.ts +381 -157
- package/src/tools/bashTool.ts +5 -4
- package/src/tools/deleteFileTool.ts +2 -1
- package/src/tools/editTool.ts +3 -2
- package/src/tools/multiEditTool.ts +4 -3
- package/src/tools/readTool.ts +2 -1
- package/src/tools/todoWriteTool.ts +3 -11
- package/src/tools/writeTool.ts +7 -6
- package/src/types/commands.ts +6 -0
- package/src/types/core.ts +44 -0
- package/src/types/environment.ts +60 -0
- package/src/types/hooks.ts +21 -8
- package/src/types/index.ts +2 -0
- package/src/types/memoryStore.ts +94 -0
- package/src/types/messaging.ts +21 -10
- package/src/types/session.ts +25 -0
- package/src/utils/bashHistory.ts +27 -27
- package/src/utils/cacheControlUtils.ts +540 -0
- package/src/utils/commandPathResolver.ts +189 -0
- package/src/utils/configPaths.ts +163 -0
- package/src/utils/configResolver.ts +182 -22
- package/src/utils/constants.ts +1 -1
- package/src/utils/convertMessagesForAPI.ts +8 -14
- package/src/utils/customCommands.ts +90 -22
- package/src/utils/fileUtils.ts +65 -0
- package/src/utils/globalLogger.ts +145 -0
- package/src/utils/hookMatcher.ts +1 -12
- package/src/utils/mcpUtils.ts +34 -3
- package/src/utils/messageOperations.ts +77 -60
- package/src/utils/pathEncoder.ts +379 -0
- package/src/utils/subagentParser.ts +2 -1
- package/src/utils/tokenCalculation.ts +43 -0
- package/src/types/index.ts.backup +0 -357
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { randomUUID } from "crypto";
|
|
2
1
|
import {
|
|
3
2
|
addAssistantMessageToMessages,
|
|
4
3
|
updateToolBlockInMessage,
|
|
@@ -13,20 +12,26 @@ import {
|
|
|
13
12
|
addSubagentBlockToMessage,
|
|
14
13
|
updateSubagentBlockInMessage,
|
|
15
14
|
removeLastUserMessage,
|
|
15
|
+
UserMessageParams,
|
|
16
16
|
type AddSubagentBlockParams,
|
|
17
17
|
type UpdateSubagentBlockParams,
|
|
18
18
|
type AgentToolBlockUpdateParams,
|
|
19
19
|
} from "../utils/messageOperations.js";
|
|
20
|
+
import type { SubagentConfiguration } from "../utils/subagentParser.js";
|
|
20
21
|
import type { Logger, Message, Usage } from "../types/index.js";
|
|
22
|
+
import { join } from "path";
|
|
21
23
|
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
cleanupExpiredSessionsFromJsonl,
|
|
25
|
+
getLatestSessionFromJsonl,
|
|
26
|
+
loadSessionFromJsonl,
|
|
27
|
+
appendMessages,
|
|
28
|
+
createSession,
|
|
29
|
+
generateSessionId,
|
|
26
30
|
SessionData,
|
|
27
|
-
|
|
31
|
+
SESSION_DIR,
|
|
28
32
|
} from "../services/session.js";
|
|
29
33
|
import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
34
|
+
import { pathEncoder } from "../utils/pathEncoder.js";
|
|
30
35
|
|
|
31
36
|
export interface MessageManagerCallbacks {
|
|
32
37
|
onMessagesChange?: (messages: Message[]) => void;
|
|
@@ -35,14 +40,11 @@ export interface MessageManagerCallbacks {
|
|
|
35
40
|
onUserInputHistoryChange?: (history: string[]) => void;
|
|
36
41
|
onUsagesChange?: (usages: Usage[]) => void;
|
|
37
42
|
// Incremental callback
|
|
38
|
-
onUserMessageAdded?: (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
content?: string,
|
|
44
|
-
toolCalls?: ChatCompletionMessageFunctionToolCall[],
|
|
45
|
-
) => void;
|
|
43
|
+
onUserMessageAdded?: (params: UserMessageParams) => void;
|
|
44
|
+
// MODIFIED: Remove arguments for separation of concerns
|
|
45
|
+
onAssistantMessageAdded?: () => void;
|
|
46
|
+
// NEW: Streaming content callback - FR-001: receives chunk and accumulated content
|
|
47
|
+
onAssistantContentUpdated?: (chunk: string, accumulated: string) => void;
|
|
46
48
|
onToolBlockUpdated?: (params: AgentToolBlockUpdateParams) => void;
|
|
47
49
|
onDiffBlockAdded?: (filePath: string, diffResult: string) => void;
|
|
48
50
|
onErrorBlockAdded?: (error: string) => void;
|
|
@@ -54,12 +56,6 @@ export interface MessageManagerCallbacks {
|
|
|
54
56
|
type: "project" | "user",
|
|
55
57
|
storagePath: string,
|
|
56
58
|
) => void;
|
|
57
|
-
// Custom command callback
|
|
58
|
-
onCustomCommandAdded?: (
|
|
59
|
-
commandName: string,
|
|
60
|
-
content: string,
|
|
61
|
-
originalInput?: string,
|
|
62
|
-
) => void;
|
|
63
59
|
// Bash command callback
|
|
64
60
|
onAddCommandOutputMessage?: (command: string) => void;
|
|
65
61
|
onUpdateCommandOutputMessage?: (command: string, output: string) => void;
|
|
@@ -75,7 +71,6 @@ export interface MessageManagerCallbacks {
|
|
|
75
71
|
) => void;
|
|
76
72
|
onSubAgentBlockUpdated?: (
|
|
77
73
|
subagentId: string,
|
|
78
|
-
messages: Message[],
|
|
79
74
|
status: "active" | "completed" | "error" | "aborted",
|
|
80
75
|
) => void;
|
|
81
76
|
}
|
|
@@ -84,13 +79,9 @@ export interface MessageManagerOptions {
|
|
|
84
79
|
callbacks: MessageManagerCallbacks;
|
|
85
80
|
workdir: string;
|
|
86
81
|
logger?: Logger;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
* Custom session directory path
|
|
91
|
-
* @default join(homedir(), ".wave", "sessions")
|
|
92
|
-
*/
|
|
93
|
-
sessionDir?: string;
|
|
82
|
+
sessionType?: "main" | "subagent";
|
|
83
|
+
parentSessionId?: string;
|
|
84
|
+
subagentType?: string;
|
|
94
85
|
}
|
|
95
86
|
|
|
96
87
|
export class MessageManager {
|
|
@@ -101,20 +92,32 @@ export class MessageManager {
|
|
|
101
92
|
private userInputHistory: string[];
|
|
102
93
|
private sessionStartTime: string;
|
|
103
94
|
private workdir: string;
|
|
95
|
+
private encodedWorkdir: string; // Cached encoded workdir
|
|
104
96
|
private logger?: Logger; // Add optional logger property
|
|
105
97
|
private callbacks: MessageManagerCallbacks;
|
|
106
|
-
private
|
|
98
|
+
private transcriptPath: string; // Cached transcript path
|
|
99
|
+
private savedMessageCount: number; // Track how many messages have been saved to prevent duplication
|
|
100
|
+
private sessionType: "main" | "subagent";
|
|
101
|
+
private parentSessionId?: string;
|
|
102
|
+
private subagentType?: string;
|
|
107
103
|
|
|
108
104
|
constructor(options: MessageManagerOptions) {
|
|
109
|
-
this.sessionId =
|
|
105
|
+
this.sessionId = generateSessionId();
|
|
110
106
|
this.messages = [];
|
|
111
107
|
this.latestTotalTokens = 0;
|
|
112
108
|
this.userInputHistory = [];
|
|
113
109
|
this.sessionStartTime = new Date().toISOString();
|
|
114
110
|
this.workdir = options.workdir;
|
|
111
|
+
this.encodedWorkdir = pathEncoder.encodeSync(this.workdir); // Cache encoded workdir
|
|
115
112
|
this.callbacks = options.callbacks;
|
|
116
113
|
this.logger = options.logger;
|
|
117
|
-
this.
|
|
114
|
+
this.savedMessageCount = 0; // Initialize saved message count tracker
|
|
115
|
+
this.sessionType = options.sessionType || "main";
|
|
116
|
+
this.parentSessionId = options.parentSessionId;
|
|
117
|
+
this.subagentType = options.subagentType;
|
|
118
|
+
|
|
119
|
+
// Compute and cache the transcript path
|
|
120
|
+
this.transcriptPath = this.computeTranscriptPath();
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
// Getter methods
|
|
@@ -134,18 +137,63 @@ export class MessageManager {
|
|
|
134
137
|
return [...this.userInputHistory];
|
|
135
138
|
}
|
|
136
139
|
|
|
140
|
+
public getSessionStartTime(): string {
|
|
141
|
+
return this.sessionStartTime;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public getWorkdir(): string {
|
|
145
|
+
return this.workdir;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public getSessionDir(): string {
|
|
149
|
+
return SESSION_DIR;
|
|
150
|
+
}
|
|
151
|
+
|
|
137
152
|
public getTranscriptPath(): string {
|
|
138
|
-
return
|
|
153
|
+
return this.transcriptPath;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Compute the transcript path using cached encoded workdir
|
|
158
|
+
* Called during construction and when sessionId changes
|
|
159
|
+
*/
|
|
160
|
+
private computeTranscriptPath(): string {
|
|
161
|
+
const baseDir = join(SESSION_DIR, this.encodedWorkdir);
|
|
162
|
+
|
|
163
|
+
// All sessions now go in the same directory
|
|
164
|
+
// Session type is determined by metadata, not file path
|
|
165
|
+
return join(baseDir, `${this.sessionId}.jsonl`);
|
|
139
166
|
}
|
|
140
167
|
|
|
141
168
|
// Setter methods, will trigger callbacks
|
|
142
169
|
public setSessionId(sessionId: string): void {
|
|
143
170
|
if (this.sessionId !== sessionId) {
|
|
144
171
|
this.sessionId = sessionId;
|
|
172
|
+
// Reset saved message count for new session
|
|
173
|
+
this.savedMessageCount = 0;
|
|
174
|
+
// Recompute transcript path since session ID changed
|
|
175
|
+
this.transcriptPath = this.computeTranscriptPath();
|
|
145
176
|
this.callbacks.onSessionIdChange?.(sessionId);
|
|
146
177
|
}
|
|
147
178
|
}
|
|
148
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Create session if needed (async helper)
|
|
182
|
+
*/
|
|
183
|
+
private async createSessionIfNeeded(): Promise<void> {
|
|
184
|
+
try {
|
|
185
|
+
await createSession(
|
|
186
|
+
this.sessionId,
|
|
187
|
+
this.workdir,
|
|
188
|
+
this.sessionType,
|
|
189
|
+
this.parentSessionId,
|
|
190
|
+
this.subagentType,
|
|
191
|
+
);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
this.logger?.error("Failed to create session:", error);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
149
197
|
public setMessages(messages: Message[]): void {
|
|
150
198
|
this.messages = [...messages];
|
|
151
199
|
this.callbacks.onMessagesChange?.([...messages]);
|
|
@@ -156,14 +204,29 @@ export class MessageManager {
|
|
|
156
204
|
*/
|
|
157
205
|
public async saveSession(): Promise<void> {
|
|
158
206
|
try {
|
|
159
|
-
|
|
207
|
+
// Only save messages that haven't been saved yet
|
|
208
|
+
const unsavedMessages = this.messages.slice(this.savedMessageCount);
|
|
209
|
+
|
|
210
|
+
if (unsavedMessages.length === 0) {
|
|
211
|
+
// No new messages to save
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Create session if needed (only when we have messages to save)
|
|
216
|
+
if (this.savedMessageCount === 0) {
|
|
217
|
+
// This is the first time saving messages, so create the session
|
|
218
|
+
await this.createSessionIfNeeded();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Use JSONL format for new sessions
|
|
222
|
+
await appendMessages(
|
|
160
223
|
this.sessionId,
|
|
161
|
-
|
|
224
|
+
unsavedMessages, // Only append new messages
|
|
162
225
|
this.workdir,
|
|
163
|
-
this.latestTotalTokens,
|
|
164
|
-
this.sessionStartTime,
|
|
165
|
-
this.sessionDir,
|
|
166
226
|
);
|
|
227
|
+
|
|
228
|
+
// Update the saved message count
|
|
229
|
+
this.savedMessageCount = this.messages.length;
|
|
167
230
|
} catch (error) {
|
|
168
231
|
this.logger?.error("Failed to save session:", error);
|
|
169
232
|
}
|
|
@@ -177,11 +240,9 @@ export class MessageManager {
|
|
|
177
240
|
continueLastSession?: boolean,
|
|
178
241
|
): Promise<void> {
|
|
179
242
|
// Clean up expired sessions first
|
|
180
|
-
|
|
181
|
-
await cleanupExpiredSessions(this.workdir, this.sessionDir);
|
|
182
|
-
} catch (error) {
|
|
243
|
+
cleanupExpiredSessionsFromJsonl(this.workdir).catch((error) => {
|
|
183
244
|
this.logger?.warn("Failed to cleanup expired sessions:", error);
|
|
184
|
-
}
|
|
245
|
+
});
|
|
185
246
|
|
|
186
247
|
if (!restoreSessionId && !continueLastSession) {
|
|
187
248
|
return;
|
|
@@ -191,16 +252,18 @@ export class MessageManager {
|
|
|
191
252
|
let sessionToRestore: SessionData | null = null;
|
|
192
253
|
|
|
193
254
|
if (restoreSessionId) {
|
|
194
|
-
|
|
255
|
+
// Use only JSONL format - no legacy support
|
|
256
|
+
sessionToRestore = await loadSessionFromJsonl(
|
|
257
|
+
restoreSessionId,
|
|
258
|
+
this.workdir,
|
|
259
|
+
);
|
|
195
260
|
if (!sessionToRestore) {
|
|
196
261
|
console.error(`Session not found: ${restoreSessionId}`);
|
|
197
262
|
process.exit(1);
|
|
198
263
|
}
|
|
199
264
|
} else if (continueLastSession) {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
this.sessionDir,
|
|
203
|
-
);
|
|
265
|
+
// Use only JSONL format - no legacy support
|
|
266
|
+
sessionToRestore = await getLatestSessionFromJsonl(this.workdir);
|
|
204
267
|
if (!sessionToRestore) {
|
|
205
268
|
console.error(
|
|
206
269
|
`No previous session found for workdir: ${this.workdir}`,
|
|
@@ -213,11 +276,7 @@ export class MessageManager {
|
|
|
213
276
|
console.log(`Restoring session: ${sessionToRestore.id}`);
|
|
214
277
|
|
|
215
278
|
// Initialize from session data
|
|
216
|
-
this.initializeFromSession(
|
|
217
|
-
sessionToRestore.id,
|
|
218
|
-
sessionToRestore.messages,
|
|
219
|
-
sessionToRestore.metadata.latestTotalTokens,
|
|
220
|
-
);
|
|
279
|
+
this.initializeFromSession(sessionToRestore);
|
|
221
280
|
}
|
|
222
281
|
} catch (error) {
|
|
223
282
|
console.error("Failed to restore session:", error);
|
|
@@ -243,23 +302,27 @@ export class MessageManager {
|
|
|
243
302
|
public clearMessages(): void {
|
|
244
303
|
this.setMessages([]);
|
|
245
304
|
this.setUserInputHistory([]);
|
|
246
|
-
this.setSessionId(
|
|
305
|
+
this.setSessionId(generateSessionId());
|
|
247
306
|
this.setlatestTotalTokens(0);
|
|
248
307
|
this.sessionStartTime = new Date().toISOString();
|
|
308
|
+
this.savedMessageCount = 0; // Reset saved message count
|
|
249
309
|
}
|
|
250
310
|
|
|
251
311
|
// Initialize state from session data
|
|
252
|
-
public initializeFromSession(
|
|
253
|
-
|
|
254
|
-
messages
|
|
255
|
-
latestTotalTokens
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
this.
|
|
259
|
-
this.setlatestTotalTokens(latestTotalTokens);
|
|
312
|
+
public initializeFromSession(sessionData: SessionData): void {
|
|
313
|
+
this.setSessionId(sessionData.id);
|
|
314
|
+
this.setMessages([...sessionData.messages]);
|
|
315
|
+
this.setlatestTotalTokens(sessionData.metadata.latestTotalTokens);
|
|
316
|
+
|
|
317
|
+
// Restore the original session start time
|
|
318
|
+
this.sessionStartTime = sessionData.metadata.startedAt;
|
|
260
319
|
|
|
261
320
|
// Extract user input history from session messages
|
|
262
|
-
this.setUserInputHistory(extractUserInputHistory(messages));
|
|
321
|
+
this.setUserInputHistory(extractUserInputHistory(sessionData.messages));
|
|
322
|
+
|
|
323
|
+
// Set saved message count to the number of loaded messages since they're already saved
|
|
324
|
+
// This must be done after setSessionId which resets it to 0
|
|
325
|
+
this.savedMessageCount = sessionData.messages.length;
|
|
263
326
|
}
|
|
264
327
|
|
|
265
328
|
// Add to input history
|
|
@@ -281,68 +344,92 @@ export class MessageManager {
|
|
|
281
344
|
}
|
|
282
345
|
|
|
283
346
|
// Encapsulated message operation functions
|
|
284
|
-
public addUserMessage(
|
|
285
|
-
content: string,
|
|
286
|
-
images?: Array<{ path: string; mimeType: string }>,
|
|
287
|
-
): void {
|
|
347
|
+
public addUserMessage(params: UserMessageParams): void {
|
|
288
348
|
const newMessages = addUserMessageToMessages({
|
|
289
349
|
messages: this.messages,
|
|
290
|
-
|
|
291
|
-
images,
|
|
350
|
+
...params,
|
|
292
351
|
});
|
|
293
352
|
this.setMessages(newMessages);
|
|
294
|
-
this.callbacks.onUserMessageAdded?.(
|
|
295
|
-
}
|
|
353
|
+
this.callbacks.onUserMessageAdded?.(params);
|
|
296
354
|
|
|
297
|
-
|
|
298
|
-
commandName: string,
|
|
299
|
-
content: string,
|
|
300
|
-
originalInput?: string,
|
|
301
|
-
): void {
|
|
302
|
-
const newMessages = addUserMessageToMessages({
|
|
303
|
-
messages: this.messages,
|
|
304
|
-
content: "", // Empty content, as we will use CustomCommandBlock
|
|
305
|
-
customCommandBlock: {
|
|
306
|
-
type: "custom_command",
|
|
307
|
-
commandName,
|
|
308
|
-
content,
|
|
309
|
-
originalInput,
|
|
310
|
-
},
|
|
311
|
-
});
|
|
312
|
-
this.setMessages(newMessages);
|
|
313
|
-
this.callbacks.onCustomCommandAdded?.(commandName, content, originalInput);
|
|
355
|
+
// Note: Subagent-specific callbacks are now handled by SubagentManager
|
|
314
356
|
}
|
|
315
357
|
|
|
316
358
|
public addAssistantMessage(
|
|
317
359
|
content?: string,
|
|
318
360
|
toolCalls?: ChatCompletionMessageFunctionToolCall[],
|
|
319
361
|
usage?: Usage,
|
|
362
|
+
metadata?: Record<string, unknown>,
|
|
320
363
|
): void {
|
|
364
|
+
const metadataRecord = metadata
|
|
365
|
+
? Object.fromEntries(
|
|
366
|
+
Object.entries(metadata).filter(([, value]) => value !== undefined),
|
|
367
|
+
)
|
|
368
|
+
: undefined;
|
|
369
|
+
|
|
321
370
|
const newMessages = addAssistantMessageToMessages(
|
|
322
371
|
this.messages,
|
|
323
372
|
content,
|
|
324
373
|
toolCalls,
|
|
325
374
|
usage,
|
|
375
|
+
metadataRecord,
|
|
326
376
|
);
|
|
327
377
|
this.setMessages(newMessages);
|
|
328
|
-
this.callbacks.onAssistantMessageAdded?.(
|
|
378
|
+
this.callbacks.onAssistantMessageAdded?.();
|
|
379
|
+
|
|
380
|
+
// Note: Subagent-specific callbacks are now handled by SubagentManager
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
public mergeAssistantMetadata(metadata: Record<string, unknown>): void {
|
|
384
|
+
if (!metadata || Object.keys(metadata).length === 0) {
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const newMessages = [...this.messages];
|
|
389
|
+
for (let i = newMessages.length - 1; i >= 0; i--) {
|
|
390
|
+
const message = newMessages[i];
|
|
391
|
+
if (message.role === "assistant") {
|
|
392
|
+
const mergedMetadata = {
|
|
393
|
+
...(message.metadata || {}),
|
|
394
|
+
} as Record<string, unknown>;
|
|
395
|
+
|
|
396
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
397
|
+
if (value === undefined) {
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
mergedMetadata[key] = value;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (Object.keys(mergedMetadata).length === 0) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
message.metadata = mergedMetadata;
|
|
408
|
+
this.setMessages(newMessages);
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
329
412
|
}
|
|
330
413
|
|
|
331
414
|
public updateToolBlock(params: AgentToolBlockUpdateParams): void {
|
|
332
415
|
const newMessages = updateToolBlockInMessage({
|
|
333
416
|
messages: this.messages,
|
|
334
|
-
id: params.
|
|
335
|
-
parameters: params.
|
|
417
|
+
id: params.id,
|
|
418
|
+
parameters: params.parameters,
|
|
336
419
|
result: params.result,
|
|
337
420
|
success: params.success,
|
|
338
421
|
error: params.error,
|
|
339
|
-
|
|
422
|
+
stage: params.stage,
|
|
340
423
|
name: params.name,
|
|
341
424
|
shortResult: params.shortResult,
|
|
425
|
+
images: params.images,
|
|
342
426
|
compactParams: params.compactParams,
|
|
427
|
+
parametersChunk: params.parametersChunk,
|
|
343
428
|
});
|
|
344
429
|
this.setMessages(newMessages);
|
|
345
430
|
this.callbacks.onToolBlockUpdated?.(params);
|
|
431
|
+
|
|
432
|
+
// Note: Subagent-specific callbacks are now handled by SubagentManager
|
|
346
433
|
}
|
|
347
434
|
|
|
348
435
|
public addDiffBlock(
|
|
@@ -373,6 +460,7 @@ export class MessageManager {
|
|
|
373
460
|
public compressMessagesAndUpdateSession(
|
|
374
461
|
insertIndex: number,
|
|
375
462
|
compressedContent: string,
|
|
463
|
+
usage?: Usage,
|
|
376
464
|
): void {
|
|
377
465
|
const currentMessages = this.messages;
|
|
378
466
|
|
|
@@ -383,8 +471,10 @@ export class MessageManager {
|
|
|
383
471
|
{
|
|
384
472
|
type: "compress",
|
|
385
473
|
content: compressedContent,
|
|
474
|
+
sessionId: this.sessionId,
|
|
386
475
|
},
|
|
387
476
|
],
|
|
477
|
+
...(usage && { usage }),
|
|
388
478
|
};
|
|
389
479
|
|
|
390
480
|
// Convert negative index to positive index
|
|
@@ -398,7 +488,7 @@ export class MessageManager {
|
|
|
398
488
|
];
|
|
399
489
|
|
|
400
490
|
// Update sessionId
|
|
401
|
-
this.setSessionId(
|
|
491
|
+
this.setSessionId(generateSessionId());
|
|
402
492
|
|
|
403
493
|
// Set new message list
|
|
404
494
|
this.setMessages(newMessages);
|
|
@@ -458,8 +548,9 @@ export class MessageManager {
|
|
|
458
548
|
public addSubagentBlock(
|
|
459
549
|
subagentId: string,
|
|
460
550
|
subagentName: string,
|
|
551
|
+
sessionId: string,
|
|
552
|
+
configuration: SubagentConfiguration,
|
|
461
553
|
status: "active" | "completed" | "error" = "active",
|
|
462
|
-
subagentMessages: Message[] = [],
|
|
463
554
|
parameters: {
|
|
464
555
|
description: string;
|
|
465
556
|
prompt: string;
|
|
@@ -470,8 +561,9 @@ export class MessageManager {
|
|
|
470
561
|
messages: this.messages,
|
|
471
562
|
subagentId,
|
|
472
563
|
subagentName,
|
|
564
|
+
sessionId,
|
|
473
565
|
status,
|
|
474
|
-
|
|
566
|
+
configuration,
|
|
475
567
|
};
|
|
476
568
|
const updatedMessages = addSubagentBlockToMessage(params);
|
|
477
569
|
this.setMessages(updatedMessages);
|
|
@@ -482,7 +574,7 @@ export class MessageManager {
|
|
|
482
574
|
subagentId: string,
|
|
483
575
|
updates: Partial<{
|
|
484
576
|
status: "active" | "completed" | "error" | "aborted";
|
|
485
|
-
|
|
577
|
+
sessionId: string;
|
|
486
578
|
}>,
|
|
487
579
|
): void {
|
|
488
580
|
const updatedMessages = updateSubagentBlockInMessage(
|
|
@@ -495,13 +587,8 @@ export class MessageManager {
|
|
|
495
587
|
messages: this.messages,
|
|
496
588
|
subagentId,
|
|
497
589
|
status: updates.status || "active",
|
|
498
|
-
subagentMessages: updates.messages || [],
|
|
499
590
|
};
|
|
500
|
-
this.callbacks.onSubAgentBlockUpdated?.(
|
|
501
|
-
params.subagentId,
|
|
502
|
-
params.messages,
|
|
503
|
-
params.status,
|
|
504
|
-
);
|
|
591
|
+
this.callbacks.onSubAgentBlockUpdated?.(params.subagentId, params.status);
|
|
505
592
|
}
|
|
506
593
|
|
|
507
594
|
/**
|
|
@@ -517,6 +604,56 @@ export class MessageManager {
|
|
|
517
604
|
this.callbacks.onUsagesChange?.(usages);
|
|
518
605
|
}
|
|
519
606
|
|
|
607
|
+
/**
|
|
608
|
+
* Update the current assistant message content during streaming
|
|
609
|
+
* This method updates the last assistant message's content without creating a new message
|
|
610
|
+
* FR-001: Tracks and provides both chunk (new content) and accumulated (total content)
|
|
611
|
+
*/
|
|
612
|
+
public updateCurrentMessageContent(newAccumulatedContent: string): void {
|
|
613
|
+
if (this.messages.length === 0) return;
|
|
614
|
+
|
|
615
|
+
const lastMessage = this.messages[this.messages.length - 1];
|
|
616
|
+
if (lastMessage.role !== "assistant") return;
|
|
617
|
+
|
|
618
|
+
// Get the current content to calculate the chunk
|
|
619
|
+
const textBlockIndex = lastMessage.blocks.findIndex(
|
|
620
|
+
(block) => block.type === "text",
|
|
621
|
+
);
|
|
622
|
+
const currentContent =
|
|
623
|
+
textBlockIndex >= 0
|
|
624
|
+
? (
|
|
625
|
+
lastMessage.blocks[textBlockIndex] as {
|
|
626
|
+
type: "text";
|
|
627
|
+
content: string;
|
|
628
|
+
}
|
|
629
|
+
).content || ""
|
|
630
|
+
: "";
|
|
631
|
+
|
|
632
|
+
// Calculate the chunk (new content since last update)
|
|
633
|
+
const chunk = newAccumulatedContent.slice(currentContent.length);
|
|
634
|
+
|
|
635
|
+
if (textBlockIndex >= 0) {
|
|
636
|
+
// Update existing text block
|
|
637
|
+
lastMessage.blocks[textBlockIndex] = {
|
|
638
|
+
type: "text",
|
|
639
|
+
content: newAccumulatedContent,
|
|
640
|
+
};
|
|
641
|
+
} else {
|
|
642
|
+
// Add new text block if none exists
|
|
643
|
+
lastMessage.blocks.unshift({
|
|
644
|
+
type: "text",
|
|
645
|
+
content: newAccumulatedContent,
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
// FR-001: Trigger callbacks with chunk and accumulated content
|
|
650
|
+
this.callbacks.onAssistantContentUpdated?.(chunk, newAccumulatedContent);
|
|
651
|
+
|
|
652
|
+
// Note: Subagent-specific callbacks are now handled by SubagentManager
|
|
653
|
+
|
|
654
|
+
this.callbacks.onMessagesChange?.([...this.messages]); // Still need to notify of changes
|
|
655
|
+
}
|
|
656
|
+
|
|
520
657
|
/**
|
|
521
658
|
* Remove the last user message from the conversation
|
|
522
659
|
* Used for hook error handling when the user prompt needs to be erased
|
|
@@ -52,9 +52,12 @@ export class SlashCommandManager {
|
|
|
52
52
|
this.registerCommand({
|
|
53
53
|
id: "clear",
|
|
54
54
|
name: "clear",
|
|
55
|
-
description: "Clear the chat session",
|
|
55
|
+
description: "Clear the chat session and terminal",
|
|
56
56
|
handler: () => {
|
|
57
|
+
// Clear chat messages
|
|
57
58
|
this.messageManager.clearMessages();
|
|
59
|
+
// Clear terminal screen
|
|
60
|
+
process.stdout.write("\x1Bc");
|
|
58
61
|
},
|
|
59
62
|
});
|
|
60
63
|
}
|
|
@@ -257,15 +260,14 @@ export class SlashCommandManager {
|
|
|
257
260
|
? replaceBashCommandsWithOutput(processedContent, bashResults)
|
|
258
261
|
: processedContent;
|
|
259
262
|
|
|
260
|
-
// Add custom command
|
|
263
|
+
// Add custom command message to show the command being executed
|
|
261
264
|
const originalInput = args
|
|
262
265
|
? `/${commandName} ${args}`
|
|
263
266
|
: `/${commandName}`;
|
|
264
|
-
this.messageManager.
|
|
265
|
-
|
|
266
|
-
finalContent,
|
|
267
|
-
|
|
268
|
-
);
|
|
267
|
+
this.messageManager.addUserMessage({
|
|
268
|
+
content: originalInput,
|
|
269
|
+
customCommandContent: finalContent,
|
|
270
|
+
});
|
|
269
271
|
|
|
270
272
|
// Execute the AI conversation with custom configuration
|
|
271
273
|
await this.aiManager.sendAIMessage({
|