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.
- package/dist/adapters/llm/BrowserOpenAIProvider.js +7 -3
- package/dist/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/adapters/llm/OpenAIProvider.js +11 -3
- package/dist/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/conventions.js +9 -0
- package/dist/conventions.js.map +1 -1
- package/dist/core/Agent.js +61 -2
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/agent/AgentBuilder.js +136 -1
- package/dist/core/agent/AgentBuilder.js.map +1 -1
- package/dist/core/agent/buildAgentChart.js +12 -1
- package/dist/core/agent/buildAgentChart.js.map +1 -1
- package/dist/core/agent/buildDynamicAgentChart.js +10 -1
- package/dist/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/core/agent/stages/window.js +141 -0
- package/dist/core/agent/stages/window.js.map +1 -0
- package/dist/core/agent/window/errors.js +40 -0
- package/dist/core/agent/window/errors.js.map +1 -0
- package/dist/core/agent/window/index.js +36 -0
- package/dist/core/agent/window/index.js.map +1 -0
- package/dist/core/agent/window/notice.js +57 -0
- package/dist/core/agent/window/notice.js.map +1 -0
- package/dist/core/agent/window/options.js +93 -0
- package/dist/core/agent/window/options.js.map +1 -0
- package/dist/core/agent/window/removal.js +45 -0
- package/dist/core/agent/window/removal.js.map +1 -0
- package/dist/core/agent/window/strategies/drop.js +106 -0
- package/dist/core/agent/window/strategies/drop.js.map +1 -0
- package/dist/core/agent/window/strategies/slidingWindow.js +87 -0
- package/dist/core/agent/window/strategies/slidingWindow.js.map +1 -0
- package/dist/core/agent/window/strategies/summarizeOldest.js +178 -0
- package/dist/core/agent/window/strategies/summarizeOldest.js.map +1 -0
- package/dist/core/agent/window/strategies/tokenBudget.js +95 -0
- package/dist/core/agent/window/strategies/tokenBudget.js.map +1 -0
- package/dist/core/agent/window/strategy.js +42 -0
- package/dist/core/agent/window/strategy.js.map +1 -0
- package/dist/core/agent/window/summarize.js +103 -0
- package/dist/core/agent/window/summarize.js.map +1 -0
- package/dist/core/agent/window/turns.js +175 -0
- package/dist/core/agent/window/turns.js.map +1 -0
- package/dist/core/agent/window/types.js +23 -0
- package/dist/core/agent/window/types.js.map +1 -0
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.js +7 -3
- package/dist/esm/adapters/llm/BrowserOpenAIProvider.js.map +1 -1
- package/dist/esm/adapters/llm/OpenAIProvider.js +11 -3
- package/dist/esm/adapters/llm/OpenAIProvider.js.map +1 -1
- package/dist/esm/conventions.d.ts +9 -0
- package/dist/esm/conventions.js +9 -0
- package/dist/esm/conventions.js.map +1 -1
- package/dist/esm/core/Agent.d.ts +8 -1
- package/dist/esm/core/Agent.js +61 -2
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/agent/AgentBuilder.d.ts +99 -0
- package/dist/esm/core/agent/AgentBuilder.js +136 -1
- package/dist/esm/core/agent/AgentBuilder.js.map +1 -1
- package/dist/esm/core/agent/buildAgentChart.d.ts +20 -0
- package/dist/esm/core/agent/buildAgentChart.js +12 -1
- package/dist/esm/core/agent/buildAgentChart.js.map +1 -1
- package/dist/esm/core/agent/buildDynamicAgentChart.js +10 -1
- package/dist/esm/core/agent/buildDynamicAgentChart.js.map +1 -1
- package/dist/esm/core/agent/stages/window.d.ts +63 -0
- package/dist/esm/core/agent/stages/window.js +137 -0
- package/dist/esm/core/agent/stages/window.js.map +1 -0
- package/dist/esm/core/agent/types.d.ts +18 -0
- package/dist/esm/core/agent/window/errors.d.ts +26 -0
- package/dist/esm/core/agent/window/errors.js +36 -0
- package/dist/esm/core/agent/window/errors.js.map +1 -0
- package/dist/esm/core/agent/window/index.d.ts +27 -0
- package/dist/esm/core/agent/window/index.js +25 -0
- package/dist/esm/core/agent/window/index.js.map +1 -0
- package/dist/esm/core/agent/window/notice.d.ts +46 -0
- package/dist/esm/core/agent/window/notice.js +52 -0
- package/dist/esm/core/agent/window/notice.js.map +1 -0
- package/dist/esm/core/agent/window/options.d.ts +33 -0
- package/dist/esm/core/agent/window/options.js +87 -0
- package/dist/esm/core/agent/window/options.js.map +1 -0
- package/dist/esm/core/agent/window/removal.d.ts +22 -0
- package/dist/esm/core/agent/window/removal.js +40 -0
- package/dist/esm/core/agent/window/removal.js.map +1 -0
- package/dist/esm/core/agent/window/strategies/drop.d.ts +54 -0
- package/dist/esm/core/agent/window/strategies/drop.js +102 -0
- package/dist/esm/core/agent/window/strategies/drop.js.map +1 -0
- package/dist/esm/core/agent/window/strategies/slidingWindow.d.ts +48 -0
- package/dist/esm/core/agent/window/strategies/slidingWindow.js +83 -0
- package/dist/esm/core/agent/window/strategies/slidingWindow.js.map +1 -0
- package/dist/esm/core/agent/window/strategies/summarizeOldest.d.ts +42 -0
- package/dist/esm/core/agent/window/strategies/summarizeOldest.js +174 -0
- package/dist/esm/core/agent/window/strategies/summarizeOldest.js.map +1 -0
- package/dist/esm/core/agent/window/strategies/tokenBudget.d.ts +47 -0
- package/dist/esm/core/agent/window/strategies/tokenBudget.js +91 -0
- package/dist/esm/core/agent/window/strategies/tokenBudget.js.map +1 -0
- package/dist/esm/core/agent/window/strategy.d.ts +181 -0
- package/dist/esm/core/agent/window/strategy.js +41 -0
- package/dist/esm/core/agent/window/strategy.js.map +1 -0
- package/dist/esm/core/agent/window/summarize.d.ts +61 -0
- package/dist/esm/core/agent/window/summarize.js +96 -0
- package/dist/esm/core/agent/window/summarize.js.map +1 -0
- package/dist/esm/core/agent/window/turns.d.ts +108 -0
- package/dist/esm/core/agent/window/turns.js +167 -0
- package/dist/esm/core/agent/window/turns.js.map +1 -0
- package/dist/esm/core/agent/window/types.d.ts +263 -0
- package/dist/esm/core/agent/window/types.js +22 -0
- package/dist/esm/core/agent/window/types.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/recorders/core/CompactionMeter.d.ts +84 -0
- package/dist/esm/recorders/core/CompactionMeter.js +109 -0
- package/dist/esm/recorders/core/CompactionMeter.js.map +1 -0
- package/dist/index.js +23 -5
- package/dist/index.js.map +1 -1
- package/dist/recorders/core/CompactionMeter.js +113 -0
- package/dist/recorders/core/CompactionMeter.js.map +1 -0
- package/dist/types/adapters/llm/BrowserOpenAIProvider.d.ts.map +1 -1
- package/dist/types/adapters/llm/OpenAIProvider.d.ts.map +1 -1
- package/dist/types/conventions.d.ts +9 -0
- package/dist/types/conventions.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +8 -1
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/agent/AgentBuilder.d.ts +99 -0
- package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -1
- package/dist/types/core/agent/buildAgentChart.d.ts +20 -0
- package/dist/types/core/agent/buildAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/buildDynamicAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/stages/window.d.ts +64 -0
- package/dist/types/core/agent/stages/window.d.ts.map +1 -0
- package/dist/types/core/agent/types.d.ts +18 -0
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/agent/window/errors.d.ts +27 -0
- package/dist/types/core/agent/window/errors.d.ts.map +1 -0
- package/dist/types/core/agent/window/index.d.ts +28 -0
- package/dist/types/core/agent/window/index.d.ts.map +1 -0
- package/dist/types/core/agent/window/notice.d.ts +47 -0
- package/dist/types/core/agent/window/notice.d.ts.map +1 -0
- package/dist/types/core/agent/window/options.d.ts +34 -0
- package/dist/types/core/agent/window/options.d.ts.map +1 -0
- package/dist/types/core/agent/window/removal.d.ts +23 -0
- package/dist/types/core/agent/window/removal.d.ts.map +1 -0
- package/dist/types/core/agent/window/strategies/drop.d.ts +55 -0
- package/dist/types/core/agent/window/strategies/drop.d.ts.map +1 -0
- package/dist/types/core/agent/window/strategies/slidingWindow.d.ts +49 -0
- package/dist/types/core/agent/window/strategies/slidingWindow.d.ts.map +1 -0
- package/dist/types/core/agent/window/strategies/summarizeOldest.d.ts +43 -0
- package/dist/types/core/agent/window/strategies/summarizeOldest.d.ts.map +1 -0
- package/dist/types/core/agent/window/strategies/tokenBudget.d.ts +48 -0
- package/dist/types/core/agent/window/strategies/tokenBudget.d.ts.map +1 -0
- package/dist/types/core/agent/window/strategy.d.ts +182 -0
- package/dist/types/core/agent/window/strategy.d.ts.map +1 -0
- package/dist/types/core/agent/window/summarize.d.ts +62 -0
- package/dist/types/core/agent/window/summarize.d.ts.map +1 -0
- package/dist/types/core/agent/window/turns.d.ts +109 -0
- package/dist/types/core/agent/window/turns.d.ts.map +1 -0
- package/dist/types/core/agent/window/types.d.ts +264 -0
- package/dist/types/core/agent/window/types.d.ts.map +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/recorders/core/CompactionMeter.d.ts +85 -0
- package/dist/types/recorders/core/CompactionMeter.d.ts.map +1 -0
- 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"}
|