@animalabs/context-manager 0.3.0 → 0.5.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 (161) hide show
  1. package/dist/src/adaptive/chunker.d.ts +70 -0
  2. package/dist/src/adaptive/chunker.d.ts.map +1 -0
  3. package/dist/src/adaptive/chunker.js +233 -0
  4. package/dist/src/adaptive/chunker.js.map +1 -0
  5. package/dist/src/adaptive/folding-strategy.d.ts +118 -0
  6. package/dist/src/adaptive/folding-strategy.d.ts.map +1 -0
  7. package/dist/src/adaptive/folding-strategy.js +12 -0
  8. package/dist/src/adaptive/folding-strategy.js.map +1 -0
  9. package/dist/src/adaptive/index.d.ts +17 -0
  10. package/dist/src/adaptive/index.d.ts.map +1 -0
  11. package/dist/src/adaptive/index.js +23 -0
  12. package/dist/src/adaptive/index.js.map +1 -0
  13. package/dist/src/adaptive/picker.d.ts +103 -0
  14. package/dist/src/adaptive/picker.d.ts.map +1 -0
  15. package/dist/src/adaptive/picker.js +357 -0
  16. package/dist/src/adaptive/picker.js.map +1 -0
  17. package/dist/src/adaptive/render.d.ts +39 -0
  18. package/dist/src/adaptive/render.d.ts.map +1 -0
  19. package/dist/src/adaptive/render.js +104 -0
  20. package/dist/src/adaptive/render.js.map +1 -0
  21. package/dist/src/adaptive/strategies/flat-profile.d.ts +19 -0
  22. package/dist/src/adaptive/strategies/flat-profile.d.ts.map +1 -0
  23. package/dist/src/adaptive/strategies/flat-profile.js +86 -0
  24. package/dist/src/adaptive/strategies/flat-profile.js.map +1 -0
  25. package/dist/src/adaptive/strategies/oldest-first.d.ts +19 -0
  26. package/dist/src/adaptive/strategies/oldest-first.d.ts.map +1 -0
  27. package/dist/src/adaptive/strategies/oldest-first.js +39 -0
  28. package/dist/src/adaptive/strategies/oldest-first.js.map +1 -0
  29. package/dist/src/context-manager.d.ts +74 -2
  30. package/dist/src/context-manager.d.ts.map +1 -1
  31. package/dist/src/context-manager.js +150 -10
  32. package/dist/src/context-manager.js.map +1 -1
  33. package/dist/src/index.d.ts +1 -1
  34. package/dist/src/index.d.ts.map +1 -1
  35. package/dist/src/index.js.map +1 -1
  36. package/dist/src/message-store.d.ts +36 -1
  37. package/dist/src/message-store.d.ts.map +1 -1
  38. package/dist/src/message-store.js +134 -8
  39. package/dist/src/message-store.js.map +1 -1
  40. package/dist/src/strategies/autobiographical.d.ts +422 -5
  41. package/dist/src/strategies/autobiographical.d.ts.map +1 -1
  42. package/dist/src/strategies/autobiographical.js +2248 -98
  43. package/dist/src/strategies/autobiographical.js.map +1 -1
  44. package/dist/src/strategies/index.d.ts +1 -1
  45. package/dist/src/strategies/index.d.ts.map +1 -1
  46. package/dist/src/strategies/index.js.map +1 -1
  47. package/dist/src/types/index.d.ts +2 -2
  48. package/dist/src/types/index.d.ts.map +1 -1
  49. package/dist/src/types/index.js +1 -1
  50. package/dist/src/types/index.js.map +1 -1
  51. package/dist/src/types/message.d.ts +38 -0
  52. package/dist/src/types/message.d.ts.map +1 -1
  53. package/dist/src/types/strategy.d.ts +302 -10
  54. package/dist/src/types/strategy.d.ts.map +1 -1
  55. package/dist/src/types/strategy.js +28 -0
  56. package/dist/src/types/strategy.js.map +1 -1
  57. package/dist/test/adaptive/branching.test.d.ts +20 -0
  58. package/dist/test/adaptive/branching.test.d.ts.map +1 -0
  59. package/dist/test/adaptive/branching.test.js +176 -0
  60. package/dist/test/adaptive/branching.test.js.map +1 -0
  61. package/dist/test/adaptive/chunker.test.d.ts +2 -0
  62. package/dist/test/adaptive/chunker.test.d.ts.map +1 -0
  63. package/dist/test/adaptive/chunker.test.js +120 -0
  64. package/dist/test/adaptive/chunker.test.js.map +1 -0
  65. package/dist/test/adaptive/deep-levels.test.d.ts +10 -0
  66. package/dist/test/adaptive/deep-levels.test.d.ts.map +1 -0
  67. package/dist/test/adaptive/deep-levels.test.js +167 -0
  68. package/dist/test/adaptive/deep-levels.test.js.map +1 -0
  69. package/dist/test/adaptive/doc-plus-chat.test.d.ts +10 -0
  70. package/dist/test/adaptive/doc-plus-chat.test.d.ts.map +1 -0
  71. package/dist/test/adaptive/doc-plus-chat.test.js +194 -0
  72. package/dist/test/adaptive/doc-plus-chat.test.js.map +1 -0
  73. package/dist/test/adaptive/hard-fail.test.d.ts +9 -0
  74. package/dist/test/adaptive/hard-fail.test.d.ts.map +1 -0
  75. package/dist/test/adaptive/hard-fail.test.js +154 -0
  76. package/dist/test/adaptive/hard-fail.test.js.map +1 -0
  77. package/dist/test/adaptive/harness.d.ts +109 -0
  78. package/dist/test/adaptive/harness.d.ts.map +1 -0
  79. package/dist/test/adaptive/harness.js +263 -0
  80. package/dist/test/adaptive/harness.js.map +1 -0
  81. package/dist/test/adaptive/ingestion.test.d.ts +13 -0
  82. package/dist/test/adaptive/ingestion.test.d.ts.map +1 -0
  83. package/dist/test/adaptive/ingestion.test.js +306 -0
  84. package/dist/test/adaptive/ingestion.test.js.map +1 -0
  85. package/dist/test/adaptive/integration.test.d.ts +12 -0
  86. package/dist/test/adaptive/integration.test.d.ts.map +1 -0
  87. package/dist/test/adaptive/integration.test.js +247 -0
  88. package/dist/test/adaptive/integration.test.js.map +1 -0
  89. package/dist/test/adaptive/long-chronicle.test.d.ts +13 -0
  90. package/dist/test/adaptive/long-chronicle.test.d.ts.map +1 -0
  91. package/dist/test/adaptive/long-chronicle.test.js +186 -0
  92. package/dist/test/adaptive/long-chronicle.test.js.map +1 -0
  93. package/dist/test/adaptive/persistence.test.d.ts +11 -0
  94. package/dist/test/adaptive/persistence.test.d.ts.map +1 -0
  95. package/dist/test/adaptive/persistence.test.js +200 -0
  96. package/dist/test/adaptive/persistence.test.js.map +1 -0
  97. package/dist/test/adaptive/picker.test.d.ts +2 -0
  98. package/dist/test/adaptive/picker.test.d.ts.map +1 -0
  99. package/dist/test/adaptive/picker.test.js +333 -0
  100. package/dist/test/adaptive/picker.test.js.map +1 -0
  101. package/dist/test/adaptive/render.test.d.ts +2 -0
  102. package/dist/test/adaptive/render.test.d.ts.map +1 -0
  103. package/dist/test/adaptive/render.test.js +109 -0
  104. package/dist/test/adaptive/render.test.js.map +1 -0
  105. package/dist/test/adaptive/shard-immutability.test.d.ts +14 -0
  106. package/dist/test/adaptive/shard-immutability.test.d.ts.map +1 -0
  107. package/dist/test/adaptive/shard-immutability.test.js +184 -0
  108. package/dist/test/adaptive/shard-immutability.test.js.map +1 -0
  109. package/dist/test/adaptive/strategy-integration.test.d.ts +9 -0
  110. package/dist/test/adaptive/strategy-integration.test.d.ts.map +1 -0
  111. package/dist/test/adaptive/strategy-integration.test.js +293 -0
  112. package/dist/test/adaptive/strategy-integration.test.js.map +1 -0
  113. package/dist/test/message-store-sequence.test.d.ts +25 -0
  114. package/dist/test/message-store-sequence.test.d.ts.map +1 -0
  115. package/dist/test/message-store-sequence.test.js +157 -0
  116. package/dist/test/message-store-sequence.test.js.map +1 -0
  117. package/dist/test/non-blocking-compile.test.d.ts +22 -0
  118. package/dist/test/non-blocking-compile.test.d.ts.map +1 -0
  119. package/dist/test/non-blocking-compile.test.js +114 -0
  120. package/dist/test/non-blocking-compile.test.js.map +1 -0
  121. package/dist/test/pins.test.d.ts +10 -0
  122. package/dist/test/pins.test.d.ts.map +1 -0
  123. package/dist/test/pins.test.js +164 -0
  124. package/dist/test/pins.test.js.map +1 -0
  125. package/dist/test/recall-positioning.test.d.ts +16 -0
  126. package/dist/test/recall-positioning.test.d.ts.map +1 -0
  127. package/dist/test/recall-positioning.test.js +181 -0
  128. package/dist/test/recall-positioning.test.js.map +1 -0
  129. package/dist/test/search.test.d.ts +10 -0
  130. package/dist/test/search.test.d.ts.map +1 -0
  131. package/dist/test/search.test.js +141 -0
  132. package/dist/test/search.test.js.map +1 -0
  133. package/dist/test/speculation-cap.test.d.ts +17 -0
  134. package/dist/test/speculation-cap.test.d.ts.map +1 -0
  135. package/dist/test/speculation-cap.test.js +157 -0
  136. package/dist/test/speculation-cap.test.js.map +1 -0
  137. package/dist/test/strategy-persistence.test.d.ts +15 -0
  138. package/dist/test/strategy-persistence.test.d.ts.map +1 -0
  139. package/dist/test/strategy-persistence.test.js +244 -0
  140. package/dist/test/strategy-persistence.test.js.map +1 -0
  141. package/dist/test/tool-pruning.test.d.ts +10 -0
  142. package/dist/test/tool-pruning.test.d.ts.map +1 -0
  143. package/dist/test/tool-pruning.test.js +140 -0
  144. package/dist/test/tool-pruning.test.js.map +1 -0
  145. package/dist/tsconfig.tsbuildinfo +1 -1
  146. package/package.json +1 -1
  147. package/src/adaptive/chunker.ts +323 -0
  148. package/src/adaptive/folding-strategy.ts +129 -0
  149. package/src/adaptive/index.ts +51 -0
  150. package/src/adaptive/picker.ts +442 -0
  151. package/src/adaptive/render.ts +115 -0
  152. package/src/adaptive/strategies/flat-profile.ts +96 -0
  153. package/src/adaptive/strategies/oldest-first.ts +48 -0
  154. package/src/context-manager.ts +174 -10
  155. package/src/index.ts +1 -1
  156. package/src/message-store.ts +147 -8
  157. package/src/strategies/autobiographical.ts +2468 -166
  158. package/src/strategies/index.ts +1 -1
  159. package/src/types/index.ts +14 -1
  160. package/src/types/message.ts +43 -0
  161. package/src/types/strategy.ts +332 -10
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunker.test.d.ts","sourceRoot":"","sources":["../../../test/adaptive/chunker.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,120 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { chunkMessage, DEFAULT_CHUNKER_OPTIONS } from '../../src/adaptive/chunker.js';
4
+ // Use small thresholds for tests so we don't have to generate huge inputs.
5
+ const TINY = { chunkThreshold: 100, chunkSize: 40, charsPerToken: 1.0 };
6
+ test('chunker: under threshold passes through as single shard', () => {
7
+ const body = 'Hello world. This is a short message.';
8
+ const result = chunkMessage(body, TINY);
9
+ assert.equal(result.wasSharded, false);
10
+ assert.equal(result.shards.length, 1);
11
+ assert.equal(result.shards[0].content, body);
12
+ assert.equal(result.shards[0].range.startByte, 0);
13
+ assert.equal(result.shards[0].range.endByte, Buffer.byteLength(body, 'utf8'));
14
+ });
15
+ test('chunker: over threshold produces multiple shards with byte-faithful reassembly', () => {
16
+ // 12 lines of ~20 chars each ≈ 240 chars total, target 40 chars/shard → ~6 shards
17
+ const lines = [];
18
+ for (let i = 0; i < 12; i++)
19
+ lines.push(`Line number ${i.toString().padStart(2, '0')} text`);
20
+ const body = lines.join('\n');
21
+ const result = chunkMessage(body, TINY);
22
+ assert.equal(result.wasSharded, true);
23
+ assert.ok(result.shards.length >= 3, `expected ≥3 shards, got ${result.shards.length}`);
24
+ // Byte-faithful reassembly
25
+ const reassembled = result.shards.map((s) => s.content).join('');
26
+ assert.equal(reassembled, body, 'reassembled content must equal original byte-for-byte');
27
+ // Indices sequential from 0
28
+ for (let i = 0; i < result.shards.length; i++) {
29
+ assert.equal(result.shards[i].index, i);
30
+ }
31
+ // Byte ranges contiguous and cover the entire body
32
+ const bodyBytes = Buffer.byteLength(body, 'utf8');
33
+ let prevEnd = 0;
34
+ for (const s of result.shards) {
35
+ assert.equal(s.range.startByte, prevEnd, `gap or overlap at shard ${s.index}`);
36
+ prevEnd = s.range.endByte;
37
+ }
38
+ assert.equal(prevEnd, bodyBytes, 'final endByte must equal body length');
39
+ });
40
+ test('chunker: deterministic — same input produces identical shards', () => {
41
+ const body = 'a'.repeat(200) + '\n' + 'b'.repeat(200);
42
+ const r1 = chunkMessage(body, TINY);
43
+ const r2 = chunkMessage(body, TINY);
44
+ assert.equal(r1.bodyGroupId, r2.bodyGroupId);
45
+ assert.equal(r1.shards.length, r2.shards.length);
46
+ for (let i = 0; i < r1.shards.length; i++) {
47
+ assert.equal(r1.shards[i].sourceHash, r2.shards[i].sourceHash);
48
+ assert.equal(r1.shards[i].content, r2.shards[i].content);
49
+ assert.equal(r1.shards[i].range.startByte, r2.shards[i].range.startByte);
50
+ assert.equal(r1.shards[i].range.endByte, r2.shards[i].range.endByte);
51
+ }
52
+ });
53
+ test('chunker: prefers structural splits at markdown headings', () => {
54
+ const body = [
55
+ '## Section A',
56
+ 'Some text in section A. '.repeat(10),
57
+ '',
58
+ '## Section B',
59
+ 'Some text in section B. '.repeat(10),
60
+ '',
61
+ '## Section C',
62
+ 'Some text in section C. '.repeat(10),
63
+ ].join('\n');
64
+ // chunkSize chosen so ~one section fits per shard
65
+ const result = chunkMessage(body, { chunkThreshold: 50, chunkSize: 100, charsPerToken: 1.0 });
66
+ assert.equal(result.wasSharded, true);
67
+ // We expect splits at or near "## Section" boundaries. Verify at least one
68
+ // shard starts with "## Section".
69
+ const startsWithHeading = result.shards.filter((s, i) => i > 0 && s.content.startsWith('## Section'));
70
+ assert.ok(startsWithHeading.length >= 1, 'at least one mid-body shard should start at a heading');
71
+ });
72
+ test('chunker: handles long line without seams via hard split', () => {
73
+ // One very long line with no whitespace at all
74
+ const body = 'x'.repeat(500);
75
+ const result = chunkMessage(body, TINY);
76
+ assert.equal(result.wasSharded, true);
77
+ // Byte-faithful even with hard splits
78
+ assert.equal(result.shards.map((s) => s.content).join(''), body);
79
+ });
80
+ test('chunker: handles multi-byte UTF-8 (CJK) without corrupting characters', () => {
81
+ // Some Japanese text + emoji
82
+ const body = '日本語のテストです。' + '🌸'.repeat(50) + 'もう少しテキストを追加します。'.repeat(20);
83
+ const result = chunkMessage(body, { chunkThreshold: 30, chunkSize: 25, charsPerToken: 1.0 });
84
+ assert.equal(result.wasSharded, true);
85
+ // Reassembly must be byte-faithful
86
+ assert.equal(result.shards.map((s) => s.content).join(''), body);
87
+ // Each shard's content should round-trip through UTF-8 cleanly
88
+ for (const s of result.shards) {
89
+ const bytes = Buffer.from(s.content, 'utf8');
90
+ const decoded = bytes.toString('utf8');
91
+ assert.equal(decoded, s.content, `shard ${s.index} did not round-trip through UTF-8`);
92
+ }
93
+ });
94
+ test('chunker: sourceHash is stable across identical content in different runs', () => {
95
+ const fragment = 'This is some content that should hash identically.';
96
+ const r1 = chunkMessage(fragment + fragment + fragment + fragment + fragment, TINY);
97
+ const r2 = chunkMessage(fragment + fragment + fragment + fragment + fragment, TINY);
98
+ assert.equal(r1.shards[0].sourceHash, r2.shards[0].sourceHash);
99
+ });
100
+ test('chunker: bodyGroupId differs for different content', () => {
101
+ const r1 = chunkMessage('a'.repeat(500), TINY);
102
+ const r2 = chunkMessage('b'.repeat(500), TINY);
103
+ assert.notEqual(r1.bodyGroupId, r2.bodyGroupId);
104
+ });
105
+ test('chunker: large doc (synthetic 500K-token-equivalent) produces sensible shard count', () => {
106
+ // 500K tokens × 4 chars/token = 2M chars. Use a smaller synthetic stand-in to keep test fast.
107
+ // 50K chars at default chunkSize 4096 tokens × 4 chars = 16K chars/shard → ~3-4 shards.
108
+ // Use 200K chars to get ~12 shards.
109
+ const para = 'Paragraph of content. '.repeat(20); // ~440 chars per "paragraph"
110
+ const body = Array.from({ length: 500 }, () => para).join('\n\n'); // ~220K chars
111
+ const result = chunkMessage(body); // default options
112
+ assert.equal(result.wasSharded, true);
113
+ // Each shard should be ≤ chunkSize tokens (with some slack for seam-finding)
114
+ for (const s of result.shards) {
115
+ assert.ok(s.approxTokens <= DEFAULT_CHUNKER_OPTIONS.chunkSize * 1.3, `shard ${s.index} has ${s.approxTokens} tokens, exceeds chunkSize`);
116
+ }
117
+ // Byte-faithful
118
+ assert.equal(result.shards.map((s) => s.content).join(''), body);
119
+ });
120
+ //# sourceMappingURL=chunker.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunker.test.js","sourceRoot":"","sources":["../../../test/adaptive/chunker.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Tests that the bottom-up speculative pre-producer (config.speculativeProduction)
3
+ * builds the full L_n chain — not just L2/L3 like the legacy threshold path.
4
+ *
5
+ * Drives enough conversation to produce ≥ N^2 L1s, then verifies the chronicle
6
+ * ends up with L2, L3, L4, ... summaries via the same checkMergeThreshold
7
+ * mechanism (now recursive) that previously stopped at L3.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=deep-levels.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-levels.test.d.ts","sourceRoot":"","sources":["../../../test/adaptive/deep-levels.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Tests that the bottom-up speculative pre-producer (config.speculativeProduction)
3
+ * builds the full L_n chain — not just L2/L3 like the legacy threshold path.
4
+ *
5
+ * Drives enough conversation to produce ≥ N^2 L1s, then verifies the chronicle
6
+ * ends up with L2, L3, L4, ... summaries via the same checkMergeThreshold
7
+ * mechanism (now recursive) that previously stopped at L3.
8
+ */
9
+ import { describe, it, before, after, beforeEach } from 'node:test';
10
+ import assert from 'node:assert/strict';
11
+ import { rmSync, existsSync } from 'node:fs';
12
+ import { ContextManager, AutobiographicalStrategy } from '../../src/index.js';
13
+ const TEST_STORE_PATH = './test-adaptive-deep-levels-store';
14
+ function cleanup() {
15
+ if (existsSync(TEST_STORE_PATH)) {
16
+ rmSync(TEST_STORE_PATH, { recursive: true, force: true });
17
+ }
18
+ }
19
+ function makeMockMembrane() {
20
+ let callCount = 0;
21
+ return {
22
+ complete: async () => {
23
+ callCount++;
24
+ return {
25
+ content: [{ type: 'text', text: `[mock summary #${callCount}] short summary content here.` }],
26
+ };
27
+ },
28
+ get callCount() {
29
+ return callCount;
30
+ },
31
+ };
32
+ }
33
+ function summariesByLevel(strategy) {
34
+ const out = {};
35
+ for (const s of strategy.summaries) {
36
+ out[s.level] = (out[s.level] ?? 0) + 1;
37
+ }
38
+ return out;
39
+ }
40
+ describe('AutobiographicalStrategy — deep-level pre-production', () => {
41
+ before(() => cleanup());
42
+ after(() => cleanup());
43
+ beforeEach(() => cleanup());
44
+ it('speculativeProduction off: only L1/L2/L3 (legacy behavior)', async () => {
45
+ const mock = makeMockMembrane();
46
+ const strategy = new AutobiographicalStrategy({
47
+ adaptiveResolution: false,
48
+ targetChunkTokens: 100,
49
+ mergeThreshold: 3, // small so we get to deep levels quickly
50
+ recentWindowTokens: 50,
51
+ });
52
+ const manager = await ContextManager.open({
53
+ path: TEST_STORE_PATH,
54
+ strategy,
55
+ membrane: mock,
56
+ });
57
+ // Need enough chunks for L1 → L2 → L3 to fire under threshold=3.
58
+ for (let i = 0; i < 30; i++) {
59
+ manager.addMessage('User', [{ type: 'text', text: `Turn ${i}. ` + 'word '.repeat(30) }]);
60
+ }
61
+ while (!manager.isReady()) {
62
+ await manager.tick();
63
+ }
64
+ const counts = summariesByLevel(strategy);
65
+ // Legacy path caps at L3 — even with many L3s, no L4 is built.
66
+ assert.ok(!counts[4], `legacy path should not produce L4; got counts: ${JSON.stringify(counts)}`);
67
+ manager.close();
68
+ });
69
+ it('speculativeProduction on: produces L4+ when source counts warrant it', async () => {
70
+ const mock = makeMockMembrane();
71
+ const strategy = new AutobiographicalStrategy({
72
+ adaptiveResolution: true, // turns on speculativeProduction
73
+ targetChunkTokens: 80,
74
+ mergeThreshold: 2, // smallest possible — forces the chain to climb fast
75
+ recentWindowTokens: 50,
76
+ });
77
+ const manager = await ContextManager.open({
78
+ path: TEST_STORE_PATH,
79
+ strategy,
80
+ membrane: mock,
81
+ });
82
+ // With mergeThreshold=2, each level halves the count. So if we end up
83
+ // with N L1s after compression, we get:
84
+ // ceil(N/2) L2s, ceil(N/4) L3s, ceil(N/8) L4s, ...
85
+ // Need N ≥ 16 for L4 (2 L3s required to merge → L4).
86
+ for (let i = 0; i < 120; i++) {
87
+ manager.addMessage('User', [{ type: 'text', text: `T${i}. ` + 'word '.repeat(20) }]);
88
+ }
89
+ while (!manager.isReady()) {
90
+ await manager.tick();
91
+ }
92
+ const counts = summariesByLevel(strategy);
93
+ // Should see L1, L2, L3 — and L4 with threshold=2.
94
+ assert.ok(counts[1] > 0, `expected L1 summaries; got ${JSON.stringify(counts)}`);
95
+ assert.ok(counts[2] > 0, `expected L2 summaries; got ${JSON.stringify(counts)}`);
96
+ assert.ok(counts[3] > 0, `expected L3 summaries; got ${JSON.stringify(counts)}`);
97
+ assert.ok(counts[4] >= 1, `with mergeThreshold=2 and 120 chunks, expected at least one L4; got ${JSON.stringify(counts)}`);
98
+ manager.close();
99
+ });
100
+ it('parentId set correctly across deep levels', async () => {
101
+ const mock = makeMockMembrane();
102
+ const strategy = new AutobiographicalStrategy({
103
+ adaptiveResolution: true,
104
+ targetChunkTokens: 80,
105
+ mergeThreshold: 2,
106
+ recentWindowTokens: 50,
107
+ });
108
+ const manager = await ContextManager.open({
109
+ path: TEST_STORE_PATH,
110
+ strategy,
111
+ membrane: mock,
112
+ });
113
+ for (let i = 0; i < 120; i++) {
114
+ manager.addMessage('User', [{ type: 'text', text: `T${i}. ` + 'word '.repeat(20) }]);
115
+ }
116
+ while (!manager.isReady()) {
117
+ await manager.tick();
118
+ }
119
+ // Walk the summary tree. Every L_n summary (except the topmost) should
120
+ // have a parentId pointing to an L_{n+1} that exists.
121
+ const summaries = strategy.summaries;
122
+ const byId = new Map(summaries.map((s) => [s.id, s]));
123
+ let maxLevel = 0;
124
+ for (const s of summaries)
125
+ if (s.level > maxLevel)
126
+ maxLevel = s.level;
127
+ for (const s of summaries) {
128
+ const parentId = s.parentId ?? s.mergedInto;
129
+ if (s.level === maxLevel)
130
+ continue; // top level has no parent
131
+ if (!parentId)
132
+ continue; // legitimately may be the newest at its level, no parent yet
133
+ const parent = byId.get(parentId);
134
+ assert.ok(parent, `summary ${s.id} (L${s.level}) has parentId ${parentId} but parent not found`);
135
+ assert.equal(parent.level, s.level + 1, `parent of L${s.level} should be L${s.level + 1}`);
136
+ }
137
+ manager.close();
138
+ });
139
+ it('picker uses L4+ summaries when budget pressure requires it', async () => {
140
+ const mock = makeMockMembrane();
141
+ const strategy = new AutobiographicalStrategy({
142
+ adaptiveResolution: true,
143
+ targetChunkTokens: 80,
144
+ mergeThreshold: 2,
145
+ recentWindowTokens: 50,
146
+ });
147
+ const manager = await ContextManager.open({
148
+ path: TEST_STORE_PATH,
149
+ strategy,
150
+ membrane: mock,
151
+ });
152
+ for (let i = 0; i < 120; i++) {
153
+ manager.addMessage('User', [{ type: 'text', text: `T${i}. ` + 'word '.repeat(20) }]);
154
+ }
155
+ while (!manager.isReady()) {
156
+ await manager.tick();
157
+ }
158
+ // Aggressive compression to force the picker to reach L4+.
159
+ await manager.compile({ maxTokens: 600, reserveForResponse: 100 });
160
+ // Inspect strategy.resolutions for any value >= 3 (L3 or deeper).
161
+ const resolutions = strategy.resolutions;
162
+ const maxResolution = Math.max(0, ...Array.from(resolutions.values()));
163
+ assert.ok(maxResolution >= 3, `with tight budget and deep tree, picker should reach L3+; max resolution was L${maxResolution}`);
164
+ manager.close();
165
+ });
166
+ });
167
+ //# sourceMappingURL=deep-levels.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-levels.test.js","sourceRoot":"","sources":["../../../test/adaptive/deep-levels.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACpE,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE7C,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAE9E,MAAM,eAAe,GAAG,mCAAmC,CAAC;AAE5D,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;AAED,SAAS,gBAAgB;IACvB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,OAAO;QACL,QAAQ,EAAE,KAAK,IAAI,EAAE;YACnB,SAAS,EAAE,CAAC;YACZ,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,SAAS,+BAA+B,EAAE,CAAC;aAC9F,CAAC;QACJ,CAAC;QACD,IAAI,SAAS;YACX,OAAO,SAAS,CAAC;QACnB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,QAAa;IACrC,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,SAAqC,EAAE,CAAC;QAC/D,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;IACzC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,QAAQ,CAAC,sDAAsD,EAAE,GAAG,EAAE;IACpE,MAAM,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACxB,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACvB,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IAE5B,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,wBAAwB,CAAC;YAC5C,kBAAkB,EAAE,KAAK;YACzB,iBAAiB,EAAE,GAAG;YACtB,cAAc,EAAE,CAAC,EAAE,yCAAyC;YAC5D,kBAAkB,EAAE,EAAE;SACvB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC;YACxC,IAAI,EAAE,eAAe;YACrB,QAAQ;YACR,QAAQ,EAAE,IAAW;SACtB,CAAC,CAAC;QACH,iEAAiE;QACjE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QAC3F,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC1B,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC;QACD,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC1C,+DAA+D;QAC/D,MAAM,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,kDAAkD,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAClG,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QACpF,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,wBAAwB,CAAC;YAC5C,kBAAkB,EAAE,IAAI,EAAE,iCAAiC;YAC3D,iBAAiB,EAAE,EAAE;YACrB,cAAc,EAAE,CAAC,EAAE,qDAAqD;YACxE,kBAAkB,EAAE,EAAE;SACvB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC;YACxC,IAAI,EAAE,eAAe;YACrB,QAAQ;YACR,QAAQ,EAAE,IAAW;SACtB,CAAC,CAAC;QAEH,sEAAsE;QACtE,wCAAwC;QACxC,qDAAqD;QACrD,qDAAqD;QACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC1B,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC;QAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;QAC1C,mDAAmD;QACnD,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,8BAA8B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjF,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,8BAA8B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjF,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,8BAA8B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjF,MAAM,CAAC,EAAE,CACP,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EACd,uEAAuE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAChG,CAAC;QACF,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2CAA2C,EAAE,KAAK,IAAI,EAAE;QACzD,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,wBAAwB,CAAC;YAC5C,kBAAkB,EAAE,IAAI;YACxB,iBAAiB,EAAE,EAAE;YACrB,cAAc,EAAE,CAAC;YACjB,kBAAkB,EAAE,EAAE;SACvB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC;YACxC,IAAI,EAAE,eAAe;YACrB,QAAQ;YACR,QAAQ,EAAE,IAAW;SACtB,CAAC,CAAC;QACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC1B,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC;QAED,uEAAuE;QACvE,sDAAsD;QACtD,MAAM,SAAS,GAAI,QAAgB,CAAC,SAKlC,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,IAAI,QAAQ,GAAG,CAAC,CAAC;QACjB,KAAK,MAAM,CAAC,IAAI,SAAS;YAAE,IAAI,CAAC,CAAC,KAAK,GAAG,QAAQ;gBAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC;QAEtE,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,UAAU,CAAC;YAC5C,IAAI,CAAC,CAAC,KAAK,KAAK,QAAQ;gBAAE,SAAS,CAAC,0BAA0B;YAC9D,IAAI,CAAC,QAAQ;gBAAE,SAAS,CAAC,6DAA6D;YACtF,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAClC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,kBAAkB,QAAQ,uBAAuB,CAAC,CAAC;YACjG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,EAAE,cAAc,CAAC,CAAC,KAAK,eAAe,CAAC,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7F,CAAC;QACD,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,wBAAwB,CAAC;YAC5C,kBAAkB,EAAE,IAAI;YACxB,iBAAiB,EAAE,EAAE;YACrB,cAAc,EAAE,CAAC;YACjB,kBAAkB,EAAE,EAAE;SACvB,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC;YACxC,IAAI,EAAE,eAAe;YACrB,QAAQ;YACR,QAAQ,EAAE,IAAW;SACtB,CAAC,CAAC;QACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC;YAC1B,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC;QAED,2DAA2D;QAC3D,MAAM,OAAO,CAAC,OAAO,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,kBAAkB,EAAE,GAAG,EAAE,CAAC,CAAC;QAEnE,kEAAkE;QAClE,MAAM,WAAW,GAAI,QAAgB,CAAC,WAAkC,CAAC;QACzE,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QACvE,MAAM,CAAC,EAAE,CACP,aAAa,IAAI,CAAC,EAClB,iFAAiF,aAAa,EAAE,CACjG,CAAC;QACF,OAAO,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Realistic Lena-migration scenario: a chronicle that starts with a large doc,
3
+ * then has many turns of chat about/with that doc.
4
+ *
5
+ * Verifies the doc gets sharded at ingestion, the chat turns coexist with
6
+ * the doc shards, the picker handles both correctly, and the compiled
7
+ * output structure makes sense throughout.
8
+ */
9
+ export {};
10
+ //# sourceMappingURL=doc-plus-chat.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc-plus-chat.test.d.ts","sourceRoot":"","sources":["../../../test/adaptive/doc-plus-chat.test.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
@@ -0,0 +1,194 @@
1
+ /**
2
+ * Realistic Lena-migration scenario: a chronicle that starts with a large doc,
3
+ * then has many turns of chat about/with that doc.
4
+ *
5
+ * Verifies the doc gets sharded at ingestion, the chat turns coexist with
6
+ * the doc shards, the picker handles both correctly, and the compiled
7
+ * output structure makes sense throughout.
8
+ */
9
+ import { describe, it, before, after, beforeEach } from 'node:test';
10
+ import assert from 'node:assert/strict';
11
+ import { rmSync, existsSync } from 'node:fs';
12
+ import { ContextManager, AutobiographicalStrategy } from '../../src/index.js';
13
+ const TEST_STORE_PATH = './test-adaptive-doc-plus-chat-store';
14
+ function cleanup() {
15
+ if (existsSync(TEST_STORE_PATH)) {
16
+ rmSync(TEST_STORE_PATH, { recursive: true, force: true });
17
+ }
18
+ }
19
+ function makeMockMembrane() {
20
+ let callCount = 0;
21
+ return {
22
+ complete: async () => {
23
+ callCount++;
24
+ return {
25
+ content: [{ type: 'text', text: `[mock summary #${callCount}] short content.` }],
26
+ };
27
+ },
28
+ get callCount() {
29
+ return callCount;
30
+ },
31
+ };
32
+ }
33
+ function compiledTokens(compiled) {
34
+ let total = 0;
35
+ for (const m of compiled.messages) {
36
+ for (const block of m.content) {
37
+ if (block.type === 'text')
38
+ total += Math.ceil(block.text.length / 4);
39
+ }
40
+ }
41
+ return total;
42
+ }
43
+ describe('AutobiographicalStrategy — doc + chat workload (Lena-like)', () => {
44
+ before(() => cleanup());
45
+ after(() => cleanup());
46
+ beforeEach(() => cleanup());
47
+ it('500K-equivalent doc + 50 chat turns: budget honored throughout', async () => {
48
+ const mock = makeMockMembrane();
49
+ const BUDGET = 30000;
50
+ const strategy = new AutobiographicalStrategy({
51
+ adaptiveResolution: true,
52
+ targetChunkTokens: 1000, // ~4K chars per shard
53
+ recentWindowTokens: 2000,
54
+ mergeThreshold: 6,
55
+ compressionSlackRatio: 0.1,
56
+ });
57
+ const manager = await ContextManager.open({
58
+ path: TEST_STORE_PATH,
59
+ strategy,
60
+ membrane: mock,
61
+ });
62
+ // Synthetic ~500K-equivalent doc. Use 50K chars ≈ 12.5K tokens for test
63
+ // speed; chunker treats ~1K tokens per shard. ~12 shards.
64
+ const sections = [];
65
+ for (let s = 0; s < 12; s++) {
66
+ sections.push(`# Section ${s}\n\n` + 'paragraph content with some words. '.repeat(40));
67
+ }
68
+ const doc = sections.join('\n\n');
69
+ manager.addMessage('User', [{ type: 'text', text: doc }]);
70
+ // Verify sharding happened at ingestion
71
+ const allMessages = manager.getAllMessages();
72
+ assert.ok(allMessages.length > 1, `expected doc to shard; got ${allMessages.length} messages`);
73
+ const shardCount = allMessages.length;
74
+ const groupId = allMessages[0].bodyGroupId;
75
+ assert.ok(groupId, 'first shard should have bodyGroupId');
76
+ for (const m of allMessages) {
77
+ assert.equal(m.bodyGroupId, groupId, 'all shards share bodyGroupId');
78
+ }
79
+ while (!manager.isReady()) {
80
+ await manager.tick();
81
+ }
82
+ // First compile after doc — verify budget honored
83
+ const compiledAfterDoc = await manager.compile({ maxTokens: BUDGET, reserveForResponse: 1000 });
84
+ assert.ok(compiledTokens(compiledAfterDoc) <= BUDGET - 1000, `after-doc tokens exceed budget: ${compiledTokens(compiledAfterDoc)}`);
85
+ // Now 50 chat turns about the doc
86
+ for (let i = 0; i < 50; i++) {
87
+ manager.addMessage('User', [{ type: 'text', text: `Question ${i} about section ${i % 12}: ` + 'word '.repeat(20) }]);
88
+ manager.addMessage('Claude', [{ type: 'text', text: `Answer ${i}: ` + 'word '.repeat(25) }]);
89
+ while (!manager.isReady()) {
90
+ await manager.tick();
91
+ }
92
+ const compiled = await manager.compile({ maxTokens: BUDGET, reserveForResponse: 1000 });
93
+ const tokens = compiledTokens(compiled);
94
+ assert.ok(tokens <= BUDGET - 1000, `turn ${i}: ${tokens} tokens exceeds budget ${BUDGET - 1000}`);
95
+ }
96
+ // The compiled output should still reflect the doc somewhere
97
+ const finalCompile = await manager.compile({ maxTokens: BUDGET, reserveForResponse: 1000 });
98
+ const finalText = finalCompile.messages
99
+ .flatMap((m) => m.content)
100
+ .filter((b) => b.type === 'text')
101
+ .map((b) => b.text)
102
+ .join('\n');
103
+ // Either the doc is still raw-rendered, OR a summary referring to it appears
104
+ assert.ok(finalText.includes('Section') || finalText.includes('summary'), 'final compile should reference doc content via either raw or summary');
105
+ manager.close();
106
+ });
107
+ it('agent can lock a critical doc section and it survives folding pressure', async () => {
108
+ const mock = makeMockMembrane();
109
+ const strategy = new AutobiographicalStrategy({
110
+ adaptiveResolution: true,
111
+ targetChunkTokens: 500,
112
+ recentWindowTokens: 500,
113
+ });
114
+ const manager = await ContextManager.open({
115
+ path: TEST_STORE_PATH,
116
+ strategy,
117
+ membrane: mock,
118
+ });
119
+ // Doc with distinct sections — big enough to shard at targetChunkTokens=500
120
+ // (chunker threshold = 2x targetChunkTokens = 1000 tokens; we need ~10 sections
121
+ // × 200 tokens = 2000+ tokens to trigger sharding).
122
+ const sections = Array.from({ length: 10 }, (_, i) => `# Section ${i}\n\nCRITICAL-MARKER-${i} ` + 'distinctive word here. '.repeat(40));
123
+ manager.addMessage('User', [{ type: 'text', text: sections.join('\n\n') }]);
124
+ const shards = manager.getAllMessages();
125
+ assert.ok(shards.length > 1, `doc should shard; got ${shards.length} messages`);
126
+ // Lock shard 3 specifically
127
+ const criticalShard = shards[3];
128
+ strategy.lockChunk(criticalShard.id);
129
+ // Add chat to push pressure
130
+ for (let i = 0; i < 30; i++) {
131
+ manager.addMessage('User', [{ type: 'text', text: `T${i}` }]);
132
+ }
133
+ while (!manager.isReady()) {
134
+ await manager.tick();
135
+ }
136
+ // Tight compile
137
+ const compiled = await manager.compile({ maxTokens: 3500, reserveForResponse: 500 });
138
+ // The locked shard's resolution should remain 0 in strategy.resolutions
139
+ const resolutions = strategy.resolutions;
140
+ const lockedRes = resolutions.get(criticalShard.id) ?? 0;
141
+ assert.equal(lockedRes, 0, `locked shard should remain L0, got L${lockedRes}`);
142
+ // The compiled output should contain the locked shard's content verbatim
143
+ // (or at least the CRITICAL-MARKER-3 substring from its raw text).
144
+ const allText = compiled.messages
145
+ .flatMap((m) => m.content)
146
+ .filter((b) => b.type === 'text')
147
+ .map((b) => b.text)
148
+ .join('\n');
149
+ assert.ok(allText.includes('CRITICAL-MARKER-3'), 'compiled output should contain the locked shard\'s content verbatim');
150
+ manager.close();
151
+ });
152
+ it('doc + many turns: shards in different regions render correctly', async () => {
153
+ const mock = makeMockMembrane();
154
+ const strategy = new AutobiographicalStrategy({
155
+ adaptiveResolution: true,
156
+ targetChunkTokens: 400,
157
+ recentWindowTokens: 800,
158
+ mergeThreshold: 3,
159
+ });
160
+ const manager = await ContextManager.open({
161
+ path: TEST_STORE_PATH,
162
+ strategy,
163
+ membrane: mock,
164
+ });
165
+ // Doc → some shards in middle, some in tail
166
+ const doc = Array.from({ length: 15 }, (_, i) => `Section ${i}: ` + 'word '.repeat(60)).join('\n\n');
167
+ manager.addMessage('User', [{ type: 'text', text: doc }]);
168
+ // Trailing chat so the doc isn't all-tail
169
+ for (let i = 0; i < 8; i++) {
170
+ manager.addMessage('User', [{ type: 'text', text: `Followup ${i}` }]);
171
+ }
172
+ while (!manager.isReady()) {
173
+ await manager.tick();
174
+ }
175
+ const compiled = await manager.compile({ maxTokens: 5000, reserveForResponse: 500 });
176
+ // The compile should have produced output containing both doc content
177
+ // (some sections) and chat content (followups). The doc should be a
178
+ // combined entry (or entries) representing its shards.
179
+ const userMessages = compiled.messages.filter((m) => m.participant.toLowerCase() === 'user');
180
+ assert.ok(userMessages.length >= 2, 'should have multiple user messages (doc + chat)');
181
+ // Find a user message containing "Section" (from the doc)
182
+ const docEntry = userMessages.find((m) => m.content
183
+ .filter((b) => b.type === 'text')
184
+ .some((b) => b.text.includes('Section ')));
185
+ assert.ok(docEntry, 'should have a user entry with doc section content');
186
+ // Find a user message containing "Followup" (from chat)
187
+ const chatEntry = userMessages.find((m) => m.content
188
+ .filter((b) => b.type === 'text')
189
+ .some((b) => b.text.includes('Followup')));
190
+ assert.ok(chatEntry, 'should have a user entry with chat followup content');
191
+ manager.close();
192
+ });
193
+ });
194
+ //# sourceMappingURL=doc-plus-chat.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doc-plus-chat.test.js","sourceRoot":"","sources":["../../../test/adaptive/doc-plus-chat.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tests that selectAdaptive throws OverBudgetError when the picker has
3
+ * folded everything it can but the result still exceeds the hard budget.
4
+ *
5
+ * The strategy's philosophy: surface the overage rather than silently
6
+ * dropping entries. The host decides how to recover.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=hard-fail.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hard-fail.test.d.ts","sourceRoot":"","sources":["../../../test/adaptive/hard-fail.test.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}