wave-agent-sdk 0.14.1 → 0.14.3

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.
Files changed (92) hide show
  1. package/builtin/skills/settings/HOOKS.md +69 -0
  2. package/builtin/skills/settings/PLUGINS.md +171 -0
  3. package/builtin/skills/settings/SKILL.md +8 -3
  4. package/builtin/skills/settings/SUBAGENTS.md +21 -2
  5. package/dist/agent.d.ts +2 -2
  6. package/dist/agent.d.ts.map +1 -1
  7. package/dist/agent.js +12 -3
  8. package/dist/managers/aiManager.d.ts +6 -6
  9. package/dist/managers/aiManager.d.ts.map +1 -1
  10. package/dist/managers/aiManager.js +122 -59
  11. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  12. package/dist/managers/backgroundTaskManager.js +28 -18
  13. package/dist/managers/hookManager.d.ts +16 -1
  14. package/dist/managers/hookManager.d.ts.map +1 -1
  15. package/dist/managers/hookManager.js +97 -8
  16. package/dist/managers/messageManager.d.ts +19 -4
  17. package/dist/managers/messageManager.d.ts.map +1 -1
  18. package/dist/managers/messageManager.js +63 -18
  19. package/dist/managers/pluginManager.d.ts +1 -0
  20. package/dist/managers/pluginManager.d.ts.map +1 -1
  21. package/dist/managers/pluginManager.js +7 -0
  22. package/dist/managers/subagentManager.d.ts +5 -0
  23. package/dist/managers/subagentManager.d.ts.map +1 -1
  24. package/dist/managers/subagentManager.js +35 -0
  25. package/dist/prompts/index.d.ts +1 -1
  26. package/dist/prompts/index.d.ts.map +1 -1
  27. package/dist/prompts/index.js +1 -1
  28. package/dist/services/MarketplaceService.d.ts +0 -11
  29. package/dist/services/MarketplaceService.d.ts.map +1 -1
  30. package/dist/services/MarketplaceService.js +21 -89
  31. package/dist/services/aiService.d.ts +3 -3
  32. package/dist/services/aiService.d.ts.map +1 -1
  33. package/dist/services/aiService.js +7 -7
  34. package/dist/services/hook.d.ts.map +1 -1
  35. package/dist/services/hook.js +15 -0
  36. package/dist/services/initializationService.d.ts.map +1 -1
  37. package/dist/services/initializationService.js +24 -1
  38. package/dist/services/interactionService.js +1 -1
  39. package/dist/services/pluginLoader.d.ts +5 -6
  40. package/dist/services/pluginLoader.d.ts.map +1 -1
  41. package/dist/services/pluginLoader.js +43 -53
  42. package/dist/services/session.d.ts +1 -1
  43. package/dist/services/session.js +7 -7
  44. package/dist/services/taskManager.d.ts +1 -1
  45. package/dist/services/taskManager.js +1 -1
  46. package/dist/types/core.d.ts +1 -1
  47. package/dist/types/core.d.ts.map +1 -1
  48. package/dist/types/hooks.d.ts +9 -1
  49. package/dist/types/hooks.d.ts.map +1 -1
  50. package/dist/types/hooks.js +2 -0
  51. package/dist/types/marketplace.d.ts +1 -26
  52. package/dist/types/marketplace.d.ts.map +1 -1
  53. package/dist/types/messaging.d.ts +3 -3
  54. package/dist/types/messaging.d.ts.map +1 -1
  55. package/dist/types/plugins.d.ts +3 -13
  56. package/dist/types/plugins.d.ts.map +1 -1
  57. package/dist/utils/convertMessagesForAPI.d.ts +1 -1
  58. package/dist/utils/convertMessagesForAPI.d.ts.map +1 -1
  59. package/dist/utils/convertMessagesForAPI.js +18 -7
  60. package/dist/utils/groupMessagesByApiRound.d.ts +1 -1
  61. package/dist/utils/groupMessagesByApiRound.js +6 -6
  62. package/dist/utils/messageOperations.d.ts.map +1 -1
  63. package/dist/utils/messageOperations.js +3 -3
  64. package/dist/utils/subagentParser.d.ts +8 -1
  65. package/dist/utils/subagentParser.d.ts.map +1 -1
  66. package/dist/utils/subagentParser.js +18 -3
  67. package/package.json +1 -1
  68. package/src/agent.ts +16 -3
  69. package/src/managers/aiManager.ts +142 -63
  70. package/src/managers/backgroundTaskManager.ts +32 -22
  71. package/src/managers/hookManager.ts +125 -10
  72. package/src/managers/messageManager.ts +76 -22
  73. package/src/managers/pluginManager.ts +10 -0
  74. package/src/managers/subagentManager.ts +47 -0
  75. package/src/prompts/index.ts +1 -1
  76. package/src/services/MarketplaceService.ts +26 -127
  77. package/src/services/aiService.ts +11 -11
  78. package/src/services/hook.ts +17 -0
  79. package/src/services/initializationService.ts +33 -1
  80. package/src/services/interactionService.ts +1 -1
  81. package/src/services/pluginLoader.ts +51 -67
  82. package/src/services/session.ts +7 -7
  83. package/src/services/taskManager.ts +1 -1
  84. package/src/types/core.ts +1 -1
  85. package/src/types/hooks.ts +16 -2
  86. package/src/types/marketplace.ts +1 -24
  87. package/src/types/messaging.ts +3 -3
  88. package/src/types/plugins.ts +3 -13
  89. package/src/utils/convertMessagesForAPI.ts +24 -9
  90. package/src/utils/groupMessagesByApiRound.ts +6 -6
  91. package/src/utils/messageOperations.ts +3 -5
  92. package/src/utils/subagentParser.ts +31 -4
@@ -7,7 +7,7 @@
7
7
  * Boundaries:
8
8
  * - A new `role: "user"` message starts a new round.
9
9
  * - A new `role: "assistant"` message with a different `id` starts a new round.
10
- * - A message with a `compress` block is pushed as its own round and starts a
10
+ * - A message with a `compact` block is pushed as its own round and starts a
11
11
  * new round after it.
12
12
  */
13
13
  export function groupMessagesByApiRound(messages) {
@@ -20,9 +20,9 @@ export function groupMessagesByApiRound(messages) {
20
20
  startNewRound = true;
21
21
  }
22
22
  else if (msg.role === "assistant") {
23
- // Compress block is always its own round
24
- const hasCompress = msg.blocks.some((b) => b.type === "compress");
25
- if (hasCompress) {
23
+ // Compact block is always its own round
24
+ const hasCompact = msg.blocks.some((b) => b.type === "compact");
25
+ if (hasCompact) {
26
26
  startNewRound = true;
27
27
  }
28
28
  else if (msg.id !== lastAssistantId) {
@@ -46,9 +46,9 @@ export function groupMessagesByApiRound(messages) {
46
46
  currentRound = [];
47
47
  }
48
48
  currentRound.push(msg);
49
- // After pushing a compress message as its own round, flush immediately
49
+ // After pushing a compact message as its own round, flush immediately
50
50
  if (msg.role === "assistant" &&
51
- msg.blocks.some((b) => b.type === "compress")) {
51
+ msg.blocks.some((b) => b.type === "compact")) {
52
52
  rounds.push({
53
53
  messages: currentRound,
54
54
  estimatedTokens: estimateTokens(currentRound),
@@ -1 +1 @@
1
- {"version":3,"file":"messageOperations.d.ts","sourceRoot":"","sources":["../../src/utils/messageOperations.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messageOperations.d.ts","sourceRoot":"","sources":["../../src/utils/messageOperations.ts"],"names":[],"mappings":"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"}
@@ -423,9 +423,9 @@ export function getMessageContent(message) {
423
423
  if (bangBlock && "command" in bangBlock) {
424
424
  return `!${bangBlock.command}`;
425
425
  }
426
- const compressBlock = message.blocks.find((block) => block.type === "compress");
427
- if (compressBlock && "content" in compressBlock) {
428
- return compressBlock.content;
426
+ const compactBlock = message.blocks.find((block) => block.type === "compact");
427
+ if (compactBlock && "content" in compactBlock) {
428
+ return compactBlock.content;
429
429
  }
430
430
  return "";
431
431
  }
@@ -5,9 +5,16 @@ export interface SubagentConfiguration {
5
5
  model?: string;
6
6
  systemPrompt: string;
7
7
  filePath: string;
8
- scope: "project" | "user" | "builtin";
8
+ scope: "project" | "user" | "builtin" | "plugin";
9
9
  priority: number;
10
+ /** Plugin root directory path, set when scope is "plugin" */
11
+ pluginRoot?: string;
10
12
  }
13
+ /**
14
+ * Parse a plugin agent markdown file.
15
+ * Exposed as a public API for PluginLoader to use.
16
+ */
17
+ export declare function parseAgentFile(filePath: string, scope: "plugin", pluginRoot: string): SubagentConfiguration;
11
18
  /**
12
19
  * Load all subagent configurations from project and user directories, plus built-in subagents
13
20
  */
@@ -1 +1 @@
1
- {"version":3,"file":"subagentParser.d.ts","sourceRoot":"","sources":["../../src/utils/subagentParser.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAwLD;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAsBlC;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAGvC"}
1
+ {"version":3,"file":"subagentParser.d.ts","sourceRoot":"","sources":["../../src/utils/subagentParser.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,QAAQ,CAAC;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAkKD;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,QAAQ,EACf,UAAU,EAAE,MAAM,GACjB,qBAAqB,CAEvB;AAqCD;;GAEG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAsBlC;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAGvC"}
@@ -80,9 +80,9 @@ function validateConfiguration(config, filePath) {
80
80
  }
81
81
  }
82
82
  /**
83
- * Parse a single subagent markdown file
83
+ * Parse a single subagent markdown file with optional pluginRoot support
84
84
  */
85
- function parseSubagentFile(filePath, scope) {
85
+ function parseSubagentFile(filePath, scope, pluginRoot) {
86
86
  try {
87
87
  const content = readFileSync(filePath, "utf-8");
88
88
  const { frontmatter, body } = parseFrontmatter(content);
@@ -99,21 +99,36 @@ function parseSubagentFile(filePath, scope) {
99
99
  priority = 2;
100
100
  if (scope === "builtin")
101
101
  priority = 3;
102
+ if (scope === "plugin")
103
+ priority = 2; // Same priority as user-level
104
+ let systemPrompt = body;
105
+ // Substitute ${WAVE_PLUGIN_ROOT} for plugin scope at parse time
106
+ if (scope === "plugin" && pluginRoot) {
107
+ systemPrompt = systemPrompt.replace(/\$\{WAVE_PLUGIN_ROOT\}/g, pluginRoot);
108
+ }
102
109
  return {
103
110
  name: frontmatter.name,
104
111
  description: frontmatter.description,
105
112
  tools: frontmatter.tools,
106
113
  model: frontmatter.model,
107
- systemPrompt: body,
114
+ systemPrompt,
108
115
  filePath,
109
116
  scope,
110
117
  priority,
118
+ pluginRoot: scope === "plugin" ? pluginRoot : undefined,
111
119
  };
112
120
  }
113
121
  catch (error) {
114
122
  throw new Error(`Failed to parse subagent file ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
115
123
  }
116
124
  }
125
+ /**
126
+ * Parse a plugin agent markdown file.
127
+ * Exposed as a public API for PluginLoader to use.
128
+ */
129
+ export function parseAgentFile(filePath, scope, pluginRoot) {
130
+ return parseSubagentFile(filePath, scope, pluginRoot);
131
+ }
117
132
  /**
118
133
  * Scan directory for subagent files
119
134
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-agent-sdk",
3
- "version": "0.14.1",
3
+ "version": "0.14.3",
4
4
  "description": "SDK for building AI-powered development tools and agents",
5
5
  "keywords": [
6
6
  "ai",
package/src/agent.ts CHANGED
@@ -317,9 +317,9 @@ export class Agent {
317
317
  return this.aiManager.isLoading;
318
318
  }
319
319
 
320
- /** Get message compression status */
321
- public get isCompressing(): boolean {
322
- return this.aiManager.getIsCompressing();
320
+ /** Get message compaction status */
321
+ public get isCompacting(): boolean {
322
+ return this.aiManager.getIsCompacting();
323
323
  }
324
324
 
325
325
  /** Get bash command execution status */
@@ -633,6 +633,19 @@ export class Agent {
633
633
  this.pendingNotificationPromises = [];
634
634
  }
635
635
 
636
+ // Fire SessionEnd hooks (fire-and-forget, don't block shutdown)
637
+ try {
638
+ const sessionId = this.messageManager.getSessionId();
639
+ const transcriptPath = this.messageManager.getTranscriptPath();
640
+ await this.hookManager.executeSessionEndHooks(
641
+ "stop",
642
+ sessionId,
643
+ transcriptPath,
644
+ );
645
+ } catch (error) {
646
+ this.logger?.warn(`SessionEnd hooks failed: ${(error as Error).message}`);
647
+ }
648
+
636
649
  await this.messageManager.saveSession();
637
650
  this.abortAIMessage(); // This will abort tools including Agent tool (subagents)
638
651
  this.abortBashCommand();
@@ -30,7 +30,7 @@ import type { NotificationQueue } from "./notificationQueue.js";
30
30
  import { logger } from "../utils/globalLogger.js";
31
31
 
32
32
  export interface AIManagerCallbacks {
33
- onCompressionStateChange?: (isCompressing: boolean) => void;
33
+ onCompactionStateChange?: (isCompacting: boolean) => void;
34
34
  onUsageAdded?: (usage: Usage) => void;
35
35
  onCwdChange?: (newCwd: string) => void;
36
36
  }
@@ -58,7 +58,7 @@ export class AIManager {
58
58
  private stream: boolean; // Streaming mode flag
59
59
  private modelOverride?: string;
60
60
  private _onCwdChange?: (newCwd: string) => void; // Store callback for CWD changes
61
- private consecutiveCompressionFailures: number = 0;
61
+ private consecutiveCompactionFailures: number = 0;
62
62
 
63
63
  // Service overrides
64
64
  constructor(
@@ -177,7 +177,7 @@ export class AIManager {
177
177
  this._onCwdChange = callback;
178
178
  }
179
179
 
180
- private isCompressing: boolean = false;
180
+ private isCompacting: boolean = false;
181
181
  private callbacks: AIManagerCallbacks;
182
182
 
183
183
  /**
@@ -253,8 +253,8 @@ export class AIManager {
253
253
  return "";
254
254
  }
255
255
 
256
- // Private method to handle token statistics and message compression
257
- private async handleTokenUsageAndCompression(
256
+ // Private method to handle token statistics and message compaction
257
+ private async handleTokenUsageAndCompaction(
258
258
  usage: Usage | undefined,
259
259
  abortController: AbortController,
260
260
  ): Promise<void> {
@@ -272,30 +272,30 @@ export class AIManager {
272
272
  this.getMaxInputTokens()
273
273
  ) {
274
274
  logger?.debug(
275
- `Token usage exceeded ${this.getMaxInputTokens()}, compressing messages...`,
275
+ `Token usage exceeded ${this.getMaxInputTokens()}, compacting messages...`,
276
276
  );
277
277
 
278
- // Check if messages need compression
279
- const messagesToCompress = this.messageManager.getMessages();
278
+ // Check if messages need compaction
279
+ const messagesToCompact = this.messageManager.getMessages();
280
280
 
281
- // If there are messages to compress, perform compression
282
- if (messagesToCompress.length > 0) {
283
- // Circuit breaker: skip compression after 3 consecutive failures
284
- if (this.consecutiveCompressionFailures >= 3) {
281
+ // If there are messages to compact, perform compaction
282
+ if (messagesToCompact.length > 0) {
283
+ // Circuit breaker: skip compaction after 3 consecutive failures
284
+ if (this.consecutiveCompactionFailures >= 3) {
285
285
  logger?.warn(
286
- `Skipping compression: ${this.consecutiveCompressionFailures} consecutive failures`,
286
+ `Skipping compaction: ${this.consecutiveCompactionFailures} consecutive failures`,
287
287
  );
288
288
  return;
289
289
  }
290
290
 
291
- const recentChatMessages = convertMessagesForAPI(messagesToCompress);
291
+ const recentChatMessages = convertMessagesForAPI(messagesToCompact);
292
292
 
293
- // Save session before compression to preserve original messages
293
+ // Save session before compaction to preserve original messages
294
294
  await this.messageManager.saveSession();
295
295
 
296
- this.setIsCompressing(true);
296
+ this.setIsCompacting(true);
297
297
  try {
298
- const compressionResult = await aiService.compressMessages({
298
+ const compactResult = await aiService.compactMessages({
299
299
  gatewayConfig: this.getGatewayConfig(),
300
300
  modelConfig: this.getModelConfig(),
301
301
  messages: recentChatMessages,
@@ -303,15 +303,15 @@ export class AIManager {
303
303
  model: this.getModelConfig().fastModel,
304
304
  });
305
305
 
306
- // Handle usage tracking for compression operations
307
- let compressionUsage: Usage | undefined;
308
- if (compressionResult.usage) {
309
- compressionUsage = {
310
- prompt_tokens: compressionResult.usage.prompt_tokens,
311
- completion_tokens: compressionResult.usage.completion_tokens,
312
- total_tokens: compressionResult.usage.total_tokens,
306
+ // Handle usage tracking for compaction operations
307
+ let compactUsage: Usage | undefined;
308
+ if (compactResult.usage) {
309
+ compactUsage = {
310
+ prompt_tokens: compactResult.usage.prompt_tokens,
311
+ completion_tokens: compactResult.usage.completion_tokens,
312
+ total_tokens: compactResult.usage.total_tokens,
313
313
  model: this.getModelConfig().fastModel,
314
- operation_type: "compress",
314
+ operation_type: "compact",
315
315
  };
316
316
  }
317
317
 
@@ -364,73 +364,152 @@ export class AIManager {
364
364
  }
365
365
  }
366
366
 
367
- // 4. Skills context
368
- const skills =
369
- this.skillManager
370
- ?.getAvailableSkills()
371
- .filter((s) => !s.disableModelInvocation) || [];
372
- if (skills.length > 0) {
373
- const skillList = skills
374
- .map((s) => `- ${s.name}: ${s.description || ""}`)
375
- .join("\n");
376
- contextParts.push(`\n\n[Available Skills]\n${skillList}`);
367
+ // 4. Invoked skills context (with token budget, matching Claude Code)
368
+ const POST_COMPACT_SKILLS_TOKEN_BUDGET = 25_000;
369
+ const POST_COMPACT_MAX_TOKENS_PER_SKILL = 5_000;
370
+ const invokedSkillNames =
371
+ this.messageManager.getInvokedSkillNames(10);
372
+ if (invokedSkillNames.length > 0 && this.skillManager) {
373
+ const invokedSkillParts: string[] = [];
374
+ let skillsUsedTokens = 0;
375
+ for (const skillName of invokedSkillNames) {
376
+ try {
377
+ const skill = await this.skillManager.loadSkill(skillName);
378
+ if (!skill) continue;
379
+
380
+ // Extract content after frontmatter (matching prepareSkillContent pattern)
381
+ const contentMatch = skill.content.match(
382
+ /^---\n[\s\S]*?\n---\n([\s\S]*)$/,
383
+ );
384
+ let skillContent = contentMatch
385
+ ? contentMatch[1].trim()
386
+ : skill.content;
387
+
388
+ // Per-skill token budget enforcement (~4 chars per token)
389
+ const maxSkillChars = POST_COMPACT_MAX_TOKENS_PER_SKILL * 4;
390
+ if (skillContent.length > maxSkillChars) {
391
+ skillContent =
392
+ skillContent.slice(0, maxSkillChars) +
393
+ "\n\n...[truncated]...";
394
+ }
395
+
396
+ const skillTokens = Math.ceil(skillContent.length / 4);
397
+ if (
398
+ skillsUsedTokens + skillTokens >
399
+ POST_COMPACT_SKILLS_TOKEN_BUDGET
400
+ )
401
+ break;
402
+ skillsUsedTokens += skillTokens;
403
+
404
+ invokedSkillParts.push(
405
+ `\n\n## ${skill.name}\n${skill.description ? `*${skill.description}*\n\n` : ""}\`\`\`\n${skillContent}\n\`\`\``,
406
+ );
407
+ } catch {
408
+ // Skip skills that can't be loaded
409
+ }
410
+ }
411
+ if (invokedSkillParts.length > 0) {
412
+ contextParts.push(
413
+ `\n\n[Invoked Skills]\n${invokedSkillParts.join("")}`,
414
+ );
415
+ }
377
416
  }
378
417
 
379
- // 5. Background agents status
380
- const agents = this.backgroundTaskManager?.getAllTasks() || [];
418
+ // 5. Background subagent status (shell tasks excluded, matching Claude Code's createAsyncAgentAttachmentsIfNeeded)
419
+ const agents =
420
+ this.backgroundTaskManager
421
+ ?.getAllTasks()
422
+ .filter((a) => a.type === "subagent") || [];
381
423
  if (agents.length > 0) {
382
- const agentList = agents
383
- .map((a) => `- Agent "${a.description}": ${a.status}`)
384
- .join("\n");
385
- contextParts.push(`\n\n[Background Tasks]\n${agentList}`);
424
+ const agentParts: string[] = [];
425
+ for (const a of agents) {
426
+ if (a.status === "killed") {
427
+ agentParts.push(
428
+ `Task "${a.description}" (${a.id}) was stopped by the user.`,
429
+ );
430
+ } else if (a.status === "running") {
431
+ const parts = [
432
+ `Background agent "${a.description}" (${a.id}) is still running.`,
433
+ `Do NOT spawn a duplicate. You will be notified when it completes.`,
434
+ ];
435
+ if (a.outputPath) {
436
+ parts.push(`You can read partial output at ${a.outputPath}.`);
437
+ }
438
+ agentParts.push(parts.join(" "));
439
+ } else {
440
+ // completed or failed
441
+ const parts = [
442
+ `Task ${a.id} (status: ${a.status}) (description: ${a.description}).`,
443
+ ];
444
+ const deltaText = a.status === "failed" ? a.stderr : a.stdout;
445
+ if (deltaText && deltaText.length > 0) {
446
+ const summary =
447
+ deltaText.length > 500
448
+ ? deltaText.slice(0, 500) + "..."
449
+ : deltaText;
450
+ parts.push(`Delta: ${summary}`);
451
+ }
452
+ if (a.outputPath) {
453
+ parts.push(
454
+ `Read the output file to retrieve the result: ${a.outputPath}.`,
455
+ );
456
+ }
457
+ agentParts.push(parts.join(" "));
458
+ }
459
+ }
460
+ if (agentParts.length > 0) {
461
+ contextParts.push(
462
+ `\n\n[Background Tasks]\n${agentParts.join("\n")}`,
463
+ );
464
+ }
386
465
  }
387
466
 
388
467
  // Merge context restoration into summary
389
468
  const enhancedSummary =
390
- compressionResult.content +
469
+ compactResult.content +
391
470
  (contextParts.length > 0
392
471
  ? `\n\n[Context Restoration]` + contextParts.join("")
393
472
  : "");
394
473
 
395
- // Execute message reconstruction and sessionId update after compression
396
- this.messageManager.compressMessagesAndUpdateSession(
474
+ // Execute message reconstruction and sessionId update after compaction
475
+ this.messageManager.compactMessagesAndUpdateSession(
397
476
  enhancedSummary,
398
- compressionUsage,
477
+ compactUsage,
399
478
  );
400
479
 
401
480
  // Notify Agent to add to usage tracking
402
- if (compressionUsage && this.callbacks?.onUsageAdded) {
403
- this.callbacks.onUsageAdded(compressionUsage);
481
+ if (compactUsage && this.callbacks?.onUsageAdded) {
482
+ this.callbacks.onUsageAdded(compactUsage);
404
483
  }
405
484
 
406
485
  logger?.debug(
407
- `Successfully compressed ${messagesToCompress.length} messages and updated session`,
486
+ `Successfully compacted ${messagesToCompact.length} messages and updated session`,
408
487
  );
409
- this.consecutiveCompressionFailures = 0;
410
- } catch (compressError) {
411
- this.consecutiveCompressionFailures++;
488
+ this.consecutiveCompactionFailures = 0;
489
+ } catch (compactError) {
490
+ this.consecutiveCompactionFailures++;
412
491
  logger?.error(
413
- `Failed to compress messages (${this.consecutiveCompressionFailures} consecutive):`,
414
- compressError,
492
+ `Failed to compact messages (${this.consecutiveCompactionFailures} consecutive):`,
493
+ compactError,
415
494
  );
416
495
  this.messageManager.addErrorBlock(
417
- `Failed to compress conversation history: ${compressError instanceof Error ? compressError.message : String(compressError)}. You may encounter context limit issues.`,
496
+ `Failed to compact conversation history: ${compactError instanceof Error ? compactError.message : String(compactError)}. You may encounter context limit issues.`,
418
497
  );
419
498
  } finally {
420
- this.setIsCompressing(false);
499
+ this.setIsCompacting(false);
421
500
  }
422
501
  }
423
502
  }
424
503
  }
425
504
 
426
- public getIsCompressing(): boolean {
427
- return this.isCompressing;
505
+ public getIsCompacting(): boolean {
506
+ return this.isCompacting;
428
507
  }
429
508
 
430
- public setIsCompressing(isCompressing: boolean): void {
431
- if (this.isCompressing !== isCompressing) {
432
- this.isCompressing = isCompressing;
433
- this.callbacks.onCompressionStateChange?.(isCompressing);
509
+ public setIsCompacting(isCompacting: boolean): void {
510
+ if (this.isCompacting !== isCompacting) {
511
+ this.isCompacting = isCompacting;
512
+ this.callbacks.onCompactionStateChange?.(isCompacting);
434
513
  }
435
514
  }
436
515
 
@@ -914,8 +993,8 @@ export class AIManager {
914
993
  await Promise.all(toolExecutionPromises);
915
994
  }
916
995
 
917
- // Handle token statistics and message compression
918
- await this.handleTokenUsageAndCompression(result.usage, abortController);
996
+ // Handle token statistics and message compaction
997
+ await this.handleTokenUsageAndCompaction(result.usage, abortController);
919
998
 
920
999
  // Finalize text/reasoning blocks for the final response (no tools)
921
1000
  this.messageManager.finalizeStreamingBlocks();
@@ -153,22 +153,27 @@ export class BackgroundTaskManager {
153
153
  if (logStream.writable) {
154
154
  logStream.end();
155
155
  }
156
- shell.status = code === 0 ? "completed" : "failed";
156
+ const wasKilled = shell.status === "killed";
157
+ if (!wasKilled) {
158
+ shell.status = code === 0 ? "completed" : "failed";
159
+ }
157
160
  shell.exitCode = code ?? 0;
158
161
  shell.endTime = Date.now();
159
162
  shell.runtime = shell.endTime - startTime;
160
163
  this.notifyTasksChange();
161
164
 
162
- // Enqueue completion notification
163
- const notificationQueue = this.container.has("NotificationQueue")
164
- ? this.container.get<NotificationQueue>("NotificationQueue")
165
- : undefined;
166
- if (notificationQueue) {
167
- const statusStr = shell.status;
168
- const summary = `Command "${command}" ${statusStr} with exit code ${code ?? 0}`;
169
- notificationQueue.enqueue(
170
- `<task-notification>\n<task-id>${id}</task-id>\n<task-type>shell</task-type>\n<output-file>${logPath}</output-file>\n<status>${statusStr}</status>\n<summary>${summary}</summary>\n</task-notification>`,
171
- );
165
+ // Skip notification if task was manually killed (user/agent-initiated stop)
166
+ if (!wasKilled) {
167
+ const notificationQueue = this.container.has("NotificationQueue")
168
+ ? this.container.get<NotificationQueue>("NotificationQueue")
169
+ : undefined;
170
+ if (notificationQueue) {
171
+ const statusStr = shell.status;
172
+ const summary = `Command "${command}" ${statusStr} with exit code ${code ?? 0}`;
173
+ notificationQueue.enqueue(
174
+ `<task-notification>\n<task-id>${id}</task-id>\n<task-type>shell</task-type>\n<output-file>${logPath}</output-file>\n<status>${statusStr}</status>\n<summary>${summary}</summary>\n</task-notification>`,
175
+ );
176
+ }
172
177
  }
173
178
  };
174
179
 
@@ -301,22 +306,27 @@ export class BackgroundTaskManager {
301
306
  if (logStream.writable) {
302
307
  logStream.end();
303
308
  }
304
- shell.status = code === 0 ? "completed" : "failed";
309
+ const wasKilled = shell.status === "killed";
310
+ if (!wasKilled) {
311
+ shell.status = code === 0 ? "completed" : "failed";
312
+ }
305
313
  shell.exitCode = code ?? 0;
306
314
  shell.endTime = Date.now();
307
315
  shell.runtime = shell.endTime - startTime;
308
316
  this.notifyTasksChange();
309
317
 
310
- // Enqueue completion notification
311
- const notificationQueue = this.container.has("NotificationQueue")
312
- ? this.container.get<NotificationQueue>("NotificationQueue")
313
- : undefined;
314
- if (notificationQueue) {
315
- const statusStr = shell.status;
316
- const summary = `Command "${command}" ${statusStr} with exit code ${code ?? 0}`;
317
- notificationQueue.enqueue(
318
- `<task-notification>\n<task-id>${id}</task-id>\n<task-type>shell</task-type>\n<output-file>${logPath}</output-file>\n<status>${statusStr}</status>\n<summary>${summary}</summary>\n</task-notification>`,
319
- );
318
+ // Skip notification if task was manually killed (user/agent-initiated stop)
319
+ if (!wasKilled) {
320
+ const notificationQueue = this.container.has("NotificationQueue")
321
+ ? this.container.get<NotificationQueue>("NotificationQueue")
322
+ : undefined;
323
+ if (notificationQueue) {
324
+ const statusStr = shell.status;
325
+ const summary = `Command "${command}" ${statusStr} with exit code ${code ?? 0}`;
326
+ notificationQueue.enqueue(
327
+ `<task-notification>\n<task-id>${id}</task-id>\n<task-type>shell</task-type>\n<output-file>${logPath}</output-file>\n<status>${statusStr}</status>\n<summary>${summary}</summary>\n</task-notification>`,
328
+ );
329
+ }
320
330
  }
321
331
  });
322
332