agentfootprint 7.15.0 → 7.17.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.
Files changed (159) hide show
  1. package/dist/adapters/llm/BrowserOpenAIProvider.js +7 -3
  2. package/dist/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
  3. package/dist/adapters/llm/OpenAIProvider.js +11 -3
  4. package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
  5. package/dist/conventions.js +9 -0
  6. package/dist/conventions.js.map +1 -1
  7. package/dist/core/Agent.js +61 -2
  8. package/dist/core/Agent.js.map +1 -1
  9. package/dist/core/agent/AgentBuilder.js +136 -1
  10. package/dist/core/agent/AgentBuilder.js.map +1 -1
  11. package/dist/core/agent/buildAgentChart.js +12 -1
  12. package/dist/core/agent/buildAgentChart.js.map +1 -1
  13. package/dist/core/agent/buildDynamicAgentChart.js +10 -1
  14. package/dist/core/agent/buildDynamicAgentChart.js.map +1 -1
  15. package/dist/core/agent/stages/window.js +141 -0
  16. package/dist/core/agent/stages/window.js.map +1 -0
  17. package/dist/core/agent/window/errors.js +40 -0
  18. package/dist/core/agent/window/errors.js.map +1 -0
  19. package/dist/core/agent/window/index.js +36 -0
  20. package/dist/core/agent/window/index.js.map +1 -0
  21. package/dist/core/agent/window/notice.js +57 -0
  22. package/dist/core/agent/window/notice.js.map +1 -0
  23. package/dist/core/agent/window/options.js +93 -0
  24. package/dist/core/agent/window/options.js.map +1 -0
  25. package/dist/core/agent/window/removal.js +45 -0
  26. package/dist/core/agent/window/removal.js.map +1 -0
  27. package/dist/core/agent/window/strategies/drop.js +106 -0
  28. package/dist/core/agent/window/strategies/drop.js.map +1 -0
  29. package/dist/core/agent/window/strategies/slidingWindow.js +87 -0
  30. package/dist/core/agent/window/strategies/slidingWindow.js.map +1 -0
  31. package/dist/core/agent/window/strategies/summarizeOldest.js +178 -0
  32. package/dist/core/agent/window/strategies/summarizeOldest.js.map +1 -0
  33. package/dist/core/agent/window/strategies/tokenBudget.js +95 -0
  34. package/dist/core/agent/window/strategies/tokenBudget.js.map +1 -0
  35. package/dist/core/agent/window/strategy.js +42 -0
  36. package/dist/core/agent/window/strategy.js.map +1 -0
  37. package/dist/core/agent/window/summarize.js +103 -0
  38. package/dist/core/agent/window/summarize.js.map +1 -0
  39. package/dist/core/agent/window/turns.js +175 -0
  40. package/dist/core/agent/window/turns.js.map +1 -0
  41. package/dist/core/agent/window/types.js +23 -0
  42. package/dist/core/agent/window/types.js.map +1 -0
  43. package/dist/esm/adapters/llm/BrowserOpenAIProvider.js +7 -3
  44. package/dist/esm/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
  45. package/dist/esm/adapters/llm/OpenAIProvider.js +11 -3
  46. package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
  47. package/dist/esm/conventions.d.ts +9 -0
  48. package/dist/esm/conventions.js +9 -0
  49. package/dist/esm/conventions.js.map +1 -1
  50. package/dist/esm/core/Agent.d.ts +8 -1
  51. package/dist/esm/core/Agent.js +61 -2
  52. package/dist/esm/core/Agent.js.map +1 -1
  53. package/dist/esm/core/agent/AgentBuilder.d.ts +99 -0
  54. package/dist/esm/core/agent/AgentBuilder.js +136 -1
  55. package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
  56. package/dist/esm/core/agent/buildAgentChart.d.ts +20 -0
  57. package/dist/esm/core/agent/buildAgentChart.js +12 -1
  58. package/dist/esm/core/agent/buildAgentChart.js.map +1 -1
  59. package/dist/esm/core/agent/buildDynamicAgentChart.js +10 -1
  60. package/dist/esm/core/agent/buildDynamicAgentChart.js.map +1 -1
  61. package/dist/esm/core/agent/stages/window.d.ts +63 -0
  62. package/dist/esm/core/agent/stages/window.js +137 -0
  63. package/dist/esm/core/agent/stages/window.js.map +1 -0
  64. package/dist/esm/core/agent/types.d.ts +18 -0
  65. package/dist/esm/core/agent/window/errors.d.ts +26 -0
  66. package/dist/esm/core/agent/window/errors.js +36 -0
  67. package/dist/esm/core/agent/window/errors.js.map +1 -0
  68. package/dist/esm/core/agent/window/index.d.ts +27 -0
  69. package/dist/esm/core/agent/window/index.js +25 -0
  70. package/dist/esm/core/agent/window/index.js.map +1 -0
  71. package/dist/esm/core/agent/window/notice.d.ts +46 -0
  72. package/dist/esm/core/agent/window/notice.js +52 -0
  73. package/dist/esm/core/agent/window/notice.js.map +1 -0
  74. package/dist/esm/core/agent/window/options.d.ts +33 -0
  75. package/dist/esm/core/agent/window/options.js +87 -0
  76. package/dist/esm/core/agent/window/options.js.map +1 -0
  77. package/dist/esm/core/agent/window/removal.d.ts +22 -0
  78. package/dist/esm/core/agent/window/removal.js +40 -0
  79. package/dist/esm/core/agent/window/removal.js.map +1 -0
  80. package/dist/esm/core/agent/window/strategies/drop.d.ts +54 -0
  81. package/dist/esm/core/agent/window/strategies/drop.js +102 -0
  82. package/dist/esm/core/agent/window/strategies/drop.js.map +1 -0
  83. package/dist/esm/core/agent/window/strategies/slidingWindow.d.ts +48 -0
  84. package/dist/esm/core/agent/window/strategies/slidingWindow.js +83 -0
  85. package/dist/esm/core/agent/window/strategies/slidingWindow.js.map +1 -0
  86. package/dist/esm/core/agent/window/strategies/summarizeOldest.d.ts +42 -0
  87. package/dist/esm/core/agent/window/strategies/summarizeOldest.js +174 -0
  88. package/dist/esm/core/agent/window/strategies/summarizeOldest.js.map +1 -0
  89. package/dist/esm/core/agent/window/strategies/tokenBudget.d.ts +47 -0
  90. package/dist/esm/core/agent/window/strategies/tokenBudget.js +91 -0
  91. package/dist/esm/core/agent/window/strategies/tokenBudget.js.map +1 -0
  92. package/dist/esm/core/agent/window/strategy.d.ts +181 -0
  93. package/dist/esm/core/agent/window/strategy.js +41 -0
  94. package/dist/esm/core/agent/window/strategy.js.map +1 -0
  95. package/dist/esm/core/agent/window/summarize.d.ts +61 -0
  96. package/dist/esm/core/agent/window/summarize.js +96 -0
  97. package/dist/esm/core/agent/window/summarize.js.map +1 -0
  98. package/dist/esm/core/agent/window/turns.d.ts +108 -0
  99. package/dist/esm/core/agent/window/turns.js +167 -0
  100. package/dist/esm/core/agent/window/turns.js.map +1 -0
  101. package/dist/esm/core/agent/window/types.d.ts +263 -0
  102. package/dist/esm/core/agent/window/types.js +22 -0
  103. package/dist/esm/core/agent/window/types.js.map +1 -0
  104. package/dist/esm/index.d.ts +1 -0
  105. package/dist/esm/index.js +10 -0
  106. package/dist/esm/index.js.map +1 -1
  107. package/dist/esm/recorders/core/CompactionMeter.d.ts +84 -0
  108. package/dist/esm/recorders/core/CompactionMeter.js +109 -0
  109. package/dist/esm/recorders/core/CompactionMeter.js.map +1 -0
  110. package/dist/index.js +23 -5
  111. package/dist/index.js.map +1 -1
  112. package/dist/recorders/core/CompactionMeter.js +113 -0
  113. package/dist/recorders/core/CompactionMeter.js.map +1 -0
  114. package/dist/types/adapters/llm/BrowserOpenAIProvider.d.ts.map +1 -1
  115. package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
  116. package/dist/types/conventions.d.ts +9 -0
  117. package/dist/types/conventions.d.ts.map +1 -1
  118. package/dist/types/core/Agent.d.ts +8 -1
  119. package/dist/types/core/Agent.d.ts.map +1 -1
  120. package/dist/types/core/agent/AgentBuilder.d.ts +99 -0
  121. package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
  122. package/dist/types/core/agent/buildAgentChart.d.ts +20 -0
  123. package/dist/types/core/agent/buildAgentChart.d.ts.map +1 -1
  124. package/dist/types/core/agent/buildDynamicAgentChart.d.ts.map +1 -1
  125. package/dist/types/core/agent/stages/window.d.ts +64 -0
  126. package/dist/types/core/agent/stages/window.d.ts.map +1 -0
  127. package/dist/types/core/agent/types.d.ts +18 -0
  128. package/dist/types/core/agent/types.d.ts.map +1 -1
  129. package/dist/types/core/agent/window/errors.d.ts +27 -0
  130. package/dist/types/core/agent/window/errors.d.ts.map +1 -0
  131. package/dist/types/core/agent/window/index.d.ts +28 -0
  132. package/dist/types/core/agent/window/index.d.ts.map +1 -0
  133. package/dist/types/core/agent/window/notice.d.ts +47 -0
  134. package/dist/types/core/agent/window/notice.d.ts.map +1 -0
  135. package/dist/types/core/agent/window/options.d.ts +34 -0
  136. package/dist/types/core/agent/window/options.d.ts.map +1 -0
  137. package/dist/types/core/agent/window/removal.d.ts +23 -0
  138. package/dist/types/core/agent/window/removal.d.ts.map +1 -0
  139. package/dist/types/core/agent/window/strategies/drop.d.ts +55 -0
  140. package/dist/types/core/agent/window/strategies/drop.d.ts.map +1 -0
  141. package/dist/types/core/agent/window/strategies/slidingWindow.d.ts +49 -0
  142. package/dist/types/core/agent/window/strategies/slidingWindow.d.ts.map +1 -0
  143. package/dist/types/core/agent/window/strategies/summarizeOldest.d.ts +43 -0
  144. package/dist/types/core/agent/window/strategies/summarizeOldest.d.ts.map +1 -0
  145. package/dist/types/core/agent/window/strategies/tokenBudget.d.ts +48 -0
  146. package/dist/types/core/agent/window/strategies/tokenBudget.d.ts.map +1 -0
  147. package/dist/types/core/agent/window/strategy.d.ts +182 -0
  148. package/dist/types/core/agent/window/strategy.d.ts.map +1 -0
  149. package/dist/types/core/agent/window/summarize.d.ts +62 -0
  150. package/dist/types/core/agent/window/summarize.d.ts.map +1 -0
  151. package/dist/types/core/agent/window/turns.d.ts +109 -0
  152. package/dist/types/core/agent/window/turns.d.ts.map +1 -0
  153. package/dist/types/core/agent/window/types.d.ts +264 -0
  154. package/dist/types/core/agent/window/types.d.ts.map +1 -0
  155. package/dist/types/index.d.ts +1 -0
  156. package/dist/types/index.d.ts.map +1 -1
  157. package/dist/types/recorders/core/CompactionMeter.d.ts +85 -0
  158. package/dist/types/recorders/core/CompactionMeter.d.ts.map +1 -0
  159. package/package.json +1 -1
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ /**
3
+ * window/removal — "these messages left" → the facts the ledger needs.
4
+ *
5
+ * Pattern: Pure function over the meter's provenance.
6
+ * Role: core/ layer. The stage binds this into every
7
+ * `WindowStrategyInput.removalFacts`, so a strategy can name what it
8
+ * removed without ever touching the meter — and cannot file a
9
+ * removal it is unable to name.
10
+ * Emits: N/A.
11
+ */
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.indexRange = exports.removalFacts = void 0;
14
+ /**
15
+ * Resolve which stages wrote the removed messages, and how long each lived.
16
+ *
17
+ * `survivalMs` is measured (`atMs - bornAtMs`), and is 0 — not a guess — when
18
+ * a message's birth is unknown, which happens only for a window seeded from
19
+ * outside this run.
20
+ */
21
+ function removalFacts(origins, indices, atMs) {
22
+ const removedStageIds = [];
23
+ const evictions = [];
24
+ for (const index of indices) {
25
+ const origin = origins[index];
26
+ if (origin !== undefined && !removedStageIds.includes(origin.stageId)) {
27
+ removedStageIds.push(origin.stageId);
28
+ }
29
+ evictions.push({
30
+ index,
31
+ survivalMs: origin === undefined ? 0 : Math.max(0, atMs - origin.bornAtMs),
32
+ });
33
+ }
34
+ return { removedStageIds, evictions };
35
+ }
36
+ exports.removalFacts = removalFacts;
37
+ /** `[from, toExclusive)` as a list of indices. */
38
+ function indexRange(from, toExclusive) {
39
+ const out = [];
40
+ for (let i = from; i < toExclusive; i++)
41
+ out.push(i);
42
+ return out;
43
+ }
44
+ exports.indexRange = indexRange;
45
+ //# sourceMappingURL=removal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"removal.js","sourceRoot":"","sources":["../../../../src/core/agent/window/removal.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAKH;;;;;;GAMG;AACH,SAAgB,YAAY,CAC1B,OAAiC,EACjC,OAA0B,EAC1B,IAAY;IAEZ,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,SAAS,GAAqB,EAAE,CAAC;IACvC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,MAAM,KAAK,SAAS,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACtE,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvC,CAAC;QACD,SAAS,CAAC,IAAI,CAAC;YACb,KAAK;YACL,UAAU,EAAE,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC;SAC3E,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;AACxC,CAAC;AAlBD,oCAkBC;AAED,kDAAkD;AAClD,SAAgB,UAAU,CAAC,IAAY,EAAE,WAAmB;IAC1D,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,CAAC,GAAG,WAAW,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrD,OAAO,GAAG,CAAC;AACb,CAAC;AAJD,gCAIC"}
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ /**
3
+ * window/strategies/drop — the mechanic both drop strategies share.
4
+ *
5
+ * Pattern: One pure function over a `WindowStrategyInput`.
6
+ * Role: core/ layer. `slidingWindow` and `tokenBudget` differ ONLY in when
7
+ * they engage and what they file; what actually leaves the window is
8
+ * decided here, once, so a refusal reason means the same thing under
9
+ * both — and under compaction, which asks the same `planRemoval`.
10
+ * Emits: N/A.
11
+ *
12
+ * A drop makes no LLM call and writes no summary. What it must still do is
13
+ * keep the request valid and keep the record honest:
14
+ *
15
+ * • the span comes from the shared refusal engine, so an unanswered tool
16
+ * call, the paused tool, a pending check-in and the recent turns never
17
+ * leave, and each refusal is named;
18
+ * • when the span reaches the window's HEAD, an authored notice takes that
19
+ * position — the window must open on a user turn (see notice.ts), and a
20
+ * message we are forced to author should tell the truth;
21
+ * • when it does not, nothing is inserted: the original opening turn is
22
+ * still there, so there is no wire problem to solve.
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.dropOldestSpan = void 0;
26
+ const notice_js_1 = require("../notice.js");
27
+ const removal_js_1 = require("../removal.js");
28
+ const turns_js_1 = require("../turns.js");
29
+ /**
30
+ * Drop the oldest contiguous removable span, if there is one.
31
+ *
32
+ * @param input the strategy's input, with the bound refusal engine
33
+ * @param keepRecentTurns how many trailing turns are off-limits
34
+ * @param strategyName named in the authored notice, so a reader of the
35
+ * window itself can tell which policy removed things
36
+ */
37
+ function dropOldestSpan(input, keepRecentTurns, strategyName) {
38
+ const { history, turns, iteration } = input;
39
+ const charsBefore = (0, turns_js_1.windowChars)(history);
40
+ const nothing = (refusals) => ({
41
+ refusals,
42
+ removedStageIds: [],
43
+ removedMessageCount: 0,
44
+ evictions: [],
45
+ windowCharsBefore: charsBefore,
46
+ windowCharsAfter: charsBefore,
47
+ turnsBefore: turns.length,
48
+ turnsAfter: turns.length,
49
+ });
50
+ // No `isExistingSummary` predicate: that refusal exists to stop a strategy
51
+ // spending an LLM call to re-summarize a summary. A drop spends nothing, so
52
+ // there is nothing to protect against — a stale summary is as droppable as
53
+ // any other old turn.
54
+ const plan = input.planRemoval(keepRecentTurns);
55
+ if (plan.from === -1)
56
+ return nothing(plan.refusals);
57
+ const spanStart = turns[plan.from].start;
58
+ const spanEnd = turns[plan.to].start + turns[plan.to].length;
59
+ const head = history.slice(0, spanStart);
60
+ const span = history.slice(spanStart, spanEnd);
61
+ const tail = history.slice(spanEnd);
62
+ let window;
63
+ let insertedAtMs;
64
+ const droppedAtMs = input.now();
65
+ if (spanStart === 0) {
66
+ // The head is leaving: something must open the window, and it must be a
67
+ // user turn. Author the notice — and refuse the whole drop if that notice
68
+ // would not be smaller than what it replaces, because dropping two tiny
69
+ // turns to insert a longer notice is pure loss.
70
+ const notice = (0, notice_js_1.buildDropNotice)({
71
+ droppedMessageCount: span.length,
72
+ iteration,
73
+ strategy: strategyName,
74
+ });
75
+ if (notice.content.length >= (0, turns_js_1.windowChars)(span)) {
76
+ return nothing([
77
+ { reason: 'summary-not-smaller', turnIndex: plan.from, messageIndex: spanStart },
78
+ ...plan.refusals,
79
+ ]);
80
+ }
81
+ window = [notice, ...tail];
82
+ insertedAtMs = droppedAtMs;
83
+ }
84
+ else {
85
+ window = [...head, ...tail];
86
+ }
87
+ const facts = input.removalFacts((0, removal_js_1.indexRange)(spanStart, spanEnd), droppedAtMs);
88
+ return {
89
+ refusals: plan.refusals,
90
+ window,
91
+ rebase: {
92
+ headCount: head.length,
93
+ keptTailCount: tail.length,
94
+ ...(insertedAtMs !== undefined && { insertedAtMs }),
95
+ },
96
+ removedStageIds: facts.removedStageIds,
97
+ removedMessageCount: span.length,
98
+ evictions: facts.evictions,
99
+ windowCharsBefore: charsBefore,
100
+ windowCharsAfter: (0, turns_js_1.windowChars)(window),
101
+ turnsBefore: turns.length,
102
+ turnsAfter: (0, turns_js_1.segmentTurns)(window).length,
103
+ };
104
+ }
105
+ exports.dropOldestSpan = dropOldestSpan;
106
+ //# sourceMappingURL=drop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drop.js","sourceRoot":"","sources":["../../../../../src/core/agent/window/strategies/drop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ "use strict";
2
+ /**
3
+ * slidingWindow — keep the last N turns, drop what is older.
4
+ *
5
+ * Pattern: WindowStrategy implementation. Its own module, registering
6
+ * nothing at import.
7
+ * Role: core/ layer.
8
+ * Emits: N/A — the stage emits, records and costs; this file decides.
9
+ *
10
+ * The market's simplest window policy (LangChain's `trim_messages`, the
11
+ * "last N messages" every framework ships). Two things are different here:
12
+ *
13
+ * 1. **It refuses by name.** It goes through the SAME turn segmentation and
14
+ * the SAME refusal engine as compaction, so it will not drop half of a
15
+ * `tool_use` / `tool_result` pair, will not drop an unanswered tool call
16
+ * whose answer may still arrive, will not drop the tool a paused run is
17
+ * waiting on or a pending check-in, and cannot touch the system
18
+ * envelope. Message-counting trimmers split those pairs and the vendor
19
+ * rejects the request; this one steps over them and says so in the
20
+ * record.
21
+ * 2. **It says what it dropped.** Every dropped message is an eviction
22
+ * event with its measured lifetime, and the record names the stage ids
23
+ * the messages came from. The turns themselves stay in the commit log,
24
+ * byte for byte.
25
+ *
26
+ * It triggers on turn COUNT, not tokens — so it needs no summarizer, makes no
27
+ * LLM call, and runs on ANY provider, including the ones that report no usage
28
+ * at all. Nothing here is unmeasurable, so nothing here throws.
29
+ */
30
+ Object.defineProperty(exports, "__esModule", { value: true });
31
+ exports.slidingWindow = exports.SLIDING_WINDOW = void 0;
32
+ const drop_js_1 = require("./drop.js");
33
+ const options_js_1 = require("../options.js");
34
+ /** `WindowRecord.strategy` written by every record this strategy files. */
35
+ exports.SLIDING_WINDOW = 'sliding-window';
36
+ /**
37
+ * Keep the most recent `keepRecentTurns` turns in the live window and drop
38
+ * the older ones — except anything that refuses.
39
+ *
40
+ * @example
41
+ * ```ts
42
+ * import { Agent, slidingWindow } from 'agentfootprint';
43
+ * import { ollama } from 'agentfootprint/llm-providers';
44
+ *
45
+ * // Works on a provider that reports no usage at all: the trigger is turns.
46
+ * const agent = Agent.create({ provider: ollama(), model: 'llama3' })
47
+ * .window(slidingWindow({ keepRecentTurns: 12 }))
48
+ * .build();
49
+ * ```
50
+ */
51
+ function slidingWindow(options) {
52
+ const config = (0, options_js_1.resolveSlidingWindowOptions)(options, 'slidingWindow');
53
+ return {
54
+ name: exports.SLIDING_WINDOW,
55
+ async plan(input) {
56
+ // Did not engage: the window is already within its target depth. No
57
+ // record — the ledger tracks what this strategy DID, not every time it
58
+ // looked and there was nothing to do.
59
+ if (input.turns.length <= config.keepRecentTurns)
60
+ return undefined;
61
+ const outcome = (0, drop_js_1.dropOldestSpan)(input, config.keepRecentTurns, exports.SLIDING_WINDOW);
62
+ const record = {
63
+ strategy: exports.SLIDING_WINDOW,
64
+ iteration: input.iteration,
65
+ keepRecentTurns: config.keepRecentTurns,
66
+ removedStageIds: outcome.removedStageIds,
67
+ removedMessageCount: outcome.removedMessageCount,
68
+ windowCharsBefore: outcome.windowCharsBefore,
69
+ windowCharsAfter: outcome.windowCharsAfter,
70
+ turnsBefore: outcome.turnsBefore,
71
+ turnsAfter: outcome.turnsAfter,
72
+ refusals: outcome.refusals,
73
+ };
74
+ // No `budgetPressure`: this strategy has no token budget. Reporting a
75
+ // cap nobody configured would be the invented number the family exists
76
+ // to refuse — so it reports evictions and stays quiet about budgets.
77
+ return {
78
+ ...(outcome.window !== undefined && { window: outcome.window }),
79
+ ...(outcome.rebase !== undefined && { rebase: outcome.rebase }),
80
+ record,
81
+ evictions: outcome.evictions,
82
+ };
83
+ },
84
+ };
85
+ }
86
+ exports.slidingWindow = slidingWindow;
87
+ //# sourceMappingURL=slidingWindow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slidingWindow.js","sourceRoot":"","sources":["../../../../../src/core/agent/window/strategies/slidingWindow.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;;;AAEH,uCAA2C;AAC3C,8CAA4D;AAI5D,2EAA2E;AAC9D,QAAA,cAAc,GAAG,gBAAgB,CAAC;AAE/C;;;;;;;;;;;;;;GAcG;AACH,SAAgB,aAAa,CAAC,OAA6B;IACzD,MAAM,MAAM,GAAG,IAAA,wCAA2B,EAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAErE,OAAO;QACL,IAAI,EAAE,sBAAc;QAEpB,KAAK,CAAC,IAAI,CAAC,KAA0B;YACnC,oEAAoE;YACpE,uEAAuE;YACvE,sCAAsC;YACtC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC,eAAe;gBAAE,OAAO,SAAS,CAAC;YAEnE,MAAM,OAAO,GAAG,IAAA,wBAAc,EAAC,KAAK,EAAE,MAAM,CAAC,eAAe,EAAE,sBAAc,CAAC,CAAC;YAC9E,MAAM,MAAM,GAAwB;gBAClC,QAAQ,EAAE,sBAAc;gBACxB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,eAAe,EAAE,MAAM,CAAC,eAAe;gBACvC,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;gBAChD,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;gBAC5C,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;gBAC1C,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,QAAQ,EAAE,OAAO,CAAC,QAAQ;aAC3B,CAAC;YAEF,sEAAsE;YACtE,uEAAuE;YACvE,qEAAqE;YACrE,OAAO;gBACL,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC/D,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC/D,MAAM;gBACN,SAAS,EAAE,OAAO,CAAC,SAAS;aAC7B,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AArCD,sCAqCC"}
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ /**
3
+ * summarizeOldest — fold the oldest foldable turns into one summary message.
4
+ *
5
+ * Pattern: WindowStrategy implementation. Its own module, importing nothing
6
+ * that registers anything, so a bundle that never mentions it never
7
+ * carries it (and never carries the summarizer machinery either).
8
+ * Role: core/ layer.
9
+ * Emits: N/A — the stage emits, records and costs; this file decides.
10
+ *
11
+ * This is what `.compaction({...})` configures, and the market's familiar
12
+ * move (Claude Code / the Claude Agent SDK call it compaction). What is
13
+ * different here is not the fold — it is that the fold is filed as a claim:
14
+ * a summary is a claim ABOUT the past, and the past itself stays in the
15
+ * commit log, byte for byte.
16
+ *
17
+ * Everything it decides, it explains. Every engaged path returns a record —
18
+ * including the paths that change nothing, which are the ones a person
19
+ * debugging an over-budget window actually needs.
20
+ */
21
+ Object.defineProperty(exports, "__esModule", { value: true });
22
+ exports.summarizeOldest = exports.SUMMARIZE_OLDEST = void 0;
23
+ const errors_js_1 = require("../errors.js");
24
+ const options_js_1 = require("../options.js");
25
+ const removal_js_1 = require("../removal.js");
26
+ const summarize_js_1 = require("../summarize.js");
27
+ const turns_js_1 = require("../turns.js");
28
+ /** `WindowRecord.strategy` written by every record this strategy files. */
29
+ exports.SUMMARIZE_OLDEST = 'summarize-oldest';
30
+ /**
31
+ * Fold the oldest contiguous run of foldable turns into one summary message,
32
+ * keeping the recent turns and stepping over anything unresolved.
33
+ *
34
+ * Triggered by COUNTED tokens: the last call's adapter-reported input tokens
35
+ * against `thresholdTokens`. A provider that reports no usage gets
36
+ * `CompactionUnmeasurableError` rather than an invented number.
37
+ *
38
+ * @example
39
+ * ```ts
40
+ * import { Agent, summarizeOldest } from 'agentfootprint';
41
+ *
42
+ * const agent = Agent.create({ provider: anthropic(), model: 'claude-sonnet-4-5' })
43
+ * .window(summarizeOldest({ thresholdTokens: 120_000, summarizer: anthropic() }))
44
+ * .build();
45
+ * // `.compaction({ ... })` is this exact line, spelled shorter.
46
+ * ```
47
+ */
48
+ function summarizeOldest(options) {
49
+ const config = (0, options_js_1.resolveCompactionOptions)(options, 'summarizeOldest');
50
+ return {
51
+ name: exports.SUMMARIZE_OLDEST,
52
+ async plan(input) {
53
+ const { history, turns, iteration, measured } = input;
54
+ // Iteration 1: nothing has been sent, so nothing has been counted. A
55
+ // compactor that acted here would be guessing.
56
+ if (measured === undefined)
57
+ return undefined;
58
+ if (measured.input === 0 && measured.output === 0) {
59
+ throw new errors_js_1.CompactionUnmeasurableError(input.providerName);
60
+ }
61
+ if (measured.input <= config.thresholdTokens)
62
+ return undefined;
63
+ const model = config.model ?? input.agentModel;
64
+ const charsBefore = (0, turns_js_1.windowChars)(history);
65
+ const base = {
66
+ strategy: exports.SUMMARIZE_OLDEST,
67
+ iteration,
68
+ measuredTokens: measured.input,
69
+ thresholdTokens: config.thresholdTokens,
70
+ overBudget: true,
71
+ windowCharsBefore: charsBefore,
72
+ };
73
+ const unchanged = (refusals, extra = {}) => ({
74
+ record: {
75
+ ...base,
76
+ removedStageIds: [],
77
+ removedMessageCount: 0,
78
+ foldedStageIds: [],
79
+ foldedMessageCount: 0,
80
+ windowCharsAfter: charsBefore,
81
+ summaryChars: 0,
82
+ refusals,
83
+ ...extra,
84
+ },
85
+ evictions: [],
86
+ budgetPressure: {
87
+ capTokens: config.thresholdTokens,
88
+ projectedTokens: measured.input,
89
+ planAction: 'none',
90
+ },
91
+ });
92
+ const plan = input.planRemoval(config.keepRecentTurns, (turn) => (0, summarize_js_1.isCompactedSummary)(turn.messages[0]));
93
+ if (plan.from === -1) {
94
+ // Nothing foldable. The window stays over budget and the run proceeds
95
+ // — reported, not silently truncated.
96
+ return unchanged(plan.refusals);
97
+ }
98
+ const spanStart = turns[plan.from].start;
99
+ const spanEnd = turns[plan.to].start + turns[plan.to].length;
100
+ const head = history.slice(0, spanStart);
101
+ const span = history.slice(spanStart, spanEnd);
102
+ const tail = history.slice(spanEnd);
103
+ // A broken summarizer must not take down the run.
104
+ let summary;
105
+ try {
106
+ const result = await (0, summarize_js_1.runSummarizer)(config.summarizer, model, span, input.signal);
107
+ summary = {
108
+ text: result.text,
109
+ usage: { input: result.usage.input, output: result.usage.output },
110
+ };
111
+ }
112
+ catch (err) {
113
+ return {
114
+ ...unchanged([
115
+ { reason: 'summarizer-failed', turnIndex: plan.from, messageIndex: spanStart },
116
+ ...plan.refusals,
117
+ ]),
118
+ warning: `the summarizer threw, so nothing was folded this iteration and the window ` +
119
+ `stays over budget (${measured.input} tokens vs a threshold of ` +
120
+ `${config.thresholdTokens}). The run continues. Cause: ` +
121
+ `${err instanceof Error ? err.message : String(err)}`,
122
+ };
123
+ }
124
+ const summaryMessage = (0, summarize_js_1.buildSummaryMessage)(summary.text, {
125
+ foldedMessageCount: span.length,
126
+ iteration,
127
+ model,
128
+ });
129
+ const spend = { model, usage: summary.usage };
130
+ // Would the fold actually help? A summary plus its authored frame can be
131
+ // LONGER than a handful of short turns; folding then spends a call to
132
+ // grow the window and lose detail at the same time. Both sides are
133
+ // measured in chars — one unit, an exact comparison, not a token guess.
134
+ if (summaryMessage.content.length >= (0, turns_js_1.windowChars)(span)) {
135
+ return {
136
+ ...unchanged([
137
+ { reason: 'summary-not-smaller', turnIndex: plan.from, messageIndex: spanStart },
138
+ ...plan.refusals,
139
+ ], { summaryChars: summaryMessage.content.length, summarizerTokens: summary.usage }),
140
+ spend, // the call still happened, so it still counts
141
+ };
142
+ }
143
+ const foldedAtMs = input.now();
144
+ const facts = input.removalFacts((0, removal_js_1.indexRange)(spanStart, spanEnd), foldedAtMs);
145
+ const window = [...head, summaryMessage, ...tail];
146
+ const record = {
147
+ ...base,
148
+ removedStageIds: facts.removedStageIds,
149
+ removedMessageCount: span.length,
150
+ // The 7.16 names for the two values above, kept and deprecated.
151
+ foldedStageIds: facts.removedStageIds,
152
+ foldedMessageCount: span.length,
153
+ windowCharsAfter: (0, turns_js_1.windowChars)(window),
154
+ summaryChars: summaryMessage.content.length,
155
+ summarizerTokens: summary.usage,
156
+ refusals: plan.refusals,
157
+ };
158
+ return {
159
+ window,
160
+ rebase: {
161
+ headCount: head.length,
162
+ keptTailCount: tail.length,
163
+ insertedAtMs: foldedAtMs,
164
+ },
165
+ record,
166
+ evictions: facts.evictions,
167
+ budgetPressure: {
168
+ capTokens: config.thresholdTokens,
169
+ projectedTokens: measured.input,
170
+ planAction: 'summarize',
171
+ },
172
+ spend,
173
+ };
174
+ },
175
+ };
176
+ }
177
+ exports.summarizeOldest = summarizeOldest;
178
+ //# sourceMappingURL=summarizeOldest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarizeOldest.js","sourceRoot":"","sources":["../../../../../src/core/agent/window/strategies/summarizeOldest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ /**
3
+ * tokenBudget — compaction's trigger discipline, without the summarizer.
4
+ *
5
+ * Pattern: WindowStrategy implementation. Its own module, registering
6
+ * nothing at import.
7
+ * Role: core/ layer.
8
+ * Emits: N/A — the stage emits, records and costs; this file decides.
9
+ *
10
+ * The market's other familiar policy: cap the window at a token budget
11
+ * (Mastra's `TokenLimiter` is the closest sibling). What is different here is
12
+ * the same thing that is different about compaction — the number is COUNTED,
13
+ * never guessed:
14
+ *
15
+ * • the trigger reads the input tokens the PROVIDER reported for the last
16
+ * call, not a character estimate and not a divide-by-four heuristic;
17
+ * • a provider that reports no usage gets `CompactionUnmeasurableError` by
18
+ * name, the same refusal `.compaction()` makes, rather than an invented
19
+ * window size or a configured budget that silently never applies.
20
+ *
21
+ * When over budget it drops the oldest contiguous removable span — the same
22
+ * span compaction would have folded, chosen by the same refusal engine — and
23
+ * writes no summary at all. Nothing is claimed about what left, because
24
+ * nothing was read: the record and the eviction events name it, and the
25
+ * commit log still has it verbatim.
26
+ *
27
+ * Use it over `summarizeOldest` when you would rather lose the old turns than
28
+ * pay a summarizer to paraphrase them, and over `slidingWindow` when the
29
+ * thing you are actually defending is a token bill rather than a turn depth.
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.tokenBudget = exports.TOKEN_BUDGET = void 0;
33
+ const drop_js_1 = require("./drop.js");
34
+ const errors_js_1 = require("../errors.js");
35
+ const options_js_1 = require("../options.js");
36
+ /** `WindowRecord.strategy` written by every record this strategy files. */
37
+ exports.TOKEN_BUDGET = 'token-budget';
38
+ /**
39
+ * Drop the oldest turns whenever the last call's adapter-reported input
40
+ * tokens exceed `thresholdTokens`.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { Agent, tokenBudget } from 'agentfootprint';
45
+ *
46
+ * const agent = Agent.create({ provider: anthropic(), model: 'claude-sonnet-4-5' })
47
+ * .window(tokenBudget({ thresholdTokens: 120_000 }))
48
+ * .build();
49
+ * ```
50
+ */
51
+ function tokenBudget(options) {
52
+ const config = (0, options_js_1.resolveTokenBudgetOptions)(options, 'tokenBudget');
53
+ return {
54
+ name: exports.TOKEN_BUDGET,
55
+ async plan(input) {
56
+ const { measured } = input;
57
+ // Iteration 1: nothing has been sent, so nothing has been counted.
58
+ if (measured === undefined)
59
+ return undefined;
60
+ // Counted, not guessed — the same wall compaction hits, by the same name.
61
+ if (measured.input === 0 && measured.output === 0) {
62
+ throw new errors_js_1.CompactionUnmeasurableError(input.providerName);
63
+ }
64
+ if (measured.input <= config.thresholdTokens)
65
+ return undefined;
66
+ const outcome = (0, drop_js_1.dropOldestSpan)(input, config.keepRecentTurns, exports.TOKEN_BUDGET);
67
+ const record = {
68
+ strategy: exports.TOKEN_BUDGET,
69
+ iteration: input.iteration,
70
+ measuredTokens: measured.input,
71
+ thresholdTokens: config.thresholdTokens,
72
+ overBudget: true,
73
+ keepRecentTurns: config.keepRecentTurns,
74
+ removedStageIds: outcome.removedStageIds,
75
+ removedMessageCount: outcome.removedMessageCount,
76
+ windowCharsBefore: outcome.windowCharsBefore,
77
+ windowCharsAfter: outcome.windowCharsAfter,
78
+ refusals: outcome.refusals,
79
+ };
80
+ return {
81
+ ...(outcome.window !== undefined && { window: outcome.window }),
82
+ ...(outcome.rebase !== undefined && { rebase: outcome.rebase }),
83
+ record,
84
+ evictions: outcome.evictions,
85
+ budgetPressure: {
86
+ capTokens: config.thresholdTokens,
87
+ projectedTokens: measured.input,
88
+ planAction: outcome.removedMessageCount > 0 ? 'evict' : 'none',
89
+ },
90
+ };
91
+ },
92
+ };
93
+ }
94
+ exports.tokenBudget = tokenBudget;
95
+ //# sourceMappingURL=tokenBudget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenBudget.js","sourceRoot":"","sources":["../../../../../src/core/agent/window/strategies/tokenBudget.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;;;AAEH,uCAA2C;AAC3C,4CAA2D;AAC3D,8CAA0D;AAI1D,2EAA2E;AAC9D,QAAA,YAAY,GAAG,cAAc,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,SAAgB,WAAW,CAAC,OAA2B;IACrD,MAAM,MAAM,GAAG,IAAA,sCAAyB,EAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAEjE,OAAO;QACL,IAAI,EAAE,oBAAY;QAElB,KAAK,CAAC,IAAI,CAAC,KAA0B;YACnC,MAAM,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;YAE3B,mEAAmE;YACnE,IAAI,QAAQ,KAAK,SAAS;gBAAE,OAAO,SAAS,CAAC;YAC7C,0EAA0E;YAC1E,IAAI,QAAQ,CAAC,KAAK,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClD,MAAM,IAAI,uCAA2B,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YAC5D,CAAC;YACD,IAAI,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,eAAe;gBAAE,OAAO,SAAS,CAAC;YAE/D,MAAM,OAAO,GAAG,IAAA,wBAAc,EAAC,KAAK,EAAE,MAAM,CAAC,eAAe,EAAE,oBAAY,CAAC,CAAC;YAC5E,MAAM,MAAM,GAAsB;gBAChC,QAAQ,EAAE,oBAAY;gBACtB,SAAS,EAAE,KAAK,CAAC,SAAS;gBAC1B,cAAc,EAAE,QAAQ,CAAC,KAAK;gBAC9B,eAAe,EAAE,MAAM,CAAC,eAAe;gBACvC,UAAU,EAAE,IAAI;gBAChB,eAAe,EAAE,MAAM,CAAC,eAAe;gBACvC,eAAe,EAAE,OAAO,CAAC,eAAe;gBACxC,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;gBAChD,iBAAiB,EAAE,OAAO,CAAC,iBAAiB;gBAC5C,gBAAgB,EAAE,OAAO,CAAC,gBAAgB;gBAC1C,QAAQ,EAAE,OAAO,CAAC,QAAQ;aAC3B,CAAC;YAEF,OAAO;gBACL,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC/D,GAAG,CAAC,OAAO,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC/D,MAAM;gBACN,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,cAAc,EAAE;oBACd,SAAS,EAAE,MAAM,CAAC,eAAe;oBACjC,eAAe,EAAE,QAAQ,CAAC,KAAK;oBAC/B,UAAU,EAAE,OAAO,CAAC,mBAAmB,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM;iBAC/D;aACF,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AA7CD,kCA6CC"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /**
3
+ * window/strategy — PUBLIC. How a window strategy is shaped.
4
+ *
5
+ * Pattern: Strategy (GoF), with the dangerous half of the decision handed in
6
+ * pre-bound rather than left to the implementer to re-derive.
7
+ * Role: core/ layer. The window stage does the wiring — read the meter,
8
+ * write the window, emit, record, cost — and delegates the one
9
+ * interesting question to a strategy:
10
+ *
11
+ * given the segmented turns and what the provider actually
12
+ * counted → what should the window become, and what does the
13
+ * ledger need to be told about it?
14
+ *
15
+ * Emits: N/A. A strategy is pure decision + (optionally) its own LLM call;
16
+ * it never touches scope, never emits, and never writes. That is
17
+ * what makes it testable without a chart, and what keeps the
18
+ * "record everything you did" duty in ONE place (the stage) rather
19
+ * than duplicated per strategy.
20
+ *
21
+ * Three strategies ship — `summarizeOldest` (what `.compaction()`
22
+ * configures), `slidingWindow`, `tokenBudget` — and `.window(...)` takes any
23
+ * object that satisfies `WindowStrategy`.
24
+ *
25
+ * Two things are deliberately NOT left to the implementer:
26
+ *
27
+ * 1. **The refusal rules.** `planRemoval` arrives already bound to this
28
+ * iteration's turns and guards. A strategy cannot forget that an
29
+ * unanswered tool call must not leave the window, because it never gets
30
+ * the chance to decide that for itself — it asks, and it is told, with
31
+ * every refusal named. That is safety by construction, not by docs.
32
+ * 2. **Provenance.** `removalFacts` turns "these indices left" into the
33
+ * stage ids that wrote them and how long each lived. A strategy cannot
34
+ * file a removal it cannot name.
35
+ *
36
+ * The TRIGGER, by contrast, is entirely the strategy's own: `plan` is called
37
+ * at every ReAct iteration boundary and answers `undefined` when it did not
38
+ * engage. That is why `slidingWindow` can run on a provider that reports no
39
+ * usage at all while `summarizeOldest` and `tokenBudget` refuse by name.
40
+ */
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ //# sourceMappingURL=strategy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strategy.js","sourceRoot":"","sources":["../../../../src/core/agent/window/strategy.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG"}