@agentionai/agents 0.8.1 → 0.10.0

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.
@@ -1,19 +1,84 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.History = exports.isToolResultContent = exports.isToolUseContent = exports.isTextContent = exports.textMessage = exports.toolResult = exports.toolUse = exports.text = void 0;
39
+ exports.History = exports.isImageContent = exports.isImageBase64Content = exports.isImageUrlContent = exports.isToolResultContent = exports.isToolUseContent = exports.isTextContent = exports.imageBase64 = exports.imageUrl = exports.textMessage = exports.toolResult = exports.toolUse = exports.text = void 0;
40
+ exports.resetTokenxCache = resetTokenxCache;
7
41
  const events_1 = __importDefault(require("events"));
8
42
  const types_1 = require("./types");
43
+ // Cached tokenx estimator — starts as a character-based fallback and is
44
+ // replaced with the real tokenx implementation once the module loads.
45
+ let _estimateTokenCount = (t) => Math.ceil(t.length / 4);
46
+ void Promise.resolve().then(() => __importStar(require("tokenx"))).then((mod) => {
47
+ _estimateTokenCount = mod.estimateTokenCount;
48
+ })
49
+ .catch(() => {
50
+ /* keep fallback */
51
+ });
52
+ /** @internal — exposed for test teardown only */
53
+ function resetTokenxCache() {
54
+ _estimateTokenCount = (t) => Math.ceil(t.length / 4);
55
+ }
56
+ /**
57
+ * Estimate token count for a content block array.
58
+ * Image blocks use a flat 1000-token estimate (resolution-independent conservative value).
59
+ * Text and tool blocks fall through to the tokenx estimator.
60
+ */
61
+ function estimateContentTokens(content) {
62
+ return content.reduce((sum, block) => {
63
+ if ((0, types_1.isImageContent)(block)) {
64
+ return sum + 1000;
65
+ }
66
+ return sum + _estimateTokenCount(JSON.stringify(block));
67
+ }, 0);
68
+ }
9
69
  var types_2 = require("./types");
10
70
  Object.defineProperty(exports, "text", { enumerable: true, get: function () { return types_2.text; } });
11
71
  Object.defineProperty(exports, "toolUse", { enumerable: true, get: function () { return types_2.toolUse; } });
12
72
  Object.defineProperty(exports, "toolResult", { enumerable: true, get: function () { return types_2.toolResult; } });
13
73
  Object.defineProperty(exports, "textMessage", { enumerable: true, get: function () { return types_2.textMessage; } });
74
+ Object.defineProperty(exports, "imageUrl", { enumerable: true, get: function () { return types_2.imageUrl; } });
75
+ Object.defineProperty(exports, "imageBase64", { enumerable: true, get: function () { return types_2.imageBase64; } });
14
76
  Object.defineProperty(exports, "isTextContent", { enumerable: true, get: function () { return types_2.isTextContent; } });
15
77
  Object.defineProperty(exports, "isToolUseContent", { enumerable: true, get: function () { return types_2.isToolUseContent; } });
16
78
  Object.defineProperty(exports, "isToolResultContent", { enumerable: true, get: function () { return types_2.isToolResultContent; } });
79
+ Object.defineProperty(exports, "isImageUrlContent", { enumerable: true, get: function () { return types_2.isImageUrlContent; } });
80
+ Object.defineProperty(exports, "isImageBase64Content", { enumerable: true, get: function () { return types_2.isImageBase64Content; } });
81
+ Object.defineProperty(exports, "isImageContent", { enumerable: true, get: function () { return types_2.isImageContent; } });
17
82
  /**
18
83
  * Manages conversation history in a provider-agnostic format.
19
84
  *
@@ -23,6 +88,10 @@ Object.defineProperty(exports, "isToolResultContent", { enumerable: true, get: f
23
88
  * History can be shared between agents of different providers, enabling
24
89
  * cross-provider conversations and handoffs.
25
90
  *
91
+ * Plugins can be registered with `history.use(plugin)` to add read-time
92
+ * transforms (e.g., tool result masking) or async reduce strategies
93
+ * (e.g., rolling LLM summarization).
94
+ *
26
95
  * @example Basic usage
27
96
  * ```typescript
28
97
  * const history = new History();
@@ -30,6 +99,19 @@ Object.defineProperty(exports, "isToolResultContent", { enumerable: true, get: f
30
99
  * history.addText("assistant", "Hi there!");
31
100
  * ```
32
101
  *
102
+ * @example With tool result masking plugin
103
+ * ```typescript
104
+ * import { toolResultMaskingPlugin } from "agention-lib/history/plugins";
105
+ *
106
+ * const maskingPlugin = toolResultMaskingPlugin({ keepRecentResults: 2 });
107
+ * const history = new History().use(maskingPlugin);
108
+ *
109
+ * const agent = new ClaudeAgent(
110
+ * { tools: [maskingPlugin.retrieveTool, ...otherTools] },
111
+ * history
112
+ * );
113
+ * ```
114
+ *
33
115
  * @example Sharing between agents
34
116
  * ```typescript
35
117
  * const history = new History();
@@ -43,6 +125,8 @@ class History extends events_1.default {
43
125
  super();
44
126
  this._entries = [];
45
127
  this.transient = false;
128
+ this._plugins = [];
129
+ this._reducing = false;
46
130
  this.options = options;
47
131
  this.transient = Boolean(options?.transient);
48
132
  // Convert initial entries to internal format with metadata
@@ -50,13 +134,39 @@ class History extends events_1.default {
50
134
  this.addEntry(entry);
51
135
  }
52
136
  }
137
+ // ===========================================================================
138
+ // Plugin registration
139
+ // ===========================================================================
140
+ /**
141
+ * Register a plugin with this history instance.
142
+ * Calls plugin.onRegistered(this) immediately after registration.
143
+ * Returns `this` for chaining.
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * history
148
+ * .use(compressionPlugin(summaryAgent))
149
+ * .use(toolResultMaskingPlugin({ keepRecentResults: 2 }));
150
+ * ```
151
+ */
152
+ use(plugin) {
153
+ this._plugins.push(plugin);
154
+ plugin.onRegistered?.(this);
155
+ return this;
156
+ }
157
+ // ===========================================================================
158
+ // Core write operations
159
+ // ===========================================================================
53
160
  /**
54
161
  * Add a complete history entry
55
162
  */
56
163
  addEntry(entry) {
164
+ const serialized = JSON.stringify(entry.content);
165
+ const contentLength = serialized.length;
57
166
  const __metadata = {
58
167
  date: new Date().toISOString(),
59
- contentLength: JSON.stringify(entry.content).length,
168
+ contentLength,
169
+ estimatedTokens: estimateContentTokens(entry.content),
60
170
  };
61
171
  this._entries.push({
62
172
  ...entry,
@@ -65,7 +175,27 @@ class History extends events_1.default {
65
175
  if (this.options.maxLength && this._entries.length > this.options.maxLength) {
66
176
  this._entries = this._entries.slice(this._entries.length - this.options.maxLength);
67
177
  }
178
+ if (this.options.maxTokens) {
179
+ this.trimToTokenBudget();
180
+ }
68
181
  this.emit("entry", entry);
182
+ // Fire plugin afterAdd hooks. Skipped during reduce() to avoid recursion
183
+ // when compression plugins add summary entries to the history.
184
+ if (!this._reducing) {
185
+ for (const plugin of this._plugins) {
186
+ if (!plugin.afterAdd)
187
+ continue;
188
+ void Promise.resolve(plugin.afterAdd(this)).catch((err) => {
189
+ const error = err instanceof Error ? err : new Error(String(err));
190
+ if (this.options.onPluginError) {
191
+ this.options.onPluginError(error, plugin, "afterAdd");
192
+ }
193
+ else {
194
+ this.emit("pluginError", error, plugin, "afterAdd");
195
+ }
196
+ });
197
+ }
198
+ }
69
199
  }
70
200
  /**
71
201
  * Add a simple text message
@@ -88,8 +218,28 @@ class History extends events_1.default {
88
218
  addSystem(content) {
89
219
  this.addText("system", content);
90
220
  }
221
+ // ===========================================================================
222
+ // Read operations
223
+ // ===========================================================================
224
+ /**
225
+ * Get entries as agents should see them — with all registered transform
226
+ * plugins applied in registration order.
227
+ *
228
+ * Use this when building API requests. The raw `entries` getter is
229
+ * reserved for serialization, cloning, and other internal purposes.
230
+ */
231
+ getEntries() {
232
+ let entries = this._entries;
233
+ for (const plugin of this._plugins) {
234
+ if (plugin.transform) {
235
+ entries = plugin.transform(entries);
236
+ }
237
+ }
238
+ return entries.map(({ __metadata, ...rest }) => rest);
239
+ }
91
240
  /**
92
- * Get all entries (without internal metadata)
241
+ * Get all entries without transform plugins applied (raw storage).
242
+ * Use for serialization, cloning, and debugging.
93
243
  */
94
244
  get entries() {
95
245
  return this._entries.map((entry) => {
@@ -97,6 +247,24 @@ class History extends events_1.default {
97
247
  return rest;
98
248
  });
99
249
  }
250
+ /**
251
+ * Get the full content of a tool result by its tool_use_id.
252
+ * Always reads from raw stored entries — never affected by transform plugins.
253
+ *
254
+ * For RedisHistory: call await load() before using this method.
255
+ *
256
+ * @returns The full result string, or undefined if not found.
257
+ */
258
+ getToolResult(tool_use_id) {
259
+ for (const entry of this._entries) {
260
+ for (const block of entry.content) {
261
+ if ((0, types_1.isToolResultContent)(block) && block.tool_use_id === tool_use_id) {
262
+ return block.content;
263
+ }
264
+ }
265
+ }
266
+ return undefined;
267
+ }
100
268
  /**
101
269
  * Get the number of entries
102
270
  */
@@ -111,6 +279,15 @@ class History extends events_1.default {
111
279
  return total + __metadata.contentLength;
112
280
  }, 0);
113
281
  }
282
+ /**
283
+ * Get total estimated token count across all entries.
284
+ * Uses a rough approximation of 1 token ≈ 4 characters.
285
+ */
286
+ get totalEstimatedTokens() {
287
+ return this._entries.reduce((total, { __metadata }) => {
288
+ return total + __metadata.estimatedTokens;
289
+ }, 0);
290
+ }
114
291
  /**
115
292
  * Get the last entry
116
293
  */
@@ -133,11 +310,52 @@ class History extends events_1.default {
133
310
  .join("\n");
134
311
  }
135
312
  /**
136
- * Get entries without system messages
313
+ * Get entries without system messages, with transform plugins applied.
137
314
  */
138
315
  getMessagesWithoutSystem() {
139
- return this.entries.filter((e) => e.role !== "system");
316
+ return this.getEntries().filter((e) => e.role !== "system");
317
+ }
318
+ // ===========================================================================
319
+ // Async reduction
320
+ // ===========================================================================
321
+ /**
322
+ * Asynchronously compact history using registered reduce plugins.
323
+ *
324
+ * Plugins are called in registration order, each receiving and returning
325
+ * the full entry array. If no plugin has a `reduce` hook, this is a no-op —
326
+ * the addEntry() safety net (FIFO drop via maxTokens) runs independently.
327
+ *
328
+ * Re-entrant calls during an in-progress reduce() return immediately.
329
+ *
330
+ * @example Rolling summarization
331
+ * ```typescript
332
+ * history.use(compressionPlugin(summaryAgent));
333
+ * await history.reduce({ maxTokens: 4000 });
334
+ * ```
335
+ */
336
+ async reduce(options = {}) {
337
+ if (this._reducing)
338
+ return;
339
+ const hasReducePlugin = this._plugins.some((p) => Boolean(p.reduce));
340
+ if (!hasReducePlugin)
341
+ return;
342
+ this._reducing = true;
343
+ try {
344
+ let entries = [...this._entries];
345
+ for (const plugin of this._plugins) {
346
+ if (plugin.reduce) {
347
+ entries = await plugin.reduce(entries, options);
348
+ }
349
+ }
350
+ this._entries = entries;
351
+ }
352
+ finally {
353
+ this._reducing = false;
354
+ }
140
355
  }
356
+ // ===========================================================================
357
+ // Utility
358
+ // ===========================================================================
141
359
  /**
142
360
  * Clear all history entries
143
361
  */
@@ -164,6 +382,25 @@ class History extends events_1.default {
164
382
  clone(options) {
165
383
  return new History(this.entries, options ?? this.options);
166
384
  }
385
+ // ===========================================================================
386
+ // Private helpers
387
+ // ===========================================================================
388
+ /**
389
+ * Drop oldest non-system entries until totalEstimatedTokens fits within budget.
390
+ * Called synchronously from addEntry() as a safety net.
391
+ * The system message is always preserved.
392
+ */
393
+ trimToTokenBudget(maxTokens) {
394
+ const budget = maxTokens ?? this.options.maxTokens;
395
+ if (!budget)
396
+ return;
397
+ while (this.totalEstimatedTokens > budget && this._entries.length > 1) {
398
+ const firstNonSystem = this._entries.findIndex((e) => e.role !== "system");
399
+ if (firstNonSystem === -1)
400
+ break;
401
+ this._entries.splice(firstNonSystem, 1);
402
+ }
403
+ }
167
404
  }
168
405
  exports.History = History;
169
406
  //# sourceMappingURL=History.js.map
@@ -0,0 +1,5 @@
1
+ export { History, resetTokenxCache, type EntryMetadata, type ReducibleEntry, type HistoryPlugin, } from "./History";
2
+ export { RedisHistory } from "./RedisHistory";
3
+ export type { HistoryEntry, MessageRole, MessageContent, TextContent, ToolUseContent, ToolResultContent, ProviderMeta, ReduceOptions, } from "./types";
4
+ export { text, toolUse, toolResult, textMessage, isTextContent, isToolUseContent, isToolResultContent, } from "./types";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isToolResultContent = exports.isToolUseContent = exports.isTextContent = exports.textMessage = exports.toolResult = exports.toolUse = exports.text = exports.RedisHistory = exports.resetTokenxCache = exports.History = void 0;
4
+ var History_1 = require("./History");
5
+ Object.defineProperty(exports, "History", { enumerable: true, get: function () { return History_1.History; } });
6
+ Object.defineProperty(exports, "resetTokenxCache", { enumerable: true, get: function () { return History_1.resetTokenxCache; } });
7
+ var RedisHistory_1 = require("./RedisHistory");
8
+ Object.defineProperty(exports, "RedisHistory", { enumerable: true, get: function () { return RedisHistory_1.RedisHistory; } });
9
+ var types_1 = require("./types");
10
+ Object.defineProperty(exports, "text", { enumerable: true, get: function () { return types_1.text; } });
11
+ Object.defineProperty(exports, "toolUse", { enumerable: true, get: function () { return types_1.toolUse; } });
12
+ Object.defineProperty(exports, "toolResult", { enumerable: true, get: function () { return types_1.toolResult; } });
13
+ Object.defineProperty(exports, "textMessage", { enumerable: true, get: function () { return types_1.textMessage; } });
14
+ Object.defineProperty(exports, "isTextContent", { enumerable: true, get: function () { return types_1.isTextContent; } });
15
+ Object.defineProperty(exports, "isToolUseContent", { enumerable: true, get: function () { return types_1.isToolUseContent; } });
16
+ Object.defineProperty(exports, "isToolResultContent", { enumerable: true, get: function () { return types_1.isToolResultContent; } });
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,54 @@
1
+ import type { ReduceOptions } from "../types";
2
+ import type { HistoryPlugin } from "../History";
3
+ import type { BaseAgent } from "../../agents/BaseAgent";
4
+ /** Options for {@link compressionPlugin}. */
5
+ export type CompressionPluginOptions = {
6
+ /**
7
+ * When set, the plugin automatically calls `history.reduce()` from its
8
+ * `afterAdd` hook whenever the history exceeds the given threshold.
9
+ * The same `ReduceOptions` object is forwarded to `reduce()`.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * history.use(compressionPlugin(summaryAgent, { autoReduceWhen: { maxTokens: 6000 } }));
14
+ * ```
15
+ */
16
+ autoReduceWhen?: ReduceOptions;
17
+ };
18
+ /**
19
+ * Creates a rolling-summary compression plugin.
20
+ *
21
+ * When `history.reduce(options)` is called, this plugin compresses old entries
22
+ * into a single summary entry using the provided agent. On subsequent reduces,
23
+ * the existing summary is included as prior context so the agent can extend it
24
+ * (rolling strategy) — at most one summary entry exists at any time.
25
+ *
26
+ * The summary entry uses `role: "user"` because no LLM provider has a
27
+ * dedicated summary role. Content is always wrapped as
28
+ * `[Earlier conversation summary: ...]` so it can be detected by pattern
29
+ * as well as the `isSummary` metadata flag.
30
+ *
31
+ * Pass `autoReduceWhen` to trigger compression automatically after every
32
+ * `addEntry()` call when the given threshold is exceeded — no manual
33
+ * `history.reduce()` call required.
34
+ *
35
+ * @example
36
+ * ```typescript
37
+ * const summaryAgent = new ClaudeAgent({
38
+ * id: "summarizer",
39
+ * name: "Summarizer",
40
+ * description: "Summarizes conversation history",
41
+ * apiKey: process.env.ANTHROPIC_API_KEY!,
42
+ * model: "claude-haiku-4-5-20251001",
43
+ * });
44
+ *
45
+ * // Manual trigger
46
+ * history.use(compressionPlugin(summaryAgent));
47
+ * await history.reduce({ maxTokens: 4000 });
48
+ *
49
+ * // Automatic trigger
50
+ * history.use(compressionPlugin(summaryAgent, { autoReduceWhen: { maxTokens: 6000 } }));
51
+ * ```
52
+ */
53
+ export declare function compressionPlugin(agent: BaseAgent, options?: CompressionPluginOptions): HistoryPlugin;
54
+ //# sourceMappingURL=compressionPlugin.d.ts.map
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.compressionPlugin = compressionPlugin;
4
+ const types_1 = require("../types");
5
+ /**
6
+ * Creates a rolling-summary compression plugin.
7
+ *
8
+ * When `history.reduce(options)` is called, this plugin compresses old entries
9
+ * into a single summary entry using the provided agent. On subsequent reduces,
10
+ * the existing summary is included as prior context so the agent can extend it
11
+ * (rolling strategy) — at most one summary entry exists at any time.
12
+ *
13
+ * The summary entry uses `role: "user"` because no LLM provider has a
14
+ * dedicated summary role. Content is always wrapped as
15
+ * `[Earlier conversation summary: ...]` so it can be detected by pattern
16
+ * as well as the `isSummary` metadata flag.
17
+ *
18
+ * Pass `autoReduceWhen` to trigger compression automatically after every
19
+ * `addEntry()` call when the given threshold is exceeded — no manual
20
+ * `history.reduce()` call required.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * const summaryAgent = new ClaudeAgent({
25
+ * id: "summarizer",
26
+ * name: "Summarizer",
27
+ * description: "Summarizes conversation history",
28
+ * apiKey: process.env.ANTHROPIC_API_KEY!,
29
+ * model: "claude-haiku-4-5-20251001",
30
+ * });
31
+ *
32
+ * // Manual trigger
33
+ * history.use(compressionPlugin(summaryAgent));
34
+ * await history.reduce({ maxTokens: 4000 });
35
+ *
36
+ * // Automatic trigger
37
+ * history.use(compressionPlugin(summaryAgent, { autoReduceWhen: { maxTokens: 6000 } }));
38
+ * ```
39
+ */
40
+ function compressionPlugin(agent, options = {}) {
41
+ const { autoReduceWhen } = options;
42
+ function shouldAutoReduce(history) {
43
+ if (!autoReduceWhen)
44
+ return false;
45
+ if (autoReduceWhen.maxTokens !== undefined) {
46
+ return history.totalEstimatedTokens > autoReduceWhen.maxTokens;
47
+ }
48
+ if (autoReduceWhen.maxEntries !== undefined) {
49
+ return history.length > autoReduceWhen.maxEntries;
50
+ }
51
+ // olderThan: always trigger so reduce() can evaluate
52
+ if (autoReduceWhen.olderThan !== undefined)
53
+ return true;
54
+ return false;
55
+ }
56
+ return {
57
+ afterAdd(history) {
58
+ if (!autoReduceWhen)
59
+ return;
60
+ if (!shouldAutoReduce(history))
61
+ return;
62
+ // Fire-and-forget — History._reducing guard prevents re-entrancy
63
+ void history.reduce(autoReduceWhen);
64
+ },
65
+ async reduce(entries, options) {
66
+ const { maxTokens, maxEntries, olderThan } = options;
67
+ // Separate system entries — always preserved verbatim
68
+ const systemEntries = entries.filter((e) => e.role === "system");
69
+ const nonSystemEntries = entries.filter((e) => e.role !== "system");
70
+ if (nonSystemEntries.length === 0)
71
+ return entries;
72
+ // Determine which non-system entries to compress
73
+ let toCompress = [];
74
+ if (olderThan) {
75
+ const cutoff = olderThan.toISOString();
76
+ toCompress = nonSystemEntries.filter((e) => e.__metadata.date < cutoff);
77
+ }
78
+ else if (maxEntries !== undefined) {
79
+ const totalNonSystem = nonSystemEntries.length;
80
+ if (totalNonSystem <= maxEntries)
81
+ return entries;
82
+ toCompress = nonSystemEntries.slice(0, totalNonSystem - maxEntries);
83
+ }
84
+ else if (maxTokens !== undefined) {
85
+ // Accumulate from oldest until we'd fit within budget
86
+ let totalTokens = entries.reduce((sum, e) => sum + e.__metadata.estimatedTokens, 0);
87
+ let i = 0;
88
+ while (totalTokens > maxTokens && i < nonSystemEntries.length) {
89
+ toCompress.push(nonSystemEntries[i]);
90
+ totalTokens -= nonSystemEntries[i].__metadata.estimatedTokens;
91
+ i++;
92
+ }
93
+ }
94
+ if (toCompress.length === 0)
95
+ return entries;
96
+ // Build prompt — include existing rolling summary as prior context
97
+ const existingSummary = toCompress.find((e) => e.__metadata.isSummary);
98
+ const rawToCompress = toCompress.filter((e) => !e.__metadata.isSummary);
99
+ let prompt = "Produce a concise summary of the following conversation. " +
100
+ "Preserve key facts, decisions, and outcomes. " +
101
+ "Omit filler and repetition.\n\n";
102
+ if (existingSummary) {
103
+ const summaryText = existingSummary.content
104
+ .filter(types_1.isTextContent)
105
+ .map((c) => c.text)
106
+ .join("\n");
107
+ prompt += `Prior context:\n${summaryText}\n\nAdditional turns to incorporate:\n`;
108
+ }
109
+ for (const entry of rawToCompress) {
110
+ const lines = entry.content
111
+ .filter(types_1.isTextContent)
112
+ .map((c) => c.text)
113
+ .join(" ");
114
+ prompt += `[${entry.role}]: ${lines}\n`;
115
+ }
116
+ const summaryText = await agent.execute(prompt);
117
+ // Determine date range covered by this summary
118
+ const allCompressed = existingSummary
119
+ ? [existingSummary, ...rawToCompress]
120
+ : rawToCompress;
121
+ const earliestDate = existingSummary?.__metadata.coversRange?.from ??
122
+ allCompressed[0].__metadata.date;
123
+ const latestDate = allCompressed[allCompressed.length - 1].__metadata.date;
124
+ const content = `[Earlier conversation summary: ${summaryText}]`;
125
+ const __metadata = {
126
+ date: new Date().toISOString(),
127
+ contentLength: content.length,
128
+ estimatedTokens: Math.ceil(content.length / 4),
129
+ isSummary: true,
130
+ coversRange: { from: earliestDate, to: latestDate },
131
+ };
132
+ const summaryEntry = {
133
+ role: "user",
134
+ content: [(0, types_1.text)(content)],
135
+ __metadata,
136
+ };
137
+ const toCompressSet = new Set(toCompress);
138
+ const recent = nonSystemEntries.filter((e) => !toCompressSet.has(e));
139
+ return [...systemEntries, summaryEntry, ...recent];
140
+ },
141
+ };
142
+ }
143
+ //# sourceMappingURL=compressionPlugin.js.map
@@ -0,0 +1,3 @@
1
+ export { compressionPlugin, type CompressionPluginOptions } from "./compressionPlugin";
2
+ export { toolResultMaskingPlugin, type ToolResultMaskingPlugin, type ToolResultMaskingOptions, } from "./toolResultMaskingPlugin";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.toolResultMaskingPlugin = exports.compressionPlugin = void 0;
4
+ var compressionPlugin_1 = require("./compressionPlugin");
5
+ Object.defineProperty(exports, "compressionPlugin", { enumerable: true, get: function () { return compressionPlugin_1.compressionPlugin; } });
6
+ var toolResultMaskingPlugin_1 = require("./toolResultMaskingPlugin");
7
+ Object.defineProperty(exports, "toolResultMaskingPlugin", { enumerable: true, get: function () { return toolResultMaskingPlugin_1.toolResultMaskingPlugin; } });
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,66 @@
1
+ import { Tool } from "../../tools/Tool";
2
+ import type { HistoryPlugin } from "../History";
3
+ export type ToolResultMaskingOptions = {
4
+ /**
5
+ * Number of most-recent tool results to keep verbatim.
6
+ * Older results are replaced with a reference marker.
7
+ * @default 2
8
+ */
9
+ keepRecentResults?: number;
10
+ /**
11
+ * Tool names that are never masked, regardless of age or size.
12
+ * Mutually exclusive with `include`.
13
+ */
14
+ exclude?: string[];
15
+ /**
16
+ * When set, only results from these tools are masked.
17
+ * Mutually exclusive with `exclude`.
18
+ */
19
+ include?: string[];
20
+ /**
21
+ * Skip masking for results whose estimated token count is below this
22
+ * threshold. Small results don't consume a `keepRecentResults` slot.
23
+ */
24
+ minTokensToMask?: number;
25
+ };
26
+ /**
27
+ * A HistoryPlugin with an attached `retrieveTool`.
28
+ * Register the plugin with `history.use(maskingPlugin)`, then add
29
+ * `maskingPlugin.retrieveTool` to the agent's tool list so the model can
30
+ * fetch masked results on demand.
31
+ */
32
+ export type ToolResultMaskingPlugin = HistoryPlugin & {
33
+ /** Tool the agent can call to retrieve a masked result by its tool_use_id. */
34
+ readonly retrieveTool: Tool<string>;
35
+ };
36
+ /**
37
+ * Creates a read-time tool result masking plugin.
38
+ *
39
+ * Old tool results are replaced with a reference marker `[MASKED - ref: <id>]`
40
+ * at read time via `history.getEntries()`. Stored entries are never mutated —
41
+ * the full content is always available via `history.getToolResult(id)` or the
42
+ * attached `retrieveTool`.
43
+ *
44
+ * Only results that pass the include/exclude/minTokensToMask filters are
45
+ * candidates for masking. Filtered-out results stay verbatim and do not
46
+ * consume a `keepRecentResults` slot.
47
+ *
48
+ * @throws If both `exclude` and `include` are provided.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const maskingPlugin = toolResultMaskingPlugin({
53
+ * keepRecentResults: 2,
54
+ * exclude: ["calculator", "get_date"],
55
+ * minTokensToMask: 50,
56
+ * });
57
+ *
58
+ * history.use(maskingPlugin);
59
+ *
60
+ * const agent = new ClaudeAgent({
61
+ * tools: [maskingPlugin.retrieveTool, ...otherTools],
62
+ * }, history);
63
+ * ```
64
+ */
65
+ export declare function toolResultMaskingPlugin(options?: ToolResultMaskingOptions): ToolResultMaskingPlugin;
66
+ //# sourceMappingURL=toolResultMaskingPlugin.d.ts.map