llmist 1.2.0 → 1.3.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.
@@ -348,10 +348,21 @@ function resolveRulesTemplate(rules, context) {
348
348
  }
349
349
  return [resolved];
350
350
  }
351
- var DEFAULT_PROMPTS;
351
+ function resolveHintTemplate(template, defaultValue, context) {
352
+ const resolved = template ?? defaultValue;
353
+ if (typeof resolved === "function") {
354
+ return resolved(context);
355
+ }
356
+ return resolved.replace(/\{iteration\}/g, String(context.iteration)).replace(/\{maxIterations\}/g, String(context.maxIterations)).replace(/\{remaining\}/g, String(context.remaining));
357
+ }
358
+ var DEFAULT_HINTS, DEFAULT_PROMPTS;
352
359
  var init_prompt_config = __esm({
353
360
  "src/core/prompt-config.ts"() {
354
361
  "use strict";
362
+ DEFAULT_HINTS = {
363
+ parallelGadgetsHint: "Tip: You can call multiple gadgets in a single response for efficiency.",
364
+ iterationProgressHint: "[Iteration {iteration}/{maxIterations}] Plan your actions accordingly."
365
+ };
355
366
  DEFAULT_PROMPTS = {
356
367
  mainInstruction: [
357
368
  "\u26A0\uFE0F CRITICAL: RESPOND ONLY WITH GADGET INVOCATIONS",
@@ -1116,6 +1127,417 @@ var init_output_viewer = __esm({
1116
1127
  }
1117
1128
  });
1118
1129
 
1130
+ // src/agent/compaction/config.ts
1131
+ function resolveCompactionConfig(config = {}) {
1132
+ const trigger = config.triggerThresholdPercent ?? DEFAULT_COMPACTION_CONFIG.triggerThresholdPercent;
1133
+ const target = config.targetPercent ?? DEFAULT_COMPACTION_CONFIG.targetPercent;
1134
+ if (target >= trigger) {
1135
+ console.warn(
1136
+ `[llmist/compaction] targetPercent (${target}) should be less than triggerThresholdPercent (${trigger}) to be effective.`
1137
+ );
1138
+ }
1139
+ const strategy = config.strategy ?? DEFAULT_COMPACTION_CONFIG.strategy;
1140
+ const strategyName = typeof strategy === "object" && "name" in strategy ? strategy.name : strategy;
1141
+ return {
1142
+ enabled: config.enabled ?? DEFAULT_COMPACTION_CONFIG.enabled,
1143
+ strategy: strategyName,
1144
+ triggerThresholdPercent: trigger,
1145
+ targetPercent: target,
1146
+ preserveRecentTurns: config.preserveRecentTurns ?? DEFAULT_COMPACTION_CONFIG.preserveRecentTurns,
1147
+ summarizationModel: config.summarizationModel,
1148
+ summarizationPrompt: config.summarizationPrompt ?? DEFAULT_SUMMARIZATION_PROMPT,
1149
+ onCompaction: config.onCompaction
1150
+ };
1151
+ }
1152
+ var DEFAULT_COMPACTION_CONFIG, DEFAULT_SUMMARIZATION_PROMPT;
1153
+ var init_config = __esm({
1154
+ "src/agent/compaction/config.ts"() {
1155
+ "use strict";
1156
+ DEFAULT_COMPACTION_CONFIG = {
1157
+ enabled: true,
1158
+ strategy: "hybrid",
1159
+ triggerThresholdPercent: 80,
1160
+ targetPercent: 50,
1161
+ preserveRecentTurns: 5
1162
+ };
1163
+ DEFAULT_SUMMARIZATION_PROMPT = `Summarize this conversation history concisely, preserving:
1164
+ 1. Key decisions made and their rationale
1165
+ 2. Important facts and data discovered
1166
+ 3. Errors encountered and how they were resolved
1167
+ 4. Current task context and goals
1168
+
1169
+ Format as a brief narrative paragraph, not bullet points.
1170
+ Previous conversation:`;
1171
+ }
1172
+ });
1173
+
1174
+ // src/agent/compaction/strategy.ts
1175
+ function groupIntoTurns(messages) {
1176
+ const turns = [];
1177
+ let currentTurn = [];
1178
+ for (const msg of messages) {
1179
+ if (msg.role === "user" && currentTurn.length > 0) {
1180
+ turns.push({
1181
+ messages: currentTurn,
1182
+ tokenEstimate: estimateTurnTokens(currentTurn)
1183
+ });
1184
+ currentTurn = [msg];
1185
+ } else {
1186
+ currentTurn.push(msg);
1187
+ }
1188
+ }
1189
+ if (currentTurn.length > 0) {
1190
+ turns.push({
1191
+ messages: currentTurn,
1192
+ tokenEstimate: estimateTurnTokens(currentTurn)
1193
+ });
1194
+ }
1195
+ return turns;
1196
+ }
1197
+ function estimateTurnTokens(messages) {
1198
+ return Math.ceil(messages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4);
1199
+ }
1200
+ function flattenTurns(turns) {
1201
+ return turns.flatMap((turn) => turn.messages);
1202
+ }
1203
+ var init_strategy = __esm({
1204
+ "src/agent/compaction/strategy.ts"() {
1205
+ "use strict";
1206
+ }
1207
+ });
1208
+
1209
+ // src/agent/compaction/strategies/sliding-window.ts
1210
+ var TRUNCATION_MARKER_TEMPLATE, SlidingWindowStrategy;
1211
+ var init_sliding_window = __esm({
1212
+ "src/agent/compaction/strategies/sliding-window.ts"() {
1213
+ "use strict";
1214
+ init_strategy();
1215
+ TRUNCATION_MARKER_TEMPLATE = "[Previous conversation truncated. Removed {count} turn(s) to fit context window.]";
1216
+ SlidingWindowStrategy = class {
1217
+ name = "sliding-window";
1218
+ async compact(messages, config, context) {
1219
+ const turns = groupIntoTurns(messages);
1220
+ const preserveCount = Math.min(config.preserveRecentTurns, turns.length);
1221
+ if (turns.length <= preserveCount) {
1222
+ return {
1223
+ messages,
1224
+ strategyName: this.name,
1225
+ metadata: {
1226
+ originalCount: messages.length,
1227
+ compactedCount: messages.length,
1228
+ tokensBefore: context.currentTokens,
1229
+ tokensAfter: context.currentTokens
1230
+ }
1231
+ };
1232
+ }
1233
+ const turnsToKeep = turns.slice(-preserveCount);
1234
+ const turnsRemoved = turns.length - preserveCount;
1235
+ const truncationMarker = {
1236
+ role: "user",
1237
+ content: TRUNCATION_MARKER_TEMPLATE.replace("{count}", turnsRemoved.toString())
1238
+ };
1239
+ const compactedMessages = [truncationMarker, ...flattenTurns(turnsToKeep)];
1240
+ const tokensAfter = Math.ceil(
1241
+ compactedMessages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4
1242
+ );
1243
+ return {
1244
+ messages: compactedMessages,
1245
+ strategyName: this.name,
1246
+ metadata: {
1247
+ originalCount: messages.length,
1248
+ compactedCount: compactedMessages.length,
1249
+ tokensBefore: context.currentTokens,
1250
+ tokensAfter
1251
+ }
1252
+ };
1253
+ }
1254
+ };
1255
+ }
1256
+ });
1257
+
1258
+ // src/agent/compaction/strategies/summarization.ts
1259
+ var SummarizationStrategy;
1260
+ var init_summarization = __esm({
1261
+ "src/agent/compaction/strategies/summarization.ts"() {
1262
+ "use strict";
1263
+ init_strategy();
1264
+ SummarizationStrategy = class {
1265
+ name = "summarization";
1266
+ async compact(messages, config, context) {
1267
+ const turns = groupIntoTurns(messages);
1268
+ const preserveCount = Math.min(config.preserveRecentTurns, turns.length);
1269
+ if (turns.length <= preserveCount) {
1270
+ return {
1271
+ messages,
1272
+ strategyName: this.name,
1273
+ metadata: {
1274
+ originalCount: messages.length,
1275
+ compactedCount: messages.length,
1276
+ tokensBefore: context.currentTokens,
1277
+ tokensAfter: context.currentTokens
1278
+ }
1279
+ };
1280
+ }
1281
+ const turnsToSummarize = turns.slice(0, -preserveCount);
1282
+ const turnsToKeep = turns.slice(-preserveCount);
1283
+ const conversationToSummarize = this.formatTurnsForSummary(flattenTurns(turnsToSummarize));
1284
+ const summary = await this.generateSummary(conversationToSummarize, config, context);
1285
+ const summaryMessage = {
1286
+ role: "user",
1287
+ content: `[Previous conversation summary]
1288
+ ${summary}
1289
+ [End of summary - conversation continues below]`
1290
+ };
1291
+ const compactedMessages = [summaryMessage, ...flattenTurns(turnsToKeep)];
1292
+ const tokensAfter = Math.ceil(
1293
+ compactedMessages.reduce((sum, msg) => sum + (msg.content?.length ?? 0), 0) / 4
1294
+ );
1295
+ return {
1296
+ messages: compactedMessages,
1297
+ summary,
1298
+ strategyName: this.name,
1299
+ metadata: {
1300
+ originalCount: messages.length,
1301
+ compactedCount: compactedMessages.length,
1302
+ tokensBefore: context.currentTokens,
1303
+ tokensAfter
1304
+ }
1305
+ };
1306
+ }
1307
+ /**
1308
+ * Formats messages into a readable conversation format for summarization.
1309
+ */
1310
+ formatTurnsForSummary(messages) {
1311
+ return messages.map((msg) => {
1312
+ const role = msg.role.charAt(0).toUpperCase() + msg.role.slice(1);
1313
+ return `${role}: ${msg.content}`;
1314
+ }).join("\n\n");
1315
+ }
1316
+ /**
1317
+ * Generates a summary using the configured LLM.
1318
+ */
1319
+ async generateSummary(conversation, config, context) {
1320
+ const model = config.summarizationModel ?? context.model;
1321
+ const prompt = `${config.summarizationPrompt}
1322
+
1323
+ ${conversation}`;
1324
+ const response = await context.client.complete(prompt, {
1325
+ model,
1326
+ temperature: 0.3
1327
+ // Low temperature for factual summarization
1328
+ });
1329
+ return response.trim();
1330
+ }
1331
+ };
1332
+ }
1333
+ });
1334
+
1335
+ // src/agent/compaction/strategies/hybrid.ts
1336
+ var MIN_TURNS_FOR_SUMMARIZATION, HybridStrategy;
1337
+ var init_hybrid = __esm({
1338
+ "src/agent/compaction/strategies/hybrid.ts"() {
1339
+ "use strict";
1340
+ init_strategy();
1341
+ init_sliding_window();
1342
+ init_summarization();
1343
+ MIN_TURNS_FOR_SUMMARIZATION = 3;
1344
+ HybridStrategy = class {
1345
+ name = "hybrid";
1346
+ slidingWindow = new SlidingWindowStrategy();
1347
+ summarization = new SummarizationStrategy();
1348
+ async compact(messages, config, context) {
1349
+ const turns = groupIntoTurns(messages);
1350
+ const preserveCount = Math.min(config.preserveRecentTurns, turns.length);
1351
+ if (turns.length <= preserveCount) {
1352
+ return {
1353
+ messages,
1354
+ strategyName: this.name,
1355
+ metadata: {
1356
+ originalCount: messages.length,
1357
+ compactedCount: messages.length,
1358
+ tokensBefore: context.currentTokens,
1359
+ tokensAfter: context.currentTokens
1360
+ }
1361
+ };
1362
+ }
1363
+ const turnsToSummarize = turns.length - preserveCount;
1364
+ if (turnsToSummarize < MIN_TURNS_FOR_SUMMARIZATION) {
1365
+ return this.slidingWindow.compact(messages, config, context);
1366
+ }
1367
+ return this.summarization.compact(messages, config, context);
1368
+ }
1369
+ };
1370
+ }
1371
+ });
1372
+
1373
+ // src/agent/compaction/strategies/index.ts
1374
+ var init_strategies = __esm({
1375
+ "src/agent/compaction/strategies/index.ts"() {
1376
+ "use strict";
1377
+ init_sliding_window();
1378
+ init_summarization();
1379
+ init_hybrid();
1380
+ }
1381
+ });
1382
+
1383
+ // src/agent/compaction/manager.ts
1384
+ function createStrategy(name) {
1385
+ switch (name) {
1386
+ case "sliding-window":
1387
+ return new SlidingWindowStrategy();
1388
+ case "summarization":
1389
+ return new SummarizationStrategy();
1390
+ case "hybrid":
1391
+ return new HybridStrategy();
1392
+ default:
1393
+ throw new Error(`Unknown compaction strategy: ${name}`);
1394
+ }
1395
+ }
1396
+ var CompactionManager;
1397
+ var init_manager = __esm({
1398
+ "src/agent/compaction/manager.ts"() {
1399
+ "use strict";
1400
+ init_config();
1401
+ init_strategies();
1402
+ CompactionManager = class {
1403
+ client;
1404
+ model;
1405
+ config;
1406
+ strategy;
1407
+ modelLimits;
1408
+ // Statistics
1409
+ totalCompactions = 0;
1410
+ totalTokensSaved = 0;
1411
+ lastTokenCount = 0;
1412
+ constructor(client, model, config = {}) {
1413
+ this.client = client;
1414
+ this.model = model;
1415
+ this.config = resolveCompactionConfig(config);
1416
+ if (typeof config.strategy === "object" && "compact" in config.strategy) {
1417
+ this.strategy = config.strategy;
1418
+ } else {
1419
+ this.strategy = createStrategy(this.config.strategy);
1420
+ }
1421
+ }
1422
+ /**
1423
+ * Check if compaction is needed and perform it if so.
1424
+ *
1425
+ * @param conversation - The conversation manager to compact
1426
+ * @param iteration - Current agent iteration (for event metadata)
1427
+ * @returns CompactionEvent if compaction was performed, null otherwise
1428
+ */
1429
+ async checkAndCompact(conversation, iteration) {
1430
+ if (!this.config.enabled) {
1431
+ return null;
1432
+ }
1433
+ if (!this.modelLimits) {
1434
+ this.modelLimits = this.client.modelRegistry.getModelLimits(this.model);
1435
+ if (!this.modelLimits) {
1436
+ return null;
1437
+ }
1438
+ }
1439
+ if (!this.client.countTokens) {
1440
+ return null;
1441
+ }
1442
+ const messages = conversation.getMessages();
1443
+ const currentTokens = await this.client.countTokens(this.model, messages);
1444
+ this.lastTokenCount = currentTokens;
1445
+ const usagePercent = currentTokens / this.modelLimits.contextWindow * 100;
1446
+ if (usagePercent < this.config.triggerThresholdPercent) {
1447
+ return null;
1448
+ }
1449
+ const historyMessages = conversation.getHistoryMessages();
1450
+ const baseMessages = conversation.getBaseMessages();
1451
+ const historyTokens = await this.client.countTokens(this.model, historyMessages);
1452
+ const baseTokens = await this.client.countTokens(this.model, baseMessages);
1453
+ return this.compact(conversation, iteration, {
1454
+ historyMessages,
1455
+ baseMessages,
1456
+ historyTokens,
1457
+ baseTokens,
1458
+ currentTokens: historyTokens + baseTokens
1459
+ });
1460
+ }
1461
+ /**
1462
+ * Force compaction regardless of threshold.
1463
+ *
1464
+ * @param conversation - The conversation manager to compact
1465
+ * @param iteration - Current agent iteration (for event metadata). Use -1 for manual compaction.
1466
+ * @param precomputed - Optional pre-computed token counts (passed from checkAndCompact for efficiency)
1467
+ * @returns CompactionEvent with compaction details
1468
+ */
1469
+ async compact(conversation, iteration, precomputed) {
1470
+ if (!this.modelLimits) {
1471
+ this.modelLimits = this.client.modelRegistry.getModelLimits(this.model);
1472
+ if (!this.modelLimits) {
1473
+ return null;
1474
+ }
1475
+ }
1476
+ const historyMessages = precomputed?.historyMessages ?? conversation.getHistoryMessages();
1477
+ const baseMessages = precomputed?.baseMessages ?? conversation.getBaseMessages();
1478
+ const historyTokens = precomputed?.historyTokens ?? await this.client.countTokens(this.model, historyMessages);
1479
+ const baseTokens = precomputed?.baseTokens ?? await this.client.countTokens(this.model, baseMessages);
1480
+ const currentTokens = precomputed?.currentTokens ?? historyTokens + baseTokens;
1481
+ const targetTotalTokens = Math.floor(
1482
+ this.modelLimits.contextWindow * this.config.targetPercent / 100
1483
+ );
1484
+ const targetHistoryTokens = Math.max(0, targetTotalTokens - baseTokens);
1485
+ const result = await this.strategy.compact(historyMessages, this.config, {
1486
+ currentTokens: historyTokens,
1487
+ targetTokens: targetHistoryTokens,
1488
+ modelLimits: this.modelLimits,
1489
+ client: this.client,
1490
+ model: this.config.summarizationModel ?? this.model
1491
+ });
1492
+ conversation.replaceHistory(result.messages);
1493
+ const afterTokens = await this.client.countTokens(this.model, conversation.getMessages());
1494
+ const tokensSaved = currentTokens - afterTokens;
1495
+ this.totalCompactions++;
1496
+ this.totalTokensSaved += tokensSaved;
1497
+ this.lastTokenCount = afterTokens;
1498
+ const event = {
1499
+ strategy: result.strategyName,
1500
+ tokensBefore: currentTokens,
1501
+ tokensAfter: afterTokens,
1502
+ messagesBefore: historyMessages.length + baseMessages.length,
1503
+ messagesAfter: result.messages.length + baseMessages.length,
1504
+ summary: result.summary,
1505
+ iteration
1506
+ };
1507
+ if (this.config.onCompaction) {
1508
+ try {
1509
+ this.config.onCompaction(event);
1510
+ } catch (err) {
1511
+ console.warn("[llmist/compaction] onCompaction callback error:", err);
1512
+ }
1513
+ }
1514
+ return event;
1515
+ }
1516
+ /**
1517
+ * Get compaction statistics.
1518
+ */
1519
+ getStats() {
1520
+ const contextWindow = this.modelLimits?.contextWindow ?? 0;
1521
+ return {
1522
+ totalCompactions: this.totalCompactions,
1523
+ totalTokensSaved: this.totalTokensSaved,
1524
+ currentUsage: {
1525
+ tokens: this.lastTokenCount,
1526
+ percent: contextWindow > 0 ? this.lastTokenCount / contextWindow * 100 : 0
1527
+ },
1528
+ contextWindow
1529
+ };
1530
+ }
1531
+ /**
1532
+ * Check if compaction is enabled.
1533
+ */
1534
+ isEnabled() {
1535
+ return this.config.enabled;
1536
+ }
1537
+ };
1538
+ }
1539
+ });
1540
+
1119
1541
  // src/agent/gadget-output-store.ts
1120
1542
  import { randomBytes } from "node:crypto";
1121
1543
  var GadgetOutputStore;
@@ -1206,10 +1628,16 @@ var init_conversation_manager = __esm({
1206
1628
  baseMessages;
1207
1629
  initialMessages;
1208
1630
  historyBuilder;
1631
+ startPrefix;
1632
+ endPrefix;
1633
+ argPrefix;
1209
1634
  constructor(baseMessages, initialMessages, options = {}) {
1210
1635
  this.baseMessages = baseMessages;
1211
1636
  this.initialMessages = initialMessages;
1212
1637
  this.historyBuilder = new LLMMessageBuilder();
1638
+ this.startPrefix = options.startPrefix;
1639
+ this.endPrefix = options.endPrefix;
1640
+ this.argPrefix = options.argPrefix;
1213
1641
  if (options.startPrefix && options.endPrefix) {
1214
1642
  this.historyBuilder.withPrefixes(options.startPrefix, options.endPrefix, options.argPrefix);
1215
1643
  }
@@ -1226,6 +1654,25 @@ var init_conversation_manager = __esm({
1226
1654
  getMessages() {
1227
1655
  return [...this.baseMessages, ...this.initialMessages, ...this.historyBuilder.build()];
1228
1656
  }
1657
+ getHistoryMessages() {
1658
+ return this.historyBuilder.build();
1659
+ }
1660
+ getBaseMessages() {
1661
+ return [...this.baseMessages, ...this.initialMessages];
1662
+ }
1663
+ replaceHistory(newHistory) {
1664
+ this.historyBuilder = new LLMMessageBuilder();
1665
+ if (this.startPrefix && this.endPrefix) {
1666
+ this.historyBuilder.withPrefixes(this.startPrefix, this.endPrefix, this.argPrefix);
1667
+ }
1668
+ for (const msg of newHistory) {
1669
+ if (msg.role === "user") {
1670
+ this.historyBuilder.addUser(msg.content);
1671
+ } else if (msg.role === "assistant") {
1672
+ this.historyBuilder.addAssistant(msg.content);
1673
+ }
1674
+ }
1675
+ }
1229
1676
  };
1230
1677
  }
1231
1678
  });
@@ -4545,6 +4992,7 @@ var init_agent = __esm({
4545
4992
  init_model_shortcuts();
4546
4993
  init_output_viewer();
4547
4994
  init_logger();
4995
+ init_manager();
4548
4996
  init_gadget_output_store();
4549
4997
  init_agent_internal_key();
4550
4998
  init_conversation_manager();
@@ -4575,6 +5023,8 @@ var init_agent = __esm({
4575
5023
  outputStore;
4576
5024
  outputLimitEnabled;
4577
5025
  outputLimitCharLimit;
5026
+ // Context compaction
5027
+ compactionManager;
4578
5028
  /**
4579
5029
  * Creates a new Agent instance.
4580
5030
  * @internal This constructor is private. Use LLMist.createAgent() or AgentBuilder instead.
@@ -4634,6 +5084,14 @@ var init_agent = __esm({
4634
5084
  if (options.userPrompt) {
4635
5085
  this.conversation.addUserMessage(options.userPrompt);
4636
5086
  }
5087
+ const compactionEnabled = options.compactionConfig?.enabled ?? true;
5088
+ if (compactionEnabled) {
5089
+ this.compactionManager = new CompactionManager(
5090
+ this.client,
5091
+ this.model,
5092
+ options.compactionConfig
5093
+ );
5094
+ }
4637
5095
  }
4638
5096
  /**
4639
5097
  * Get the gadget registry for this agent.
@@ -4656,6 +5114,53 @@ var init_agent = __esm({
4656
5114
  getRegistry() {
4657
5115
  return this.registry;
4658
5116
  }
5117
+ /**
5118
+ * Manually trigger context compaction.
5119
+ *
5120
+ * Forces compaction regardless of threshold. Useful for:
5121
+ * - Pre-emptive context management before expected long operations
5122
+ * - Testing compaction behavior
5123
+ *
5124
+ * @returns CompactionEvent if compaction was performed, null if not configured or no history
5125
+ *
5126
+ * @example
5127
+ * ```typescript
5128
+ * const agent = await LLMist.createAgent()
5129
+ * .withModel('sonnet')
5130
+ * .withCompaction()
5131
+ * .ask('...');
5132
+ *
5133
+ * // Manually compact before a long operation
5134
+ * const event = await agent.compact();
5135
+ * if (event) {
5136
+ * console.log(`Saved ${event.tokensBefore - event.tokensAfter} tokens`);
5137
+ * }
5138
+ * ```
5139
+ */
5140
+ async compact() {
5141
+ if (!this.compactionManager) {
5142
+ return null;
5143
+ }
5144
+ return this.compactionManager.compact(this.conversation, -1);
5145
+ }
5146
+ /**
5147
+ * Get compaction statistics.
5148
+ *
5149
+ * @returns CompactionStats if compaction is enabled, null otherwise
5150
+ *
5151
+ * @example
5152
+ * ```typescript
5153
+ * const stats = agent.getCompactionStats();
5154
+ * if (stats) {
5155
+ * console.log(`Total compactions: ${stats.totalCompactions}`);
5156
+ * console.log(`Tokens saved: ${stats.totalTokensSaved}`);
5157
+ * console.log(`Current usage: ${stats.currentUsage.percent.toFixed(1)}%`);
5158
+ * }
5159
+ * ```
5160
+ */
5161
+ getCompactionStats() {
5162
+ return this.compactionManager?.getStats() ?? null;
5163
+ }
4659
5164
  /**
4660
5165
  * Run the agent loop.
4661
5166
  * Clean, simple orchestration - all complexity is in StreamProcessor.
@@ -4676,6 +5181,30 @@ var init_agent = __esm({
4676
5181
  while (currentIteration < this.maxIterations) {
4677
5182
  this.logger.debug("Starting iteration", { iteration: currentIteration });
4678
5183
  try {
5184
+ if (this.compactionManager) {
5185
+ const compactionEvent = await this.compactionManager.checkAndCompact(
5186
+ this.conversation,
5187
+ currentIteration
5188
+ );
5189
+ if (compactionEvent) {
5190
+ this.logger.info("Context compacted", {
5191
+ strategy: compactionEvent.strategy,
5192
+ tokensBefore: compactionEvent.tokensBefore,
5193
+ tokensAfter: compactionEvent.tokensAfter
5194
+ });
5195
+ yield { type: "compaction", event: compactionEvent };
5196
+ await this.safeObserve(async () => {
5197
+ if (this.hooks.observers?.onCompaction) {
5198
+ await this.hooks.observers.onCompaction({
5199
+ iteration: currentIteration,
5200
+ event: compactionEvent,
5201
+ stats: this.compactionManager.getStats(),
5202
+ logger: this.logger
5203
+ });
5204
+ }
5205
+ });
5206
+ }
5207
+ }
4679
5208
  let llmOptions = {
4680
5209
  model: this.model,
4681
5210
  messages: this.conversation.getMessages(),
@@ -4695,6 +5224,7 @@ var init_agent = __esm({
4695
5224
  if (this.hooks.controllers?.beforeLLMCall) {
4696
5225
  const context = {
4697
5226
  iteration: currentIteration,
5227
+ maxIterations: this.maxIterations,
4698
5228
  options: llmOptions,
4699
5229
  logger: this.logger
4700
5230
  };
@@ -4759,12 +5289,17 @@ var init_agent = __esm({
4759
5289
  });
4760
5290
  let finalMessage = result.finalMessage;
4761
5291
  if (this.hooks.controllers?.afterLLMCall) {
5292
+ const gadgetCallCount = result.outputs.filter(
5293
+ (output) => output.type === "gadget_result"
5294
+ ).length;
4762
5295
  const context = {
4763
5296
  iteration: currentIteration,
5297
+ maxIterations: this.maxIterations,
4764
5298
  options: llmOptions,
4765
5299
  finishReason: result.finishReason,
4766
5300
  usage: result.usage,
4767
5301
  finalMessage: result.finalMessage,
5302
+ gadgetCallCount,
4768
5303
  logger: this.logger
4769
5304
  };
4770
5305
  const action = await this.hooks.controllers.afterLLMCall(context);
@@ -5026,6 +5561,7 @@ var init_builder = __esm({
5026
5561
  defaultGadgetTimeoutMs;
5027
5562
  gadgetOutputLimit;
5028
5563
  gadgetOutputLimitPercent;
5564
+ compactionConfig;
5029
5565
  constructor(client) {
5030
5566
  this.client = client;
5031
5567
  }
@@ -5421,6 +5957,57 @@ var init_builder = __esm({
5421
5957
  this.gadgetOutputLimitPercent = percent;
5422
5958
  return this;
5423
5959
  }
5960
+ /**
5961
+ * Configure context compaction.
5962
+ *
5963
+ * Context compaction automatically manages conversation history to prevent
5964
+ * context window overflow in long-running agent conversations.
5965
+ *
5966
+ * @param config - Compaction configuration options
5967
+ * @returns This builder for chaining
5968
+ *
5969
+ * @example
5970
+ * ```typescript
5971
+ * // Custom thresholds
5972
+ * .withCompaction({
5973
+ * triggerThresholdPercent: 70,
5974
+ * targetPercent: 40,
5975
+ * preserveRecentTurns: 10,
5976
+ * })
5977
+ *
5978
+ * // Different strategy
5979
+ * .withCompaction({
5980
+ * strategy: 'sliding-window',
5981
+ * })
5982
+ *
5983
+ * // With callback
5984
+ * .withCompaction({
5985
+ * onCompaction: (event) => {
5986
+ * console.log(`Saved ${event.tokensBefore - event.tokensAfter} tokens`);
5987
+ * }
5988
+ * })
5989
+ * ```
5990
+ */
5991
+ withCompaction(config) {
5992
+ this.compactionConfig = { ...config, enabled: config.enabled ?? true };
5993
+ return this;
5994
+ }
5995
+ /**
5996
+ * Disable context compaction.
5997
+ *
5998
+ * By default, compaction is enabled. Use this method to explicitly disable it.
5999
+ *
6000
+ * @returns This builder for chaining
6001
+ *
6002
+ * @example
6003
+ * ```typescript
6004
+ * .withoutCompaction() // Disable automatic compaction
6005
+ * ```
6006
+ */
6007
+ withoutCompaction() {
6008
+ this.compactionConfig = { enabled: false };
6009
+ return this;
6010
+ }
5424
6011
  /**
5425
6012
  * Add a synthetic gadget call to the conversation history.
5426
6013
  *
@@ -5536,7 +6123,8 @@ ${endPrefix}`
5536
6123
  shouldContinueAfterError: this.shouldContinueAfterError,
5537
6124
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
5538
6125
  gadgetOutputLimit: this.gadgetOutputLimit,
5539
- gadgetOutputLimitPercent: this.gadgetOutputLimitPercent
6126
+ gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
6127
+ compactionConfig: this.compactionConfig
5540
6128
  };
5541
6129
  return new Agent(AGENT_INTERNAL_KEY, options);
5542
6130
  }
@@ -5638,7 +6226,8 @@ ${endPrefix}`
5638
6226
  shouldContinueAfterError: this.shouldContinueAfterError,
5639
6227
  defaultGadgetTimeoutMs: this.defaultGadgetTimeoutMs,
5640
6228
  gadgetOutputLimit: this.gadgetOutputLimit,
5641
- gadgetOutputLimitPercent: this.gadgetOutputLimitPercent
6229
+ gadgetOutputLimitPercent: this.gadgetOutputLimitPercent,
6230
+ compactionConfig: this.compactionConfig
5642
6231
  };
5643
6232
  return new Agent(AGENT_INTERNAL_KEY, options);
5644
6233
  }
@@ -5903,9 +6492,11 @@ export {
5903
6492
  init_schema_validator,
5904
6493
  GadgetRegistry,
5905
6494
  init_registry,
6495
+ DEFAULT_HINTS,
5906
6496
  DEFAULT_PROMPTS,
5907
6497
  resolvePromptTemplate,
5908
6498
  resolveRulesTemplate,
6499
+ resolveHintTemplate,
5909
6500
  init_prompt_config,
5910
6501
  LLMMessageBuilder,
5911
6502
  init_messages,
@@ -5920,6 +6511,16 @@ export {
5920
6511
  init_create_gadget,
5921
6512
  createGadgetOutputViewer,
5922
6513
  init_output_viewer,
6514
+ DEFAULT_COMPACTION_CONFIG,
6515
+ DEFAULT_SUMMARIZATION_PROMPT,
6516
+ init_config,
6517
+ init_strategy,
6518
+ SlidingWindowStrategy,
6519
+ SummarizationStrategy,
6520
+ HybridStrategy,
6521
+ init_strategies,
6522
+ CompactionManager,
6523
+ init_manager,
5923
6524
  GadgetOutputStore,
5924
6525
  init_gadget_output_store,
5925
6526
  ConversationManager,
@@ -5962,4 +6563,4 @@ export {
5962
6563
  AgentBuilder,
5963
6564
  init_builder
5964
6565
  };
5965
- //# sourceMappingURL=chunk-KORMY3CD.js.map
6566
+ //# sourceMappingURL=chunk-RZTAKIDE.js.map