wave-agent-sdk 0.19.9 → 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/builtin/plugins/sdd/scripts/session-start.js +1 -1
- package/builtin/plugins/sdd/skills/specify/SKILL.md +3 -4
- package/builtin/skills/settings/ENV.md +15 -9
- package/builtin/skills/settings/HOOKS.md +27 -2
- package/dist/agent.d.ts +9 -20
- package/dist/agent.js +28 -99
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/managers/aiManager.d.ts +71 -8
- package/dist/managers/aiManager.js +290 -85
- package/dist/managers/backgroundTaskManager.d.ts +6 -0
- package/dist/managers/backgroundTaskManager.js +11 -0
- package/dist/managers/bangManager.d.ts +6 -0
- package/dist/managers/bangManager.js +11 -0
- package/dist/managers/hookManager.d.ts +8 -2
- package/dist/managers/hookManager.js +14 -4
- package/dist/managers/mcpManager.d.ts +18 -4
- package/dist/managers/mcpManager.js +40 -18
- 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/managers/toolManager.js +5 -0
- 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.d.ts +21 -2
- package/dist/services/configurationService.js +86 -24
- package/dist/services/initializationService.js +14 -4
- package/dist/services/interactionService.js +35 -7
- package/dist/services/remoteSettingsService.d.ts +12 -0
- package/dist/services/remoteSettingsService.js +15 -1
- package/dist/services/session.d.ts +13 -0
- package/dist/services/session.js +64 -0
- package/dist/services/taskManager.js +7 -1
- package/dist/tools/bashTool.js +1 -0
- package/dist/tools/enterWorktreeTool.js +14 -3
- package/dist/tools/exitWorktreeTool.js +11 -10
- package/dist/tools/types.d.ts +7 -0
- package/dist/types/agent.d.ts +0 -2
- package/dist/types/config.d.ts +9 -0
- package/dist/types/core.d.ts +1 -1
- package/dist/types/hooks.d.ts +2 -2
- package/dist/utils/containerSetup.js +13 -4
- package/dist/utils/openaiClient.js +2 -1
- package/dist/utils/pathEncoder.js +7 -2
- package/dist/utils/worktreeUtils.d.ts +17 -0
- package/dist/utils/worktreeUtils.js +339 -1
- package/package.json +1 -1
- package/src/agent.ts +43 -112
- package/src/index.ts +1 -0
- package/src/managers/aiManager.ts +389 -110
- package/src/managers/backgroundTaskManager.ts +15 -0
- package/src/managers/bangManager.ts +15 -0
- package/src/managers/hookManager.ts +20 -5
- package/src/managers/mcpManager.ts +60 -18
- package/src/managers/messageManager.ts +51 -23
- package/src/managers/subagentManager.ts +36 -25
- package/src/managers/toolManager.ts +7 -0
- 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 +100 -24
- package/src/services/initializationService.ts +17 -4
- package/src/services/interactionService.ts +49 -6
- package/src/services/remoteSettingsService.ts +16 -1
- package/src/services/session.ts +68 -0
- package/src/services/taskManager.ts +10 -1
- package/src/tools/bashTool.ts +1 -0
- package/src/tools/enterWorktreeTool.ts +19 -2
- package/src/tools/exitWorktreeTool.ts +15 -12
- package/src/tools/types.ts +7 -0
- package/src/types/agent.ts +0 -6
- package/src/types/config.ts +9 -0
- package/src/types/core.ts +1 -1
- package/src/types/hooks.ts +2 -2
- package/src/utils/containerSetup.ts +15 -5
- package/src/utils/openaiClient.ts +2 -0
- package/src/utils/pathEncoder.ts +7 -2
- package/src/utils/worktreeUtils.ts +401 -1
- 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
|
@@ -11,13 +11,21 @@ export interface McpManagerOptions {
|
|
|
11
11
|
/** Pre-configured MCP servers passed from constructor options */
|
|
12
12
|
mcpServers?: Record<string, McpServerConfig>;
|
|
13
13
|
}
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Expand environment variables in a string value.
|
|
16
|
+
* Supports ${VAR} and ${VAR:-default} patterns.
|
|
17
|
+
*
|
|
18
|
+
* @param env - Merged env to resolve against (session snapshot over OS env).
|
|
19
|
+
* Defaults to `process.env` for backward compatibility with tests
|
|
20
|
+
* and standalone callers.
|
|
21
|
+
*/
|
|
22
|
+
export declare function expandEnvVars(value: string, env?: Record<string, string | undefined>): string;
|
|
15
23
|
/**
|
|
16
24
|
* Walk an MCP config and resolve environment variables in all string fields.
|
|
17
|
-
*
|
|
18
|
-
* handled at spawn time
|
|
25
|
+
* Expands ${VAR} against the session env snapshot (over OS env); falls back to
|
|
26
|
+
* process.env. WAVE_PLUGIN_ROOT is skipped — handled at spawn time.
|
|
19
27
|
*/
|
|
20
|
-
export declare function resolveMcpConfig(config: McpConfig): McpConfig;
|
|
28
|
+
export declare function resolveMcpConfig(config: McpConfig, env?: Record<string, string | undefined>): McpConfig;
|
|
21
29
|
export declare class McpManager {
|
|
22
30
|
private container;
|
|
23
31
|
private config;
|
|
@@ -30,6 +38,12 @@ export declare class McpManager {
|
|
|
30
38
|
private reconnectTimers;
|
|
31
39
|
private reconnectAttempts;
|
|
32
40
|
constructor(container: Container, options?: McpManagerOptions);
|
|
41
|
+
/**
|
|
42
|
+
* Merged env for this session: OS env overlaid with the per-session settings
|
|
43
|
+
* snapshot. MCP env-var expansion (${VAR}) resolves against this so multiple
|
|
44
|
+
* sessions in one `wave --stdio` process don't read each other's settings env.
|
|
45
|
+
*/
|
|
46
|
+
private get envSnapshot();
|
|
33
47
|
/**
|
|
34
48
|
* Initialize MCP manager with working directory and optionally auto-connect
|
|
35
49
|
*/
|
|
@@ -11,7 +11,15 @@ import { logger } from "../utils/globalLogger.js";
|
|
|
11
11
|
* Supports ${VAR} and ${VAR:-default} patterns.
|
|
12
12
|
*/
|
|
13
13
|
const WAVE_TEMPLATE_VARS = ["WAVE_PLUGIN_ROOT", "CLAUDE_PLUGIN_ROOT"];
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Expand environment variables in a string value.
|
|
16
|
+
* Supports ${VAR} and ${VAR:-default} patterns.
|
|
17
|
+
*
|
|
18
|
+
* @param env - Merged env to resolve against (session snapshot over OS env).
|
|
19
|
+
* Defaults to `process.env` for backward compatibility with tests
|
|
20
|
+
* and standalone callers.
|
|
21
|
+
*/
|
|
22
|
+
export function expandEnvVars(value, env = process.env) {
|
|
15
23
|
return value.replace(/\$\{([^}]+)\}/g, (_match, expr) => {
|
|
16
24
|
const [varName, ...rest] = expr.split(":-");
|
|
17
25
|
const defaultValue = rest.join(":-");
|
|
@@ -19,38 +27,38 @@ export function expandEnvVars(value) {
|
|
|
19
27
|
if (WAVE_TEMPLATE_VARS.includes(varName)) {
|
|
20
28
|
return _match; // return original ${...} string untouched
|
|
21
29
|
}
|
|
22
|
-
return process.env[varName] ?? defaultValue;
|
|
30
|
+
return env[varName] ?? process.env[varName] ?? defaultValue;
|
|
23
31
|
});
|
|
24
32
|
}
|
|
25
33
|
/**
|
|
26
34
|
* Walk an MCP config and resolve environment variables in all string fields.
|
|
27
|
-
*
|
|
28
|
-
* handled at spawn time
|
|
35
|
+
* Expands ${VAR} against the session env snapshot (over OS env); falls back to
|
|
36
|
+
* process.env. WAVE_PLUGIN_ROOT is skipped — handled at spawn time.
|
|
29
37
|
*/
|
|
30
|
-
export function resolveMcpConfig(config) {
|
|
38
|
+
export function resolveMcpConfig(config, env = process.env) {
|
|
31
39
|
const resolved = { mcpServers: {} };
|
|
32
40
|
for (const [name, serverConfig] of Object.entries(config.mcpServers)) {
|
|
33
41
|
const resolvedServer = { ...serverConfig };
|
|
34
42
|
if (resolvedServer.command) {
|
|
35
|
-
resolvedServer.command = expandEnvVars(resolvedServer.command);
|
|
43
|
+
resolvedServer.command = expandEnvVars(resolvedServer.command, env);
|
|
36
44
|
}
|
|
37
45
|
if (resolvedServer.args) {
|
|
38
|
-
resolvedServer.args = resolvedServer.args.map(expandEnvVars);
|
|
46
|
+
resolvedServer.args = resolvedServer.args.map((a) => expandEnvVars(a, env));
|
|
39
47
|
}
|
|
40
48
|
if (resolvedServer.env) {
|
|
41
49
|
const resolvedEnv = {};
|
|
42
50
|
for (const [key, val] of Object.entries(resolvedServer.env)) {
|
|
43
|
-
resolvedEnv[key] = expandEnvVars(val);
|
|
51
|
+
resolvedEnv[key] = expandEnvVars(val, env);
|
|
44
52
|
}
|
|
45
53
|
resolvedServer.env = resolvedEnv;
|
|
46
54
|
}
|
|
47
55
|
if (resolvedServer.url) {
|
|
48
|
-
resolvedServer.url = expandEnvVars(resolvedServer.url);
|
|
56
|
+
resolvedServer.url = expandEnvVars(resolvedServer.url, env);
|
|
49
57
|
}
|
|
50
58
|
if (resolvedServer.headers) {
|
|
51
59
|
const resolvedHeaders = {};
|
|
52
60
|
for (const [key, val] of Object.entries(resolvedServer.headers)) {
|
|
53
|
-
resolvedHeaders[key] = expandEnvVars(val);
|
|
61
|
+
resolvedHeaders[key] = expandEnvVars(val, env);
|
|
54
62
|
}
|
|
55
63
|
resolvedServer.headers = resolvedHeaders;
|
|
56
64
|
}
|
|
@@ -71,6 +79,16 @@ export class McpManager {
|
|
|
71
79
|
this.callbacks = options.callbacks || {};
|
|
72
80
|
this.mcpServers = options.mcpServers;
|
|
73
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Merged env for this session: OS env overlaid with the per-session settings
|
|
84
|
+
* snapshot. MCP env-var expansion (${VAR}) resolves against this so multiple
|
|
85
|
+
* sessions in one `wave --stdio` process don't read each other's settings env.
|
|
86
|
+
*/
|
|
87
|
+
get envSnapshot() {
|
|
88
|
+
return (this.container
|
|
89
|
+
.get("ConfigurationService")
|
|
90
|
+
?.getMergedEnv?.() ?? process.env);
|
|
91
|
+
}
|
|
74
92
|
/**
|
|
75
93
|
* Initialize MCP manager with working directory and optionally auto-connect
|
|
76
94
|
*/
|
|
@@ -125,7 +143,7 @@ export class McpManager {
|
|
|
125
143
|
try {
|
|
126
144
|
const configContent = await fs.readFile(this.configPath, "utf-8");
|
|
127
145
|
const rawConfig = JSON.parse(configContent);
|
|
128
|
-
const workspaceConfig = resolveMcpConfig(rawConfig);
|
|
146
|
+
const workspaceConfig = resolveMcpConfig(rawConfig, this.envSnapshot);
|
|
129
147
|
// Extract original (pre-resolution) URLs for safe display
|
|
130
148
|
const originalUrls = {};
|
|
131
149
|
for (const [name, serverConfig] of Object.entries(rawConfig.mcpServers)) {
|
|
@@ -210,28 +228,29 @@ export class McpManager {
|
|
|
210
228
|
}
|
|
211
229
|
// Capture original URL before any resolution for safe display
|
|
212
230
|
const originalUrl = config.url;
|
|
213
|
-
// Expand env vars
|
|
231
|
+
// Expand env vars against the session snapshot (over OS env, e.g. ${TAVILY_API_KEY})
|
|
232
|
+
const env = this.envSnapshot;
|
|
214
233
|
const resolvedConfig = { ...config };
|
|
215
234
|
if (resolvedConfig.command) {
|
|
216
|
-
resolvedConfig.command = expandEnvVars(resolvedConfig.command);
|
|
235
|
+
resolvedConfig.command = expandEnvVars(resolvedConfig.command, env);
|
|
217
236
|
}
|
|
218
237
|
if (resolvedConfig.args) {
|
|
219
|
-
resolvedConfig.args = resolvedConfig.args.map(expandEnvVars);
|
|
238
|
+
resolvedConfig.args = resolvedConfig.args.map((a) => expandEnvVars(a, env));
|
|
220
239
|
}
|
|
221
240
|
if (resolvedConfig.env) {
|
|
222
241
|
const resolvedEnv = {};
|
|
223
242
|
for (const [key, val] of Object.entries(resolvedConfig.env)) {
|
|
224
|
-
resolvedEnv[key] = expandEnvVars(val);
|
|
243
|
+
resolvedEnv[key] = expandEnvVars(val, env);
|
|
225
244
|
}
|
|
226
245
|
resolvedConfig.env = resolvedEnv;
|
|
227
246
|
}
|
|
228
247
|
if (resolvedConfig.url) {
|
|
229
|
-
resolvedConfig.url = expandEnvVars(resolvedConfig.url);
|
|
248
|
+
resolvedConfig.url = expandEnvVars(resolvedConfig.url, env);
|
|
230
249
|
}
|
|
231
250
|
if (resolvedConfig.headers) {
|
|
232
251
|
const resolvedHeaders = {};
|
|
233
252
|
for (const [key, val] of Object.entries(resolvedConfig.headers)) {
|
|
234
|
-
resolvedHeaders[key] = expandEnvVars(val);
|
|
253
|
+
resolvedHeaders[key] = expandEnvVars(val, env);
|
|
235
254
|
}
|
|
236
255
|
resolvedConfig.headers = resolvedHeaders;
|
|
237
256
|
}
|
|
@@ -332,8 +351,11 @@ export class McpManager {
|
|
|
332
351
|
if (!server.config.command) {
|
|
333
352
|
throw new Error(`MCP server ${name} with type "stdio" requires a 'command'`);
|
|
334
353
|
}
|
|
354
|
+
// Base env = OS env overlaid with this session's settings snapshot, so
|
|
355
|
+
// custom env vars from settings.json reach the MCP server subprocess
|
|
356
|
+
// without polluting other sessions sharing one `wave --stdio` process.
|
|
335
357
|
const env = {
|
|
336
|
-
...
|
|
358
|
+
...this.envSnapshot,
|
|
337
359
|
...(server.config.env || {}),
|
|
338
360
|
};
|
|
339
361
|
// For plugin servers, substitute ${WAVE_PLUGIN_ROOT} and ${CLAUDE_PLUGIN_ROOT}
|
|
@@ -5,7 +5,6 @@ import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
|
5
5
|
import type { MemoryRule } from "../types/memoryRule.js";
|
|
6
6
|
import { Container } from "../utils/container.js";
|
|
7
7
|
export interface MessageManagerCallbacks {
|
|
8
|
-
onMessagesChange?: (messages: Message[]) => void;
|
|
9
8
|
onSessionIdChange?: (sessionId: string) => void;
|
|
10
9
|
onLatestTotalTokensChange?: (latestTotalTokens: number) => void;
|
|
11
10
|
onUsagesChange?: (usages: Usage[]) => void;
|
|
@@ -27,9 +26,9 @@ export interface MessageManagerCallbacks {
|
|
|
27
26
|
onErrorBlockAdded?: (error: string) => void;
|
|
28
27
|
onCompactBlockAdded?: (content: string) => void;
|
|
29
28
|
onCompactionStateChange?: (isCompacting: boolean) => void;
|
|
30
|
-
onAddBangMessage?: (command: string) => void;
|
|
31
|
-
onUpdateBangMessage?: (command: string, output: string) => void;
|
|
32
|
-
onCompleteBangMessage?: (command: string, exitCode: number) => void;
|
|
29
|
+
onAddBangMessage?: (command: string, messageId: string) => void;
|
|
30
|
+
onUpdateBangMessage?: (command: string, output: string, messageId: string) => void;
|
|
31
|
+
onCompleteBangMessage?: (command: string, exitCode: number, messageId: string) => void;
|
|
33
32
|
onInfoBlockAdded?: (content: string) => void;
|
|
34
33
|
onShowRewind?: () => void;
|
|
35
34
|
onFileHistoryBlockAdded?: (snapshots: import("../types/reversion.js").FileSnapshot[]) => void;
|
|
@@ -151,6 +150,12 @@ export declare class MessageManager {
|
|
|
151
150
|
addBangMessage(command: string): void;
|
|
152
151
|
updateBangMessage(command: string, output: string): void;
|
|
153
152
|
completeBangMessage(command: string, exitCode: number, output?: string): void;
|
|
153
|
+
/**
|
|
154
|
+
* Find the message ID of the most recent message containing a bang block
|
|
155
|
+
* for the given command. Bang callbacks do not carry a block ID, so the
|
|
156
|
+
* message is located by matching the command against bang blocks.
|
|
157
|
+
*/
|
|
158
|
+
private findBangMessageId;
|
|
154
159
|
addNotificationMessage(params: Omit<AddNotificationMessageParams, "messages">): void;
|
|
155
160
|
/**
|
|
156
161
|
* Rebuild usage array from messages containing usage metadata
|
|
@@ -169,7 +174,6 @@ export declare class MessageManager {
|
|
|
169
174
|
/**
|
|
170
175
|
* Finalize a streaming block of the given type by setting its stage to "end".
|
|
171
176
|
* Fires the corresponding incremental callback with chunk="" to signal finalization.
|
|
172
|
-
* Does NOT call onMessagesChange — the caller is responsible for that.
|
|
173
177
|
* Returns true if a block was finalized.
|
|
174
178
|
*/
|
|
175
179
|
private finalizeStreamingBlock;
|
|
@@ -181,7 +181,6 @@ export class MessageManager {
|
|
|
181
181
|
this.extractFileReadsFromMessage(messages[messages.length - 1]);
|
|
182
182
|
this.extractSkillInvocationsFromMessage(messages[messages.length - 1]);
|
|
183
183
|
}
|
|
184
|
-
this.callbacks.onMessagesChange?.([...messages]);
|
|
185
184
|
}
|
|
186
185
|
/**
|
|
187
186
|
* Save current session
|
|
@@ -194,6 +193,17 @@ export class MessageManager {
|
|
|
194
193
|
// No new messages to save
|
|
195
194
|
return;
|
|
196
195
|
}
|
|
196
|
+
// CC-aligned lazy materialization: when the session file has not been
|
|
197
|
+
// materialized yet (no saved messages) and every unsaved message is a
|
|
198
|
+
// meta message (isMeta: true, e.g. SessionStart hook context), skip
|
|
199
|
+
// persistence. Persisting meta-only sessions would create "0 tokens /
|
|
200
|
+
// No content" ghost entries in the resume list. The meta messages stay
|
|
201
|
+
// in memory and are flushed together with the first real user/assistant
|
|
202
|
+
// message (matches CC's pendingEntries buffering).
|
|
203
|
+
if (this.savedMessageCount === 0 &&
|
|
204
|
+
unsavedMessages.every((m) => m.isMeta)) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
197
207
|
// Create session if needed (only when we have messages to save)
|
|
198
208
|
if (this.savedMessageCount === 0) {
|
|
199
209
|
// This is the first time saving messages, so create the session
|
|
@@ -403,7 +413,9 @@ export class MessageManager {
|
|
|
403
413
|
command,
|
|
404
414
|
});
|
|
405
415
|
this.setMessages(updatedMessages);
|
|
406
|
-
|
|
416
|
+
// The bang message is appended as the last message
|
|
417
|
+
const messageId = this.messages[this.messages.length - 1]?.id ?? "";
|
|
418
|
+
this.callbacks.onAddBangMessage?.(command, messageId);
|
|
407
419
|
}
|
|
408
420
|
updateBangMessage(command, output) {
|
|
409
421
|
const updatedMessages = updateBangInMessage({
|
|
@@ -412,7 +424,8 @@ export class MessageManager {
|
|
|
412
424
|
output,
|
|
413
425
|
});
|
|
414
426
|
this.setMessages(updatedMessages);
|
|
415
|
-
this.
|
|
427
|
+
const messageId = this.findBangMessageId(command) ?? "";
|
|
428
|
+
this.callbacks.onUpdateBangMessage?.(command, output, messageId);
|
|
416
429
|
}
|
|
417
430
|
completeBangMessage(command, exitCode, output) {
|
|
418
431
|
const updatedMessages = completeBangInMessage({
|
|
@@ -422,7 +435,24 @@ export class MessageManager {
|
|
|
422
435
|
output,
|
|
423
436
|
});
|
|
424
437
|
this.setMessages(updatedMessages);
|
|
425
|
-
this.
|
|
438
|
+
const messageId = this.findBangMessageId(command) ?? "";
|
|
439
|
+
this.callbacks.onCompleteBangMessage?.(command, exitCode, messageId);
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Find the message ID of the most recent message containing a bang block
|
|
443
|
+
* for the given command. Bang callbacks do not carry a block ID, so the
|
|
444
|
+
* message is located by matching the command against bang blocks.
|
|
445
|
+
*/
|
|
446
|
+
findBangMessageId(command) {
|
|
447
|
+
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
448
|
+
const message = this.messages[i];
|
|
449
|
+
if (message.role !== "user")
|
|
450
|
+
continue;
|
|
451
|
+
const hasBangBlock = message.blocks?.some((block) => block.type === "bang" && block.command === command);
|
|
452
|
+
if (hasBangBlock)
|
|
453
|
+
return message.id;
|
|
454
|
+
}
|
|
455
|
+
return undefined;
|
|
426
456
|
}
|
|
427
457
|
addNotificationMessage(params) {
|
|
428
458
|
const newMessages = addNotificationMessageToMessages({
|
|
@@ -468,7 +498,6 @@ export class MessageManager {
|
|
|
468
498
|
/**
|
|
469
499
|
* Finalize a streaming block of the given type by setting its stage to "end".
|
|
470
500
|
* Fires the corresponding incremental callback with chunk="" to signal finalization.
|
|
471
|
-
* Does NOT call onMessagesChange — the caller is responsible for that.
|
|
472
501
|
* Returns true if a block was finalized.
|
|
473
502
|
*/
|
|
474
503
|
finalizeStreamingBlock(lastMessage, type) {
|
|
@@ -552,7 +581,6 @@ export class MessageManager {
|
|
|
552
581
|
stage: "streaming",
|
|
553
582
|
});
|
|
554
583
|
// Note: Subagent-specific callbacks are now handled by SubagentManager
|
|
555
|
-
this.callbacks.onMessagesChange?.([...this.messages]); // Still need to notify of changes
|
|
556
584
|
}
|
|
557
585
|
/**
|
|
558
586
|
* Update the current assistant message reasoning during streaming
|
|
@@ -599,7 +627,6 @@ export class MessageManager {
|
|
|
599
627
|
accumulated: newAccumulatedReasoning,
|
|
600
628
|
stage: "streaming",
|
|
601
629
|
});
|
|
602
|
-
this.callbacks.onMessagesChange?.([...this.messages]); // Still need to notify of changes
|
|
603
630
|
}
|
|
604
631
|
/**
|
|
605
632
|
* Finalize streaming text/reasoning blocks by setting their stage to "end".
|
|
@@ -612,11 +639,8 @@ export class MessageManager {
|
|
|
612
639
|
const lastMessage = this.messages[this.messages.length - 1];
|
|
613
640
|
if (lastMessage.role !== "assistant")
|
|
614
641
|
return;
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
if (textFinalized || reasoningFinalized) {
|
|
618
|
-
this.callbacks.onMessagesChange?.([...this.messages]);
|
|
619
|
-
}
|
|
642
|
+
this.finalizeStreamingBlock(lastMessage, "text");
|
|
643
|
+
this.finalizeStreamingBlock(lastMessage, "reasoning");
|
|
620
644
|
}
|
|
621
645
|
/**
|
|
622
646
|
* Finalize any tool blocks still in a non-terminal stage (start/streaming/running)
|
|
@@ -153,4 +153,10 @@ export declare class SubagentManager {
|
|
|
153
153
|
* Extracted to reuse in both create and restore flows
|
|
154
154
|
*/
|
|
155
155
|
private createSubagentCallbacks;
|
|
156
|
+
/**
|
|
157
|
+
* Pull the latest messages from the subagent instance's MessageManager and
|
|
158
|
+
* refresh the instance's cached messages, usedTools, onUpdate and the
|
|
159
|
+
* onSubagentMessagesChange forwarding. Triggered by incremental callbacks.
|
|
160
|
+
*/
|
|
161
|
+
private refreshSubagentState;
|
|
156
162
|
}
|
|
@@ -538,18 +538,21 @@ export class SubagentManager {
|
|
|
538
538
|
createSubagentCallbacks(subagentId) {
|
|
539
539
|
return {
|
|
540
540
|
onUserMessageAdded: (params) => {
|
|
541
|
+
this.refreshSubagentState(subagentId);
|
|
541
542
|
// Forward user message events to parent via SubagentManager callbacks
|
|
542
543
|
if (this.callbacks?.onSubagentUserMessageAdded) {
|
|
543
544
|
this.callbacks.onSubagentUserMessageAdded(subagentId, params);
|
|
544
545
|
}
|
|
545
546
|
},
|
|
546
547
|
onAssistantMessageAdded: (messageId) => {
|
|
548
|
+
this.refreshSubagentState(subagentId);
|
|
547
549
|
// Forward assistant message events to parent via SubagentManager callbacks
|
|
548
550
|
if (this.callbacks?.onSubagentAssistantMessageAdded) {
|
|
549
551
|
this.callbacks.onSubagentAssistantMessageAdded(subagentId, messageId);
|
|
550
552
|
}
|
|
551
553
|
},
|
|
552
554
|
onAssistantContentUpdated: (params) => {
|
|
555
|
+
this.refreshSubagentState(subagentId);
|
|
553
556
|
// Forward assistant content updates to parent via SubagentManager callbacks
|
|
554
557
|
if (this.callbacks?.onSubagentAssistantContentUpdated) {
|
|
555
558
|
this.callbacks.onSubagentAssistantContentUpdated({
|
|
@@ -559,6 +562,7 @@ export class SubagentManager {
|
|
|
559
562
|
}
|
|
560
563
|
},
|
|
561
564
|
onAssistantReasoningUpdated: (params) => {
|
|
565
|
+
this.refreshSubagentState(subagentId);
|
|
562
566
|
// Forward assistant reasoning updates to parent via SubagentManager callbacks
|
|
563
567
|
if (this.callbacks?.onSubagentAssistantReasoningUpdated) {
|
|
564
568
|
this.callbacks.onSubagentAssistantReasoningUpdated({
|
|
@@ -568,6 +572,7 @@ export class SubagentManager {
|
|
|
568
572
|
}
|
|
569
573
|
},
|
|
570
574
|
onToolBlockUpdated: (params) => {
|
|
575
|
+
this.refreshSubagentState(subagentId);
|
|
571
576
|
const instance = this.instances.get(subagentId);
|
|
572
577
|
if (instance) {
|
|
573
578
|
// Log tool execution to file only when finalized
|
|
@@ -582,28 +587,6 @@ export class SubagentManager {
|
|
|
582
587
|
this.callbacks.onSubagentToolBlockUpdated(subagentId, params);
|
|
583
588
|
}
|
|
584
589
|
},
|
|
585
|
-
// These callbacks will be handled by the parent agent
|
|
586
|
-
onMessagesChange: (messages) => {
|
|
587
|
-
const instance = this.instances.get(subagentId);
|
|
588
|
-
if (instance) {
|
|
589
|
-
instance.messages = messages;
|
|
590
|
-
// Compute usedTools from messages (last 2 tool blocks)
|
|
591
|
-
const toolBlocks = messages.flatMap((m) => m.blocks?.filter((b) => b.type === "tool") ?? []);
|
|
592
|
-
const last2 = toolBlocks.slice(-2);
|
|
593
|
-
instance.usedTools = last2.map((tb) => ({
|
|
594
|
-
name: tb.name ?? "",
|
|
595
|
-
parameters: tb.parameters ?? "",
|
|
596
|
-
compactParams: tb.compactParams,
|
|
597
|
-
stage: tb.stage,
|
|
598
|
-
}));
|
|
599
|
-
// Trigger the onUpdate callback if provided
|
|
600
|
-
instance.onUpdate?.();
|
|
601
|
-
// Forward subagent message changes to parent via callbacks
|
|
602
|
-
if (this.callbacks?.onSubagentMessagesChange) {
|
|
603
|
-
this.callbacks.onSubagentMessagesChange(subagentId, messages);
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
},
|
|
607
590
|
onLatestTotalTokensChange: (tokens) => {
|
|
608
591
|
const instance = this.instances.get(subagentId);
|
|
609
592
|
if (instance) {
|
|
@@ -616,6 +599,7 @@ export class SubagentManager {
|
|
|
616
599
|
}
|
|
617
600
|
},
|
|
618
601
|
onErrorBlockAdded: (error) => {
|
|
602
|
+
this.refreshSubagentState(subagentId);
|
|
619
603
|
const instance = this.instances.get(subagentId);
|
|
620
604
|
if (instance?.logStream) {
|
|
621
605
|
instance.logStream.write(`[${new Date().toISOString()}] Error: ${error}\n`);
|
|
@@ -623,4 +607,31 @@ export class SubagentManager {
|
|
|
623
607
|
},
|
|
624
608
|
};
|
|
625
609
|
}
|
|
610
|
+
/**
|
|
611
|
+
* Pull the latest messages from the subagent instance's MessageManager and
|
|
612
|
+
* refresh the instance's cached messages, usedTools, onUpdate and the
|
|
613
|
+
* onSubagentMessagesChange forwarding. Triggered by incremental callbacks.
|
|
614
|
+
*/
|
|
615
|
+
refreshSubagentState(subagentId) {
|
|
616
|
+
const instance = this.instances.get(subagentId);
|
|
617
|
+
if (!instance)
|
|
618
|
+
return;
|
|
619
|
+
const messages = instance.messageManager.getMessages();
|
|
620
|
+
instance.messages = messages;
|
|
621
|
+
// Compute usedTools from messages (last 2 tool blocks)
|
|
622
|
+
const toolBlocks = messages.flatMap((m) => m.blocks?.filter((b) => b.type === "tool") ?? []);
|
|
623
|
+
const last2 = toolBlocks.slice(-2);
|
|
624
|
+
instance.usedTools = last2.map((tb) => ({
|
|
625
|
+
name: tb.name ?? "",
|
|
626
|
+
parameters: tb.parameters ?? "",
|
|
627
|
+
compactParams: tb.compactParams,
|
|
628
|
+
stage: tb.stage,
|
|
629
|
+
}));
|
|
630
|
+
// Trigger the onUpdate callback if provided
|
|
631
|
+
instance.onUpdate?.();
|
|
632
|
+
// Forward subagent message changes to parent via callbacks
|
|
633
|
+
if (this.callbacks?.onSubagentMessagesChange) {
|
|
634
|
+
this.callbacks.onSubagentMessagesChange(subagentId, messages);
|
|
635
|
+
}
|
|
636
|
+
}
|
|
626
637
|
}
|
|
@@ -179,6 +179,11 @@ class ToolManager {
|
|
|
179
179
|
workflowManager: this.container.has("WorkflowManager")
|
|
180
180
|
? this.container.get("WorkflowManager")
|
|
181
181
|
: undefined,
|
|
182
|
+
sessionEnv: this.container.has("ConfigurationService")
|
|
183
|
+
? this.container
|
|
184
|
+
.get("ConfigurationService")
|
|
185
|
+
?.getMergedEnv?.()
|
|
186
|
+
: undefined,
|
|
182
187
|
sessionId: context.sessionId,
|
|
183
188
|
toolCallId: context.toolCallId,
|
|
184
189
|
};
|
package/dist/prompts/index.d.ts
CHANGED
|
@@ -34,7 +34,6 @@ export declare function getCompactPrompt(customInstructions?: string): string;
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function formatCompactSummary(summary: string): string;
|
|
36
36
|
export declare const WEB_CONTENT_SYSTEM_PROMPT = "You are a helpful assistant that extracts information from web content. The content is provided in Markdown format.";
|
|
37
|
-
export declare const BTW_SYSTEM_PROMPT = "You are a helpful assistant. Answer the user's side question based on the conversation history. \nDo NOT say things like \"Let me try...\", \"I'll now...\", \"Let me check...\", or promise to take any action. \nIf you don't know the answer, say so - do not offer to look it up or investigate. \nSimply answer the question with the information you have.";
|
|
38
37
|
export declare function buildSystemPrompt(basePrompt: string | undefined, tools: ToolPlugin[], options?: {
|
|
39
38
|
workdir?: string;
|
|
40
39
|
originalWorkdir?: string;
|
package/dist/prompts/index.js
CHANGED
|
@@ -285,10 +285,6 @@ export function formatCompactSummary(summary) {
|
|
|
285
285
|
return formattedSummary.trim();
|
|
286
286
|
}
|
|
287
287
|
export const WEB_CONTENT_SYSTEM_PROMPT = `You are a helpful assistant that extracts information from web content. The content is provided in Markdown format.`;
|
|
288
|
-
export const BTW_SYSTEM_PROMPT = `You are a helpful assistant. Answer the user's side question based on the conversation history.
|
|
289
|
-
Do NOT say things like "Let me try...", "I'll now...", "Let me check...", or promise to take any action.
|
|
290
|
-
If you don't know the answer, say so - do not offer to look it up or investigate.
|
|
291
|
-
Simply answer the question with the information you have.`;
|
|
292
288
|
export function buildSystemPrompt(basePrompt, tools, options = {}) {
|
|
293
289
|
// --- Static block (cacheable) ---
|
|
294
290
|
let staticText = basePrompt || DEFAULT_SYSTEM_PROMPT;
|
|
@@ -34,6 +34,7 @@ export interface CallAgentOptions {
|
|
|
34
34
|
stage?: "start" | "streaming" | "running" | "end";
|
|
35
35
|
}) => void;
|
|
36
36
|
onReasoningUpdate?: (content: string) => void;
|
|
37
|
+
disableThinkingOptions?: Record<string, unknown>;
|
|
37
38
|
}
|
|
38
39
|
export interface CallAgentResult {
|
|
39
40
|
content?: string;
|
|
@@ -62,37 +63,3 @@ export interface ProcessWebContentResult {
|
|
|
62
63
|
};
|
|
63
64
|
}
|
|
64
65
|
export declare function processWebContent(options: ProcessWebContentOptions): Promise<ProcessWebContentResult>;
|
|
65
|
-
export interface BtwOptions {
|
|
66
|
-
gatewayConfig: GatewayConfig;
|
|
67
|
-
modelConfig: ModelConfig;
|
|
68
|
-
messages: ChatCompletionMessageParam[];
|
|
69
|
-
question: string;
|
|
70
|
-
abortSignal?: AbortSignal;
|
|
71
|
-
model?: string;
|
|
72
|
-
}
|
|
73
|
-
export interface BtwResult {
|
|
74
|
-
content: string;
|
|
75
|
-
usage?: {
|
|
76
|
-
prompt_tokens: number;
|
|
77
|
-
completion_tokens: number;
|
|
78
|
-
total_tokens: number;
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
export declare function btw(options: BtwOptions): Promise<BtwResult>;
|
|
82
|
-
export interface EvaluateGoalOptions {
|
|
83
|
-
gatewayConfig: GatewayConfig;
|
|
84
|
-
modelConfig: ModelConfig;
|
|
85
|
-
model: string;
|
|
86
|
-
goalCondition: string;
|
|
87
|
-
messages: ChatCompletionMessageParam[];
|
|
88
|
-
abortSignal?: AbortSignal;
|
|
89
|
-
}
|
|
90
|
-
export interface EvaluateGoalResult {
|
|
91
|
-
content: string;
|
|
92
|
-
usage?: {
|
|
93
|
-
prompt_tokens: number;
|
|
94
|
-
completion_tokens: number;
|
|
95
|
-
total_tokens: number;
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
export declare function evaluateGoal(options: EvaluateGoalOptions): Promise<EvaluateGoalResult>;
|