@illuma-ai/agents 1.1.3 → 1.1.5

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 (35) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +6 -2
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/common/constants.cjs +10 -0
  4. package/dist/cjs/common/constants.cjs.map +1 -1
  5. package/dist/cjs/graphs/Graph.cjs +86 -12
  6. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  7. package/dist/cjs/main.cjs +4 -0
  8. package/dist/cjs/main.cjs.map +1 -1
  9. package/dist/cjs/types/graph.cjs.map +1 -1
  10. package/dist/cjs/utils/fileManifest.cjs +49 -0
  11. package/dist/cjs/utils/fileManifest.cjs.map +1 -0
  12. package/dist/esm/agents/AgentContext.mjs +6 -2
  13. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  14. package/dist/esm/common/constants.mjs +10 -1
  15. package/dist/esm/common/constants.mjs.map +1 -1
  16. package/dist/esm/graphs/Graph.mjs +87 -13
  17. package/dist/esm/graphs/Graph.mjs.map +1 -1
  18. package/dist/esm/main.mjs +2 -1
  19. package/dist/esm/main.mjs.map +1 -1
  20. package/dist/esm/types/graph.mjs.map +1 -1
  21. package/dist/esm/utils/fileManifest.mjs +46 -0
  22. package/dist/esm/utils/fileManifest.mjs.map +1 -0
  23. package/dist/types/agents/AgentContext.d.ts +4 -1
  24. package/dist/types/common/constants.d.ts +9 -0
  25. package/dist/types/types/graph.d.ts +35 -0
  26. package/dist/types/utils/fileManifest.d.ts +17 -0
  27. package/dist/types/utils/index.d.ts +1 -0
  28. package/package.json +1 -1
  29. package/src/agents/AgentContext.ts +7 -0
  30. package/src/common/constants.ts +10 -0
  31. package/src/graphs/Graph.ts +92 -13
  32. package/src/graphs/gapFeatures.test.ts +246 -8
  33. package/src/types/graph.ts +36 -0
  34. package/src/utils/fileManifest.ts +49 -0
  35. package/src/utils/index.ts +1 -0
@@ -11,7 +11,7 @@ import { ensureThinkingBlockInMessages } from '../messages/format.mjs';
11
11
  import { addCacheControl, addBedrockCacheControl } from '../messages/cache.mjs';
12
12
  import { formatContentStrings } from '../messages/content.mjs';
13
13
  import { GraphNodeKeys, Providers, ContentTypes, GraphEvents, MessageTypes, StepTypes, Constants } from '../common/enum.mjs';
14
- import { TOOL_TURN_THINKING_BUDGET, PROACTIVE_SUMMARY_THRESHOLD, SUMMARIZATION_CONTEXT_THRESHOLD } from '../common/constants.mjs';
14
+ import { TOOL_TURN_THINKING_BUDGET, PROACTIVE_SUMMARY_THRESHOLD, SUMMARIZATION_CONTEXT_THRESHOLD, COMPACTION_RECENT_ROUNDS } from '../common/constants.mjs';
15
15
  import { deduplicateSystemMessages } from '../messages/dedup.mjs';
16
16
  import { resetIfNotEmpty, joinKeys } from '../utils/graph.mjs';
17
17
  import { isOpenAILike, isGoogleLike } from '../utils/llm.mjs';
@@ -25,6 +25,7 @@ import 'zod-to-json-schema';
25
25
  import { hasTaskTool, buildPostPruneNote, detectDocuments, shouldInjectMultiDocHint, buildMultiDocHintContent } from '../utils/contextPressure.mjs';
26
26
  import { ToolDiscoveryCache } from '../utils/toolDiscoveryCache.mjs';
27
27
  import { createPruneCalibration, applyCalibration, updatePruneCalibration } from '../utils/pruneCalibration.mjs';
28
+ import { buildFileManifestBlock } from '../utils/fileManifest.mjs';
28
29
  import { getChatModelClass, manualToolStreamProviders } from '../llm/providers.mjs';
29
30
  import { ToolNode, toolsCondition } from '../tools/ToolNode.mjs';
30
31
  import { ChatOpenAI, AzureChatOpenAI } from '../llm/openai/index.mjs';
@@ -1179,17 +1180,52 @@ class StandardGraph extends Graph {
1179
1180
  : 0;
1180
1181
  // Budget for recent messages = total - system - summary - 3 (assistant priming)
1181
1182
  const recentBudget = calibratedMax - systemTokens - summaryTokens - 3;
1182
- // Step 3: Walk newest→oldest, collect messages that fit in the budget
1183
+ // Step 3: Determine window of recent messages to include.
1184
+ //
1185
+ // Two modes:
1186
+ // A) No summary available → fill the budget (all messages that fit)
1187
+ // B) Summary available → keep last 2 conversation rounds (H+A pairs)
1188
+ // + any trailing tool messages. The summary covers everything else.
1189
+ // This avoids wasting tokens on raw messages the summary already covers.
1190
+ //
1191
+ // A "round" = one human message + one AI response (+ any tool messages between).
1183
1192
  const contentStart = systemMsg != null ? 1 : 0;
1184
1193
  let usedTokens = 0;
1185
1194
  let windowStart = messages.length; // index where the recent window begins
1186
- for (let i = messages.length - 1; i >= contentStart; i--) {
1187
- const msgTokens = agentContext.indexTokenCountMap[i] ?? 0;
1188
- if (usedTokens + msgTokens > recentBudget) {
1189
- break;
1195
+ let fileManifestTokens = 0; // populated in Step 4 if file manifest is injected
1196
+ if (summary == null || summary === '') {
1197
+ // Mode A: No summary include as many recent messages as fit in budget
1198
+ for (let i = messages.length - 1; i >= contentStart; i--) {
1199
+ const msgTokens = agentContext.indexTokenCountMap[i] ?? 0;
1200
+ if (usedTokens + msgTokens > recentBudget) {
1201
+ break;
1202
+ }
1203
+ usedTokens += msgTokens;
1204
+ windowStart = i;
1205
+ }
1206
+ }
1207
+ else {
1208
+ // Mode B: Summary exists — keep last 2 rounds (4 core messages: H+A+H+A)
1209
+ // Walk backward counting human messages as round boundaries.
1210
+ const MAX_RECENT_ROUNDS = COMPACTION_RECENT_ROUNDS;
1211
+ let roundsSeen = 0;
1212
+ for (let i = messages.length - 1; i >= contentStart; i--) {
1213
+ const msgType = messages[i]?.getType();
1214
+ const msgTokens = agentContext.indexTokenCountMap[i] ?? 0;
1215
+ // Budget guard — even in round-limited mode, don't exceed budget
1216
+ if (usedTokens + msgTokens > recentBudget) {
1217
+ break;
1218
+ }
1219
+ usedTokens += msgTokens;
1220
+ windowStart = i;
1221
+ // Count a human message as a round boundary
1222
+ if (msgType === 'human') {
1223
+ roundsSeen++;
1224
+ if (roundsSeen >= MAX_RECENT_ROUNDS) {
1225
+ break;
1226
+ }
1227
+ }
1190
1228
  }
1191
- usedTokens += msgTokens;
1192
- windowStart = i;
1193
1229
  }
1194
1230
  // Ensure we don't split tool-call / tool-result pairs.
1195
1231
  // If windowStart lands on a ToolMessage, walk back to include its AI message.
@@ -1202,7 +1238,11 @@ class StandardGraph extends Graph {
1202
1238
  const compactedMessages = messages.slice(contentStart, windowStart);
1203
1239
  const hasSummary = summaryMsg != null;
1204
1240
  // Step 4: Assemble the windowed view
1205
- // [system] + [summary (covers compacted messages)] + [recent window]
1241
+ // [system] + [summary] + [file manifest] + [recent window]
1242
+ //
1243
+ // File manifest is injected ONLY when compaction is active (messages behind summary).
1244
+ // It provides the LLM with awareness of all conversation files so it can
1245
+ // retrieve content on demand via file_search or content_tool read.
1206
1246
  const viewParts = [];
1207
1247
  if (systemMsg != null) {
1208
1248
  viewParts.push(systemMsg);
@@ -1210,12 +1250,46 @@ class StandardGraph extends Graph {
1210
1250
  if (summaryMsg != null) {
1211
1251
  viewParts.push(summaryMsg);
1212
1252
  }
1253
+ // Inject file manifest when files exist and messages are being compacted
1254
+ const fileManifest = agentContext.fileManifest;
1255
+ if (fileManifest && fileManifest.length > 0 && compactedMessages.length > 0) {
1256
+ const manifestBlock = buildFileManifestBlock(fileManifest);
1257
+ if (manifestBlock) {
1258
+ const manifestMsg = new SystemMessage(manifestBlock);
1259
+ viewParts.push(manifestMsg);
1260
+ // Account for manifest tokens in the view token map
1261
+ const manifestTokens = tokenCounter != null ? tokenCounter(manifestMsg) : 0;
1262
+ // Will be inserted at the correct index when rebuilding viewTokenMap below
1263
+ fileManifestTokens = manifestTokens;
1264
+ }
1265
+ }
1213
1266
  viewParts.push(...recentMessages);
1214
1267
  messagesToUse = viewParts;
1215
- console.debug(`[Graph:Compaction] View: ${messages.length}→${viewParts.length} msgs ` +
1216
- `(${compactedMessages.length} behind summary, ${recentMessages.length} in window) | ` +
1217
- `summary=${summarySource}${summary ? ` (len=${summary.length})` : ''} | ` +
1218
- `budget=${recentBudget}/${calibratedMax} used=${usedTokens}`);
1268
+ // Rebuild indexTokenCountMap for the windowed view so downstream
1269
+ // analytics and summarization triggers see accurate token counts.
1270
+ const viewTokenMap = {};
1271
+ let viewIdx = 0;
1272
+ if (systemMsg != null) {
1273
+ viewTokenMap[viewIdx] = systemTokens;
1274
+ viewIdx++;
1275
+ }
1276
+ if (summaryMsg != null) {
1277
+ viewTokenMap[viewIdx] = summaryTokens;
1278
+ viewIdx++;
1279
+ }
1280
+ if (fileManifestTokens > 0) {
1281
+ viewTokenMap[viewIdx] = fileManifestTokens;
1282
+ viewIdx++;
1283
+ }
1284
+ for (let i = windowStart; i < messages.length; i++) {
1285
+ viewTokenMap[viewIdx] = agentContext.indexTokenCountMap[i];
1286
+ viewIdx++;
1287
+ }
1288
+ agentContext.indexTokenCountMap = viewTokenMap;
1289
+ console.debug(`[Graph:Compaction] ${messages.length}→${viewParts.length} msgs | ` +
1290
+ `compacted=${compactedMessages.length} window=${recentMessages.length} | ` +
1291
+ `summary=${summarySource} | budget=${usedTokens}/${recentBudget}` +
1292
+ (fileManifestTokens > 0 ? ` | manifest=${fileManifest?.length ?? 0} files (${fileManifestTokens}tok)` : ''));
1219
1293
  // Step 5: Fire background summary update (non-blocking)
1220
1294
  // Summarize messages outside the window so next iteration has a fresh summary.
1221
1295
  // Only trigger if there are compacted messages worth summarizing.