@animalabs/context-manager 0.5.5 → 0.5.9
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/src/adaptive/kv-control.d.ts +69 -32
- package/dist/src/adaptive/kv-control.d.ts.map +1 -1
- package/dist/src/adaptive/kv-control.js +471 -172
- package/dist/src/adaptive/kv-control.js.map +1 -1
- package/dist/src/adaptive/picker.d.ts +8 -0
- package/dist/src/adaptive/picker.d.ts.map +1 -1
- package/dist/src/adaptive/picker.js.map +1 -1
- package/dist/src/adaptive/strategies/kv-stable.d.ts +12 -4
- package/dist/src/adaptive/strategies/kv-stable.d.ts.map +1 -1
- package/dist/src/adaptive/strategies/kv-stable.js +14 -5
- package/dist/src/adaptive/strategies/kv-stable.js.map +1 -1
- package/dist/src/context-log.d.ts.map +1 -1
- package/dist/src/context-log.js +11 -0
- package/dist/src/context-log.js.map +1 -1
- package/dist/src/context-manager.d.ts +28 -1
- package/dist/src/context-manager.d.ts.map +1 -1
- package/dist/src/context-manager.js +42 -0
- package/dist/src/context-manager.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/message-store.d.ts +60 -0
- package/dist/src/message-store.d.ts.map +1 -1
- package/dist/src/message-store.js +165 -10
- package/dist/src/message-store.js.map +1 -1
- package/dist/src/strategies/autobiographical.d.ts +207 -2
- package/dist/src/strategies/autobiographical.d.ts.map +1 -1
- package/dist/src/strategies/autobiographical.js +1283 -124
- package/dist/src/strategies/autobiographical.js.map +1 -1
- package/dist/src/strategies/index.d.ts +1 -1
- package/dist/src/strategies/index.d.ts.map +1 -1
- package/dist/src/strategies/index.js.map +1 -1
- package/dist/src/strategies/knowledge.d.ts +8 -0
- package/dist/src/strategies/knowledge.d.ts.map +1 -1
- package/dist/src/strategies/knowledge.js +23 -1
- package/dist/src/strategies/knowledge.js.map +1 -1
- package/dist/src/types/strategy.d.ts +82 -5
- package/dist/src/types/strategy.d.ts.map +1 -1
- package/dist/src/types/strategy.js.map +1 -1
- package/dist/test/adaptive/doc-plus-chat.test.js +7 -3
- package/dist/test/adaptive/doc-plus-chat.test.js.map +1 -1
- package/dist/test/adaptive/hard-fail.test.js +22 -0
- package/dist/test/adaptive/hard-fail.test.js.map +1 -1
- package/dist/test/adaptive/ingestion.test.js +3 -1
- package/dist/test/adaptive/ingestion.test.js.map +1 -1
- package/dist/test/adaptive/kv-control.test.js +17 -11
- package/dist/test/adaptive/kv-control.test.js.map +1 -1
- package/dist/test/adaptive/single-path-solve.test.d.ts +16 -0
- package/dist/test/adaptive/single-path-solve.test.d.ts.map +1 -0
- package/dist/test/adaptive/single-path-solve.test.js +204 -0
- package/dist/test/adaptive/single-path-solve.test.js.map +1 -0
- package/dist/test/anti-redundancy-budget.test.d.ts +17 -0
- package/dist/test/anti-redundancy-budget.test.d.ts.map +1 -0
- package/dist/test/anti-redundancy-budget.test.js +197 -0
- package/dist/test/anti-redundancy-budget.test.js.map +1 -0
- package/dist/test/chunk-persistence.test.d.ts +29 -0
- package/dist/test/chunk-persistence.test.d.ts.map +1 -0
- package/dist/test/chunk-persistence.test.js +290 -0
- package/dist/test/chunk-persistence.test.js.map +1 -0
- package/dist/test/compression-dedup.test.d.ts +20 -0
- package/dist/test/compression-dedup.test.d.ts.map +1 -0
- package/dist/test/compression-dedup.test.js +92 -0
- package/dist/test/compression-dedup.test.js.map +1 -0
- package/dist/test/compression-shape-invariants.test.js +40 -3
- package/dist/test/compression-shape-invariants.test.js.map +1 -1
- package/dist/test/head-window-order.test.d.ts +19 -0
- package/dist/test/head-window-order.test.d.ts.map +1 -0
- package/dist/test/head-window-order.test.js +159 -0
- package/dist/test/head-window-order.test.js.map +1 -0
- package/dist/test/image-strip-render-stats.test.js +25 -3
- package/dist/test/image-strip-render-stats.test.js.map +1 -1
- package/dist/test/knowledge-tool-boundary.test.d.ts +14 -0
- package/dist/test/knowledge-tool-boundary.test.d.ts.map +1 -0
- package/dist/test/knowledge-tool-boundary.test.js +93 -0
- package/dist/test/knowledge-tool-boundary.test.js.map +1 -0
- package/dist/test/l1-holdback.test.d.ts +15 -0
- package/dist/test/l1-holdback.test.d.ts.map +1 -0
- package/dist/test/l1-holdback.test.js +119 -0
- package/dist/test/l1-holdback.test.js.map +1 -0
- package/dist/test/merge-contiguity.test.d.ts +11 -0
- package/dist/test/merge-contiguity.test.d.ts.map +1 -0
- package/dist/test/merge-contiguity.test.js +74 -0
- package/dist/test/merge-contiguity.test.js.map +1 -0
- package/dist/test/message-store-window.test.d.ts +13 -0
- package/dist/test/message-store-window.test.d.ts.map +1 -0
- package/dist/test/message-store-window.test.js +177 -0
- package/dist/test/message-store-window.test.js.map +1 -0
- package/dist/test/speculation-cap.test.js +4 -0
- package/dist/test/speculation-cap.test.js.map +1 -1
- package/dist/test/summary-log-consistency.test.d.ts +18 -0
- package/dist/test/summary-log-consistency.test.d.ts.map +1 -0
- package/dist/test/summary-log-consistency.test.js +97 -0
- package/dist/test/summary-log-consistency.test.js.map +1 -0
- package/dist/test/tool-pairing-invariant.test.d.ts +15 -0
- package/dist/test/tool-pairing-invariant.test.d.ts.map +1 -0
- package/dist/test/tool-pairing-invariant.test.js +225 -0
- package/dist/test/tool-pairing-invariant.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -3
- package/src/adaptive/kv-control.ts +509 -184
- package/src/adaptive/picker.ts +8 -0
- package/src/adaptive/strategies/kv-stable.ts +22 -10
- package/src/context-log.ts +11 -0
- package/src/context-manager.ts +48 -2
- package/src/index.ts +3 -2
- package/src/message-store.ts +202 -9
- package/src/strategies/autobiographical.ts +1343 -148
- package/src/strategies/index.ts +1 -1
- package/src/strategies/knowledge.ts +25 -1
- package/src/types/strategy.ts +89 -5
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression tests for the "68 initiations" confabulation incident
|
|
3
|
+
* (Lena, 2026-06-29..07-02).
|
|
4
|
+
*
|
|
5
|
+
* Root cause: `compressChunkHierarchical` emitted the raw head window
|
|
6
|
+
* AFTER the prior recall pairs, so the summarizer read the chronicle's
|
|
7
|
+
* opening as the most recent live conversation. For thin chunks (silent
|
|
8
|
+
* turns + heartbeat traffic) it then narrated the head as fresh events
|
|
9
|
+
* ("Antra came to me to explore the transformation story again…"),
|
|
10
|
+
* and L2/L3 merges compounded those into runaway false memories.
|
|
11
|
+
*
|
|
12
|
+
* Invariants pinned here:
|
|
13
|
+
* 1. In every L1 compression request, head-window content precedes
|
|
14
|
+
* the first "[CM] Recall memory" pair (chronological order).
|
|
15
|
+
* 2. Chunks with (almost) no substantive text are stubbed
|
|
16
|
+
* mechanically — no LLM call, non-empty stub content.
|
|
17
|
+
*/
|
|
18
|
+
import { describe, it, before, after } from 'node:test';
|
|
19
|
+
import assert from 'node:assert';
|
|
20
|
+
import { rmSync, existsSync } from 'node:fs';
|
|
21
|
+
import { ContextManager, AutobiographicalStrategy } from '../src/index.js';
|
|
22
|
+
const TEST_STORE_PATH = './test-head-window-order';
|
|
23
|
+
function cleanup() {
|
|
24
|
+
if (existsSync(TEST_STORE_PATH)) {
|
|
25
|
+
rmSync(TEST_STORE_PATH, { recursive: true, force: true });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function createCapturingMembrane() {
|
|
29
|
+
const calls = [];
|
|
30
|
+
const membrane = {
|
|
31
|
+
complete: async (request) => {
|
|
32
|
+
calls.push({ messages: request.messages });
|
|
33
|
+
const inputChars = request.messages
|
|
34
|
+
.flatMap((m) => m.content)
|
|
35
|
+
.map((b) => b.text ?? '')
|
|
36
|
+
.join('').length;
|
|
37
|
+
const summary = `[mock summary] ` + 'x '.repeat(Math.max(30, Math.floor(inputChars / 10)));
|
|
38
|
+
return {
|
|
39
|
+
content: [{ type: 'text', text: summary }],
|
|
40
|
+
usage: { input_tokens: Math.ceil(inputChars / 4), output_tokens: Math.ceil(summary.length / 4) },
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
return { membrane, calls };
|
|
45
|
+
}
|
|
46
|
+
const t = (s) => ({ type: 'text', text: s });
|
|
47
|
+
function flatText(m) {
|
|
48
|
+
return m.content.map((b) => b.text ?? '').join(' ');
|
|
49
|
+
}
|
|
50
|
+
async function drain(manager) {
|
|
51
|
+
for (let i = 0; i < 500; i++) {
|
|
52
|
+
if (manager.isReady())
|
|
53
|
+
return;
|
|
54
|
+
await manager.tick();
|
|
55
|
+
}
|
|
56
|
+
throw new Error('drain: queue did not converge within 500 ticks');
|
|
57
|
+
}
|
|
58
|
+
describe('Compression prompt ordering (confabulation regression)', () => {
|
|
59
|
+
before(() => cleanup());
|
|
60
|
+
after(() => cleanup());
|
|
61
|
+
it('head window precedes recall pairs in every compression request', async () => {
|
|
62
|
+
cleanup();
|
|
63
|
+
const { membrane, calls } = createCapturingMembrane();
|
|
64
|
+
const strategy = new AutobiographicalStrategy({
|
|
65
|
+
targetChunkTokens: 80,
|
|
66
|
+
headWindowTokens: 60, // covers the two sentinel opening messages
|
|
67
|
+
recentWindowTokens: 0,
|
|
68
|
+
hierarchical: true,
|
|
69
|
+
mergeThreshold: 100, // keep this test on pure L1 calls
|
|
70
|
+
});
|
|
71
|
+
const manager = await ContextManager.open({
|
|
72
|
+
path: TEST_STORE_PATH,
|
|
73
|
+
strategy,
|
|
74
|
+
membrane: membrane,
|
|
75
|
+
});
|
|
76
|
+
// Distinctive chronicle opening — the identity anchor.
|
|
77
|
+
manager.addMessage('user', [t('HEAD_SENTINEL_OPENING can you explore a story with me')]);
|
|
78
|
+
manager.addMessage('agent', [t('HEAD_SENTINEL_REPLY yes let us explore that story together')]);
|
|
79
|
+
// Enough substantive traffic for several chunks → several L1 calls,
|
|
80
|
+
// later ones carrying recall pairs of earlier summaries.
|
|
81
|
+
const filler = (i) => `event ${i} ` + 'substantive words about real happenings '.repeat(8);
|
|
82
|
+
for (let i = 0; i < 40; i++) {
|
|
83
|
+
manager.addMessage(i % 2 === 0 ? 'user' : 'agent', [t(filler(i))]);
|
|
84
|
+
}
|
|
85
|
+
await drain(manager);
|
|
86
|
+
assert.ok(calls.length >= 2, `expected multiple L1 calls, got ${calls.length}`);
|
|
87
|
+
let checked = 0;
|
|
88
|
+
for (const call of calls) {
|
|
89
|
+
const texts = call.messages.map(flatText);
|
|
90
|
+
const headIdx = texts.findIndex((s) => s.includes('HEAD_SENTINEL_OPENING'));
|
|
91
|
+
const recallIdx = texts.findIndex((s) => s.includes('[CM] Recall memory'));
|
|
92
|
+
assert.ok(headIdx >= 0, 'head window must be present in every compression request');
|
|
93
|
+
if (recallIdx >= 0) {
|
|
94
|
+
checked++;
|
|
95
|
+
assert.ok(headIdx < recallIdx, `head window (idx ${headIdx}) must precede recall pairs (idx ${recallIdx}) — ` +
|
|
96
|
+
'head-after-recalls reads as fresh live conversation and causes confabulated memories');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
assert.ok(checked >= 1, 'expected at least one call with recall pairs to verify ordering against');
|
|
100
|
+
await manager.close();
|
|
101
|
+
});
|
|
102
|
+
it('thin chunks are stubbed mechanically — no LLM call, non-empty content', async () => {
|
|
103
|
+
cleanup();
|
|
104
|
+
const { membrane, calls } = createCapturingMembrane();
|
|
105
|
+
const strategy = new AutobiographicalStrategy({
|
|
106
|
+
targetChunkTokens: 40,
|
|
107
|
+
headWindowTokens: 0,
|
|
108
|
+
recentWindowTokens: 0,
|
|
109
|
+
hierarchical: true,
|
|
110
|
+
mergeThreshold: 1000, // avoid merge calls; isolate L1 behavior
|
|
111
|
+
});
|
|
112
|
+
const manager = await ContextManager.open({
|
|
113
|
+
path: TEST_STORE_PATH,
|
|
114
|
+
strategy,
|
|
115
|
+
membrane: membrane,
|
|
116
|
+
});
|
|
117
|
+
// Pure system-noise traffic: many near-empty turns. Each chunk's total
|
|
118
|
+
// trimmed text stays far below the 200-char default threshold.
|
|
119
|
+
for (let i = 0; i < 120; i++) {
|
|
120
|
+
manager.addMessage(i % 2 === 0 ? 'user' : 'agent', [t(i % 3 === 0 ? 'hb' : ' ')]);
|
|
121
|
+
}
|
|
122
|
+
await drain(manager);
|
|
123
|
+
const snap = strategy.getProgressSnapshot();
|
|
124
|
+
assert.ok(snap.summaryCounts.l1 > 0, 'expected stub L1 summaries to be produced');
|
|
125
|
+
assert.strictEqual(calls.length, 0, `expected no LLM calls for pure-noise chunks, got ${calls.length} — ` +
|
|
126
|
+
'asking a summarizer to memorize nothing produces confabulation');
|
|
127
|
+
const stubs = strategy.searchSummaries({ text: 'quiet stretch' });
|
|
128
|
+
assert.ok(stubs.length > 0, 'stub summaries must carry non-empty "quiet stretch" content');
|
|
129
|
+
for (const s of stubs) {
|
|
130
|
+
assert.ok(s.summary.content.trim().length > 0, 'stub content must be non-empty (400 guard)');
|
|
131
|
+
}
|
|
132
|
+
await manager.close();
|
|
133
|
+
});
|
|
134
|
+
it('mixed traffic: substantive chunks still compress via LLM', async () => {
|
|
135
|
+
cleanup();
|
|
136
|
+
const { membrane, calls } = createCapturingMembrane();
|
|
137
|
+
const strategy = new AutobiographicalStrategy({
|
|
138
|
+
targetChunkTokens: 60,
|
|
139
|
+
headWindowTokens: 0,
|
|
140
|
+
recentWindowTokens: 0,
|
|
141
|
+
hierarchical: true,
|
|
142
|
+
mergeThreshold: 1000,
|
|
143
|
+
});
|
|
144
|
+
const manager = await ContextManager.open({
|
|
145
|
+
path: TEST_STORE_PATH,
|
|
146
|
+
strategy,
|
|
147
|
+
membrane: membrane,
|
|
148
|
+
});
|
|
149
|
+
for (let i = 0; i < 30; i++) {
|
|
150
|
+
manager.addMessage(i % 2 === 0 ? 'user' : 'agent', [
|
|
151
|
+
t(`real event ${i} ` + 'meaningful discussion of concrete plans and decisions '.repeat(6)),
|
|
152
|
+
]);
|
|
153
|
+
}
|
|
154
|
+
await drain(manager);
|
|
155
|
+
assert.ok(calls.length > 0, 'substantive chunks must still go through the LLM');
|
|
156
|
+
await manager.close();
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
//# sourceMappingURL=head-window-order.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"head-window-order.test.js","sourceRoot":"","sources":["../../test/head-window-order.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAG3E,MAAM,eAAe,GAAG,0BAA0B,CAAC;AAEnD,SAAS,OAAO;IACd,IAAI,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;QAChC,MAAM,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC;AAID,SAAS,uBAAuB;IAC9B,MAAM,KAAK,GAAsC,EAAE,CAAC;IACpD,MAAM,QAAQ,GAAG;QACf,QAAQ,EAAE,KAAK,EAAE,OAAmC,EAAE,EAAE;YACtD,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC3C,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ;iBAChC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;iBACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAuB,CAAC,IAAI,IAAI,EAAE,CAAC;iBAC/C,IAAI,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;YACnB,MAAM,OAAO,GAAG,iBAAiB,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;YAC3F,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBAC1C,KAAK,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,aAAa,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE;aACjG,CAAC;QACJ,CAAC;KACF,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,GAAG,CAAC,CAAS,EAAgB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC;AAEnE,SAAS,QAAQ,CAAC,CAAa;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAE,CAAuB,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC7E,CAAC;AAED,KAAK,UAAU,KAAK,CAAC,OAAuB;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,OAAO,CAAC,OAAO,EAAE;YAAE,OAAO;QAC9B,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;IACvB,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;AACpE,CAAC;AAED,QAAQ,CAAC,wDAAwD,EAAE,GAAG,EAAE;IACtE,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACxB,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IAEvB,EAAE,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;QAC9E,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,uBAAuB,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,IAAI,wBAAwB,CAAC;YAC5C,iBAAiB,EAAE,EAAE;YACrB,gBAAgB,EAAE,EAAE,EAAE,2CAA2C;YACjE,kBAAkB,EAAE,CAAC;YACrB,YAAY,EAAE,IAAI;YAClB,cAAc,EAAE,GAAG,EAAE,kCAAkC;SACxD,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC;YACxC,IAAI,EAAE,eAAe;YACrB,QAAQ;YACR,QAAQ,EAAE,QAAe;SAC1B,CAAC,CAAC;QAEH,uDAAuD;QACvD,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,uDAAuD,CAAC,CAAC,CAAC,CAAC;QACzF,OAAO,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,4DAA4D,CAAC,CAAC,CAAC,CAAC;QAE/F,oEAAoE;QACpE,yDAAyD;QACzD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,GAAG,0CAA0C,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnG,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;QACrB,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,mCAAmC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;QAEhF,IAAI,OAAO,GAAG,CAAC,CAAC;QAChB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC;YAC5E,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC3E,MAAM,CAAC,EAAE,CAAC,OAAO,IAAI,CAAC,EAAE,0DAA0D,CAAC,CAAC;YACpF,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;gBACnB,OAAO,EAAE,CAAC;gBACV,MAAM,CAAC,EAAE,CACP,OAAO,GAAG,SAAS,EACnB,oBAAoB,OAAO,oCAAoC,SAAS,MAAM;oBAC5E,sFAAsF,CACzF,CAAC;YACJ,CAAC;QACH,CAAC;QACD,MAAM,CAAC,EAAE,CAAC,OAAO,IAAI,CAAC,EAAE,yEAAyE,CAAC,CAAC;QACnG,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACrF,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,uBAAuB,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,IAAI,wBAAwB,CAAC;YAC5C,iBAAiB,EAAE,EAAE;YACrB,gBAAgB,EAAE,CAAC;YACnB,kBAAkB,EAAE,CAAC;YACrB,YAAY,EAAE,IAAI;YAClB,cAAc,EAAE,IAAI,EAAE,yCAAyC;SAChE,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC;YACxC,IAAI,EAAE,eAAe;YACrB,QAAQ;YACR,QAAQ,EAAE,QAAe;SAC1B,CAAC,CAAC;QAEH,uEAAuE;QACvE,+DAA+D;QAC/D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACpF,CAAC;QAED,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;QAErB,MAAM,IAAI,GAAG,QAAQ,CAAC,mBAAmB,EAAE,CAAC;QAC5C,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,EAAE,GAAG,CAAC,EAAE,2CAA2C,CAAC,CAAC;QAClF,MAAM,CAAC,WAAW,CAChB,KAAK,CAAC,MAAM,EACZ,CAAC,EACD,oDAAoD,KAAK,CAAC,MAAM,KAAK;YACnE,gEAAgE,CACnE,CAAC;QAEF,MAAM,KAAK,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAC;QAClE,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,6DAA6D,CAAC,CAAC;QAC3F,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,4CAA4C,CAAC,CAAC;QAC/F,CAAC;QACD,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,uBAAuB,EAAE,CAAC;QACtD,MAAM,QAAQ,GAAG,IAAI,wBAAwB,CAAC;YAC5C,iBAAiB,EAAE,EAAE;YACrB,gBAAgB,EAAE,CAAC;YACnB,kBAAkB,EAAE,CAAC;YACrB,YAAY,EAAE,IAAI;YAClB,cAAc,EAAE,IAAI;SACrB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC;YACxC,IAAI,EAAE,eAAe;YACrB,QAAQ;YACR,QAAQ,EAAE,QAAe;SAC1B,CAAC,CAAC;QAEH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE;gBACjD,CAAC,CAAC,cAAc,CAAC,GAAG,GAAG,wDAAwD,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;aAC3F,CAAC,CAAC;QACL,CAAC;QAED,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC;QACrB,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,kDAAkD,CAAC,CAAC;QAChF,MAAM,OAAO,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -32,7 +32,7 @@ function imageMessage(label, tokenEstimate = 1600) {
|
|
|
32
32
|
];
|
|
33
33
|
}
|
|
34
34
|
/** Re-derive rendered tokens from the COMPILED output using the strategy's
|
|
35
|
-
* default estimator (image -> tokenEstimate ?? 1600,
|
|
35
|
+
* default estimator (image -> tokenEstimate ?? 1600, prose -> ceil(len/2.9)).
|
|
36
36
|
* The fixtures use only image + text blocks. */
|
|
37
37
|
function renderedTokens(messages) {
|
|
38
38
|
let t = 0;
|
|
@@ -41,7 +41,7 @@ function renderedTokens(messages) {
|
|
|
41
41
|
if (b.type === 'image')
|
|
42
42
|
t += b.tokenEstimate ?? 1600;
|
|
43
43
|
else if (b.type === 'text')
|
|
44
|
-
t += Math.ceil(b.text.length /
|
|
44
|
+
t += Math.ceil(b.text.length / 2.9);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
return t;
|
|
@@ -75,7 +75,7 @@ describe('image stripping × render stats', () => {
|
|
|
75
75
|
// Decisive assertion: total == the ACTUAL rendered size. Pre-fix this was
|
|
76
76
|
// inflated by the 4 stripped images (~4 * 1592 tok).
|
|
77
77
|
const expected = renderedTokens(compiled.messages);
|
|
78
|
-
assert.
|
|
78
|
+
assert.ok(Math.abs(rs.total.tokens - expected) <= Math.max(16, expected * 0.01), `total.tokens ~= real rendered size (${rs.total.tokens} vs ${expected})`);
|
|
79
79
|
// Internal invariant must still hold (total == sum of buckets).
|
|
80
80
|
const s = rs.summaries;
|
|
81
81
|
const bucketSum = rs.head.tokens + rs.tail.tokens + rs.middleRaw.tokens +
|
|
@@ -126,5 +126,27 @@ describe('image stripping × render stats', () => {
|
|
|
126
126
|
}
|
|
127
127
|
manager.close();
|
|
128
128
|
});
|
|
129
|
+
it('(c) resolution-0 middle messages keep post-strip pricing through emission', async () => {
|
|
130
|
+
const manager = await ContextManager.open({
|
|
131
|
+
path: TEST_STORE_PATH,
|
|
132
|
+
strategy: new AutobiographicalStrategy({
|
|
133
|
+
adaptiveResolution: true,
|
|
134
|
+
headWindowTokens: 0,
|
|
135
|
+
recentWindowTokens: 1,
|
|
136
|
+
maxLiveImages: 1,
|
|
137
|
+
imageStripDepthTokens: 0,
|
|
138
|
+
}),
|
|
139
|
+
});
|
|
140
|
+
for (let i = 1; i <= 3; i++)
|
|
141
|
+
manager.addMessage('user', imageMessage(`middle-img-${i}`));
|
|
142
|
+
manager.addMessage('user', [{ type: 'text', text: 'newest '.repeat(40) }]);
|
|
143
|
+
const compiled = await manager.compile({ maxTokens: 1_000_000, reserveForResponse: 0 });
|
|
144
|
+
const rs = manager.getRenderStats();
|
|
145
|
+
assert.ok(rs, 'stats present after compile');
|
|
146
|
+
assert.ok(rs.middleRaw.messages >= 3, 'image messages were emitted from the middle');
|
|
147
|
+
const expected = renderedTokens(compiled.messages);
|
|
148
|
+
assert.ok(Math.abs(rs.total.tokens - expected) <= Math.max(16, expected * 0.01), `middleRaw pricing stays post-strip (${rs.total.tokens} vs ${expected})`);
|
|
149
|
+
manager.close();
|
|
150
|
+
});
|
|
129
151
|
});
|
|
130
152
|
//# sourceMappingURL=image-strip-render-stats.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-strip-render-stats.test.js","sourceRoot":"","sources":["../../test/image-strip-render-stats.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACpE,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AAG3E,MAAM,eAAe,GAAG,iCAAiC,CAAC;AAC1D,MAAM,WAAW,GAAG,iCAAiC,CAAC;AAEtD,SAAS,OAAO;IACd,IAAI,UAAU,CAAC,eAAe,CAAC;QAAE,MAAM,CAAC,eAAe,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7F,CAAC;AAED,gFAAgF;AAChF,SAAS,YAAY,CAAC,KAAa,EAAE,aAAa,GAAG,IAAI;IACvD,OAAO;QACL,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,EAAE,aAAa,EAAkB;QAClH,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE;KAC9B,CAAC;AACJ,CAAC;AAED;;iDAEiD;AACjD,SAAS,cAAc,CAAC,QAAuC;IAC7D,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;YAC1B,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;gBAAE,CAAC,IAAK,CAAgC,CAAC,aAAa,IAAI,IAAI,CAAC;iBAChF,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;gBAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,
|
|
1
|
+
{"version":3,"file":"image-strip-render-stats.test.js","sourceRoot":"","sources":["../../test/image-strip-render-stats.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bug 6.8: KnowledgeStrategy.rebuildChunks dropped the base class's
|
|
3
|
+
* tool-pair chunk-boundary guard. The override closed a chunk on
|
|
4
|
+
* `length >= 2 && (phaseChanged || sizeExceeded)` with NO check that the
|
|
5
|
+
* chunk's last message contains a `tool_use` — so `sizeExceeded` could
|
|
6
|
+
* split a tool_use from its tool_result across chunks. When the earlier
|
|
7
|
+
* chunk compresses first, the raw orphan tool_result renders unpaired and
|
|
8
|
+
* the Anthropic API rejects the request.
|
|
9
|
+
*
|
|
10
|
+
* Companion to chunker-tool-boundary.test.ts (same invariant on the base
|
|
11
|
+
* chunker).
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=knowledge-tool-boundary.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-tool-boundary.test.d.ts","sourceRoot":"","sources":["../../test/knowledge-tool-boundary.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bug 6.8: KnowledgeStrategy.rebuildChunks dropped the base class's
|
|
3
|
+
* tool-pair chunk-boundary guard. The override closed a chunk on
|
|
4
|
+
* `length >= 2 && (phaseChanged || sizeExceeded)` with NO check that the
|
|
5
|
+
* chunk's last message contains a `tool_use` — so `sizeExceeded` could
|
|
6
|
+
* split a tool_use from its tool_result across chunks. When the earlier
|
|
7
|
+
* chunk compresses first, the raw orphan tool_result renders unpaired and
|
|
8
|
+
* the Anthropic API rejects the request.
|
|
9
|
+
*
|
|
10
|
+
* Companion to chunker-tool-boundary.test.ts (same invariant on the base
|
|
11
|
+
* chunker).
|
|
12
|
+
*/
|
|
13
|
+
import { describe, it, before, after } from 'node:test';
|
|
14
|
+
import assert from 'node:assert';
|
|
15
|
+
import { rmSync, existsSync } from 'node:fs';
|
|
16
|
+
import { ContextManager, KnowledgeStrategy } from '../src/index.js';
|
|
17
|
+
const TEST_STORE_PATH = './test-knowledge-tool-boundary';
|
|
18
|
+
function cleanup() {
|
|
19
|
+
if (existsSync(TEST_STORE_PATH)) {
|
|
20
|
+
rmSync(TEST_STORE_PATH, { recursive: true, force: true });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
describe('KnowledgeStrategy chunker: tool cycle boundary', () => {
|
|
24
|
+
before(() => cleanup());
|
|
25
|
+
after(() => cleanup());
|
|
26
|
+
it('never closes a chunk on a message containing a tool_use (sizeExceeded lands on the tool_use)', async () => {
|
|
27
|
+
cleanup();
|
|
28
|
+
const strategy = new KnowledgeStrategy({
|
|
29
|
+
targetChunkTokens: 30,
|
|
30
|
+
// Cap research chunks low so the size trigger fires right after a
|
|
31
|
+
// [text, tool_use] prefix — i.e. the close decision lands exactly when
|
|
32
|
+
// the last message in the chunk-in-progress is the tool_use.
|
|
33
|
+
maxResearchChunkTokens: 60,
|
|
34
|
+
headWindowTokens: 0,
|
|
35
|
+
recentWindowTokens: 0,
|
|
36
|
+
});
|
|
37
|
+
const manager = await ContextManager.open({
|
|
38
|
+
path: TEST_STORE_PATH,
|
|
39
|
+
strategy,
|
|
40
|
+
});
|
|
41
|
+
// Repeated triplets: [synthesis text (~50 tok), tool_use (~20 tok),
|
|
42
|
+
// tool_result (~10 tok)]. At the tool_result's iteration the chunk
|
|
43
|
+
// holds [text, tool_use] with cumulative tokens >= maxResearchChunkTokens,
|
|
44
|
+
// so an unguarded chunker closes there — splitting the pair.
|
|
45
|
+
const filler = (n) => 'word '.repeat(n);
|
|
46
|
+
for (let k = 0; k < 4; k++) {
|
|
47
|
+
manager.addMessage('User', [{ type: 'text', text: filler(40) }]);
|
|
48
|
+
manager.addMessage('Claude', [
|
|
49
|
+
{ type: 'tool_use', id: `tu-${k}`, name: 'mcpl:search', input: { q: 'x'.repeat(60) } },
|
|
50
|
+
]);
|
|
51
|
+
manager.addMessage('User', [
|
|
52
|
+
{ type: 'tool_result', toolUseId: `tu-${k}`, content: 'ok' },
|
|
53
|
+
]);
|
|
54
|
+
}
|
|
55
|
+
// Trailing filler so the last pair isn't only in the never-closed final chunk.
|
|
56
|
+
for (let i = 0; i < 4; i++) {
|
|
57
|
+
manager.addMessage(i % 2 === 0 ? 'Claude' : 'User', [
|
|
58
|
+
{ type: 'text', text: filler(40) },
|
|
59
|
+
]);
|
|
60
|
+
}
|
|
61
|
+
const s = strategy;
|
|
62
|
+
s.rebuildChunks(manager.messageStore);
|
|
63
|
+
assert.ok(s.chunks.length >= 2, `expected multiple chunks, got ${s.chunks.length}`);
|
|
64
|
+
// Invariant 1: no chunk's LAST message contains a tool_use — a close
|
|
65
|
+
// there guarantees the pair is split.
|
|
66
|
+
for (const chunk of s.chunks) {
|
|
67
|
+
const last = chunk.messages[chunk.messages.length - 1];
|
|
68
|
+
assert.ok(!last.content.some((b) => b.type === 'tool_use'), `chunk ending on message ${last.id} has a trailing tool_use — boundary guard missing`);
|
|
69
|
+
}
|
|
70
|
+
// Invariant 2 (stronger): both members of every tool_use/tool_result
|
|
71
|
+
// pair land in the SAME chunk.
|
|
72
|
+
for (const chunk of s.chunks) {
|
|
73
|
+
const useIds = new Set();
|
|
74
|
+
const resultIds = new Set();
|
|
75
|
+
for (const msg of chunk.messages) {
|
|
76
|
+
for (const b of msg.content) {
|
|
77
|
+
if (b.type === 'tool_use')
|
|
78
|
+
useIds.add(b.id);
|
|
79
|
+
if (b.type === 'tool_result')
|
|
80
|
+
resultIds.add(b.toolUseId);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
for (const id of useIds) {
|
|
84
|
+
assert.ok(resultIds.has(id), `tool_use ${id} has no tool_result in its chunk`);
|
|
85
|
+
}
|
|
86
|
+
for (const id of resultIds) {
|
|
87
|
+
assert.ok(useIds.has(id), `tool_result for ${id} has no tool_use in its chunk`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
await manager.close();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
//# sourceMappingURL=knowledge-tool-boundary.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"knowledge-tool-boundary.test.js","sourceRoot":"","sources":["../../test/knowledge-tool-boundary.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L1 production holdback (`l1HoldbackChunks`, default 1).
|
|
3
|
+
*
|
|
4
|
+
* Speculative L1 production is supply-driven: a chunk is queued for
|
|
5
|
+
* compression the moment it closes, and the background drain produces its
|
|
6
|
+
* summary ahead of any fold demand. The holdback keeps the newest N closed
|
|
7
|
+
* chunks OUT of that speculative queue — the chunk at the live edge is the
|
|
8
|
+
* one most likely to still be in motion — releasing each automatically once
|
|
9
|
+
* a newer chunk closes behind it (the queue is rebuilt on every message).
|
|
10
|
+
*
|
|
11
|
+
* Demand overrides: a picker `produce` op (enqueueL1ForRange) marks the
|
|
12
|
+
* chunk demanded, and demanded chunks are never held back.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=l1-holdback.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"l1-holdback.test.d.ts","sourceRoot":"","sources":["../../test/l1-holdback.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L1 production holdback (`l1HoldbackChunks`, default 1).
|
|
3
|
+
*
|
|
4
|
+
* Speculative L1 production is supply-driven: a chunk is queued for
|
|
5
|
+
* compression the moment it closes, and the background drain produces its
|
|
6
|
+
* summary ahead of any fold demand. The holdback keeps the newest N closed
|
|
7
|
+
* chunks OUT of that speculative queue — the chunk at the live edge is the
|
|
8
|
+
* one most likely to still be in motion — releasing each automatically once
|
|
9
|
+
* a newer chunk closes behind it (the queue is rebuilt on every message).
|
|
10
|
+
*
|
|
11
|
+
* Demand overrides: a picker `produce` op (enqueueL1ForRange) marks the
|
|
12
|
+
* chunk demanded, and demanded chunks are never held back.
|
|
13
|
+
*/
|
|
14
|
+
import { describe, it, before, after, beforeEach } from 'node:test';
|
|
15
|
+
import assert from 'node:assert';
|
|
16
|
+
import { rmSync, existsSync } from 'node:fs';
|
|
17
|
+
import { ContextManager, AutobiographicalStrategy } from '../src/index.js';
|
|
18
|
+
const TEST_STORE_PATH = './test-l1-holdback';
|
|
19
|
+
function cleanup() {
|
|
20
|
+
if (existsSync(TEST_STORE_PATH)) {
|
|
21
|
+
rmSync(TEST_STORE_PATH, { recursive: true, force: true });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function textBlock(text) {
|
|
25
|
+
return [{ type: 'text', text }];
|
|
26
|
+
}
|
|
27
|
+
class InspectableStrategy extends AutobiographicalStrategy {
|
|
28
|
+
queuedChunkIndices() {
|
|
29
|
+
return [...this.compressionQueue];
|
|
30
|
+
}
|
|
31
|
+
closedChunks() {
|
|
32
|
+
return this.chunks;
|
|
33
|
+
}
|
|
34
|
+
demandRange(firstId, lastId) {
|
|
35
|
+
this.enqueueL1ForRange(firstId, lastId);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** Feed enough small messages to close `n` chunks (targetChunkTokens=20,
|
|
39
|
+
* recentWindowTokens=5 keeps only the newest message out of the
|
|
40
|
+
* compressible region). */
|
|
41
|
+
async function closeChunks(manager, strategy, n) {
|
|
42
|
+
let guard = 0;
|
|
43
|
+
while (strategy.closedChunks().length < n && guard++ < 200) {
|
|
44
|
+
manager.addMessage('user', textBlock(`m-${guard} hello world padding`));
|
|
45
|
+
await new Promise((r) => setTimeout(r, 1));
|
|
46
|
+
}
|
|
47
|
+
assert.strictEqual(strategy.closedChunks().length >= n, true, `expected ≥${n} closed chunks`);
|
|
48
|
+
}
|
|
49
|
+
function makeStrategy(overrides = {}) {
|
|
50
|
+
return new InspectableStrategy({
|
|
51
|
+
headWindowTokens: 0,
|
|
52
|
+
recentWindowTokens: 5,
|
|
53
|
+
targetChunkTokens: 20,
|
|
54
|
+
autoTickOnNewMessage: false, // inspect the queue without draining it
|
|
55
|
+
...overrides,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
describe('AutobiographicalStrategy — L1 holdback', () => {
|
|
59
|
+
before(cleanup);
|
|
60
|
+
after(cleanup);
|
|
61
|
+
beforeEach(cleanup);
|
|
62
|
+
it('default: the newest closed chunk is held out of the speculative queue', async () => {
|
|
63
|
+
const strategy = makeStrategy();
|
|
64
|
+
const manager = await ContextManager.open({ path: TEST_STORE_PATH, strategy });
|
|
65
|
+
await closeChunks(manager, strategy, 2);
|
|
66
|
+
const total = strategy.closedChunks().length;
|
|
67
|
+
const queued = strategy.queuedChunkIndices();
|
|
68
|
+
assert.ok(!queued.includes(total - 1), 'newest closed chunk must be held back');
|
|
69
|
+
assert.ok(queued.includes(0), 'older chunks must be queued speculatively');
|
|
70
|
+
manager.close();
|
|
71
|
+
});
|
|
72
|
+
it('a held-back chunk is released once a newer chunk closes behind it', async () => {
|
|
73
|
+
const strategy = makeStrategy();
|
|
74
|
+
const manager = await ContextManager.open({ path: TEST_STORE_PATH, strategy });
|
|
75
|
+
await closeChunks(manager, strategy, 2);
|
|
76
|
+
const heldIndex = strategy.closedChunks().length - 1;
|
|
77
|
+
assert.ok(!strategy.queuedChunkIndices().includes(heldIndex), 'sanity: held at first');
|
|
78
|
+
await closeChunks(manager, strategy, strategy.closedChunks().length + 1);
|
|
79
|
+
assert.ok(strategy.queuedChunkIndices().includes(heldIndex), 'previously-held chunk must be queued once it ages out of the holdback window');
|
|
80
|
+
manager.close();
|
|
81
|
+
});
|
|
82
|
+
it('l1HoldbackChunks: 0 restores compress-at-close', async () => {
|
|
83
|
+
const strategy = makeStrategy({ l1HoldbackChunks: 0 });
|
|
84
|
+
const manager = await ContextManager.open({ path: TEST_STORE_PATH, strategy });
|
|
85
|
+
await closeChunks(manager, strategy, 1);
|
|
86
|
+
const total = strategy.closedChunks().length;
|
|
87
|
+
assert.ok(strategy.queuedChunkIndices().includes(total - 1), 'with holdback disabled the newest chunk queues at close');
|
|
88
|
+
manager.close();
|
|
89
|
+
});
|
|
90
|
+
it('l1HoldbackChunks: 2 holds the two newest closed chunks', async () => {
|
|
91
|
+
const strategy = makeStrategy({ l1HoldbackChunks: 2 });
|
|
92
|
+
const manager = await ContextManager.open({ path: TEST_STORE_PATH, strategy });
|
|
93
|
+
await closeChunks(manager, strategy, 3);
|
|
94
|
+
const total = strategy.closedChunks().length;
|
|
95
|
+
const queued = strategy.queuedChunkIndices();
|
|
96
|
+
assert.ok(!queued.includes(total - 1), 'newest held');
|
|
97
|
+
assert.ok(!queued.includes(total - 2), 'second-newest held');
|
|
98
|
+
assert.ok(queued.includes(total - 3) || total - 3 < 0, 'third-newest queued');
|
|
99
|
+
manager.close();
|
|
100
|
+
});
|
|
101
|
+
it('demand (enqueueL1ForRange) overrides the holdback — and survives a rebuild', async () => {
|
|
102
|
+
const strategy = makeStrategy();
|
|
103
|
+
const manager = await ContextManager.open({ path: TEST_STORE_PATH, strategy });
|
|
104
|
+
await closeChunks(manager, strategy, 2);
|
|
105
|
+
const chunks = strategy.closedChunks();
|
|
106
|
+
const newest = chunks[chunks.length - 1];
|
|
107
|
+
assert.ok(!strategy.queuedChunkIndices().includes(newest.index), 'sanity: held before demand');
|
|
108
|
+
strategy.demandRange(newest.messages[0].id, newest.messages[newest.messages.length - 1].id);
|
|
109
|
+
assert.ok(strategy.queuedChunkIndices().includes(newest.index), 'demanded chunk enters the queue immediately');
|
|
110
|
+
// A new message rebuilds the queue from scratch — the demanded chunk must
|
|
111
|
+
// NOT be filtered back out by the holdback window.
|
|
112
|
+
manager.addMessage('user', textBlock('another message'));
|
|
113
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
114
|
+
const stillNewest = strategy.closedChunks()[newest.index];
|
|
115
|
+
assert.ok(strategy.queuedChunkIndices().includes(stillNewest.index) || stillNewest.compressed, 'demanded chunk stays queued across rebuilds');
|
|
116
|
+
manager.close();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
//# sourceMappingURL=l1-holdback.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"l1-holdback.test.js","sourceRoot":"","sources":["../../test/l1-holdback.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge-grouping contiguity (2026-07-12 fix) — regression tests.
|
|
3
|
+
*
|
|
4
|
+
* The old rule merged "whatever N are unmerged" in creation order, which
|
|
5
|
+
* minted merge groups bridging months of already-merged history (mythos
|
|
6
|
+
* L3-415 spanning 0-3853 of 3995 live messages). Such a group straddles the
|
|
7
|
+
* recent window, and group-atomic folding then blocks its entire lineage —
|
|
8
|
+
* the fold floor stops fitting the budget.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=merge-contiguity.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-contiguity.test.d.ts","sourceRoot":"","sources":["../../test/merge-contiguity.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Merge-grouping contiguity (2026-07-12 fix) — regression tests.
|
|
3
|
+
*
|
|
4
|
+
* The old rule merged "whatever N are unmerged" in creation order, which
|
|
5
|
+
* minted merge groups bridging months of already-merged history (mythos
|
|
6
|
+
* L3-415 spanning 0-3853 of 3995 live messages). Such a group straddles the
|
|
7
|
+
* recent window, and group-atomic folding then blocks its entire lineage —
|
|
8
|
+
* the fold floor stops fitting the budget.
|
|
9
|
+
*/
|
|
10
|
+
import { test } from 'node:test';
|
|
11
|
+
import assert from 'node:assert/strict';
|
|
12
|
+
import { AutobiographicalStrategy } from '../src/strategies/autobiographical.js';
|
|
13
|
+
/** Expose the protected candidate selector + injectable chunks. */
|
|
14
|
+
class Probe extends AutobiographicalStrategy {
|
|
15
|
+
setChunks(messageIds) {
|
|
16
|
+
this.chunks = [
|
|
17
|
+
{ messages: messageIds.map((id) => ({ id })) },
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
pick(unmerged, threshold) {
|
|
21
|
+
return this.contiguousMergeCandidates(unmerged, threshold);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function summary(id, first, last) {
|
|
25
|
+
return {
|
|
26
|
+
id, level: 2, content: `s ${id}`, tokens: 100, sourceLevel: 1,
|
|
27
|
+
sourceIds: [`x-${id}`],
|
|
28
|
+
sourceRange: { first: `m-${first}`, last: `m-${last}` },
|
|
29
|
+
created: 1,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function probe() {
|
|
33
|
+
const p = new Probe({ adaptiveResolution: true, autoTickOnNewMessage: false });
|
|
34
|
+
p.setChunks(Array.from({ length: 4000 }, (_, i) => `m-${i}`));
|
|
35
|
+
return p;
|
|
36
|
+
}
|
|
37
|
+
test('contiguous run merges; a cross-era candidate is left out', () => {
|
|
38
|
+
const p = probe();
|
|
39
|
+
// Six contiguous June-era candidates + one July-era outlier that the old
|
|
40
|
+
// creation-order rule would have grouped in.
|
|
41
|
+
const unmerged = [
|
|
42
|
+
summary('july', 3800, 3900), // creation-order FIRST — old code took it
|
|
43
|
+
summary('a', 0, 50), summary('b', 51, 170), summary('c', 171, 290),
|
|
44
|
+
summary('d', 291, 350), summary('e', 351, 512), summary('f', 513, 572),
|
|
45
|
+
];
|
|
46
|
+
const run = p.pick(unmerged, 6);
|
|
47
|
+
assert.ok(run, 'a qualifying run exists');
|
|
48
|
+
assert.deepEqual(run.map((s) => s.id).sort(), ['a', 'b', 'c', 'd', 'e', 'f'], 'contiguous six, no bridge');
|
|
49
|
+
});
|
|
50
|
+
test('small holes bridge; cross-era gaps break the run', () => {
|
|
51
|
+
const p = probe();
|
|
52
|
+
const unmerged = [
|
|
53
|
+
summary('a', 0, 50), summary('b', 120, 200), // 70-message hole: fine
|
|
54
|
+
summary('c', 201, 300), summary('d', 301, 400),
|
|
55
|
+
summary('e', 401, 500),
|
|
56
|
+
summary('f', 3000, 3100), // 2500-message gap: breaks
|
|
57
|
+
];
|
|
58
|
+
assert.equal(p.pick(unmerged, 6), null, 'five contiguous + one distant ≠ a run of six');
|
|
59
|
+
assert.ok(p.pick(unmerged, 5), 'the contiguous five qualify at threshold 5');
|
|
60
|
+
});
|
|
61
|
+
test('wide-span (replay-era) candidates are quarantined from any run', () => {
|
|
62
|
+
const p = probe();
|
|
63
|
+
const unmerged = [
|
|
64
|
+
summary('replay', 0, 3853), // spans the whole chronicle — the L2-411 shape
|
|
65
|
+
summary('a', 0, 50), summary('b', 51, 170), summary('c', 171, 290),
|
|
66
|
+
summary('d', 291, 350), summary('e', 351, 512),
|
|
67
|
+
];
|
|
68
|
+
// Without quarantine the replay span would bridge everything into a run of
|
|
69
|
+
// six; with it there are only five eligible → no merge.
|
|
70
|
+
assert.equal(p.pick(unmerged, 6), null, 'wide-span candidate cannot complete a run');
|
|
71
|
+
const five = p.pick(unmerged, 5);
|
|
72
|
+
assert.ok(five && !five.some((s) => s.id === 'replay'), 'replay stays on the frontier');
|
|
73
|
+
});
|
|
74
|
+
//# sourceMappingURL=merge-contiguity.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge-contiguity.test.js","sourceRoot":"","sources":["../../test/merge-contiguity.test.ts"],"names":[],"mappings":"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"}
|