@animalabs/context-manager 0.4.0 → 0.5.1

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 (128) 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 +5 -0
  30. package/dist/src/context-manager.d.ts.map +1 -1
  31. package/dist/src/context-manager.js +22 -0
  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 +217 -2
  41. package/dist/src/strategies/autobiographical.d.ts.map +1 -1
  42. package/dist/src/strategies/autobiographical.js +1525 -37
  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/message.d.ts +38 -0
  48. package/dist/src/types/message.d.ts.map +1 -1
  49. package/dist/src/types/strategy.d.ts +106 -10
  50. package/dist/src/types/strategy.d.ts.map +1 -1
  51. package/dist/src/types/strategy.js +7 -0
  52. package/dist/src/types/strategy.js.map +1 -1
  53. package/dist/test/adaptive/branching.test.d.ts +20 -0
  54. package/dist/test/adaptive/branching.test.d.ts.map +1 -0
  55. package/dist/test/adaptive/branching.test.js +176 -0
  56. package/dist/test/adaptive/branching.test.js.map +1 -0
  57. package/dist/test/adaptive/chunker.test.d.ts +2 -0
  58. package/dist/test/adaptive/chunker.test.d.ts.map +1 -0
  59. package/dist/test/adaptive/chunker.test.js +120 -0
  60. package/dist/test/adaptive/chunker.test.js.map +1 -0
  61. package/dist/test/adaptive/deep-levels.test.d.ts +10 -0
  62. package/dist/test/adaptive/deep-levels.test.d.ts.map +1 -0
  63. package/dist/test/adaptive/deep-levels.test.js +167 -0
  64. package/dist/test/adaptive/deep-levels.test.js.map +1 -0
  65. package/dist/test/adaptive/doc-plus-chat.test.d.ts +10 -0
  66. package/dist/test/adaptive/doc-plus-chat.test.d.ts.map +1 -0
  67. package/dist/test/adaptive/doc-plus-chat.test.js +194 -0
  68. package/dist/test/adaptive/doc-plus-chat.test.js.map +1 -0
  69. package/dist/test/adaptive/hard-fail.test.d.ts +9 -0
  70. package/dist/test/adaptive/hard-fail.test.d.ts.map +1 -0
  71. package/dist/test/adaptive/hard-fail.test.js +154 -0
  72. package/dist/test/adaptive/hard-fail.test.js.map +1 -0
  73. package/dist/test/adaptive/harness.d.ts +109 -0
  74. package/dist/test/adaptive/harness.d.ts.map +1 -0
  75. package/dist/test/adaptive/harness.js +263 -0
  76. package/dist/test/adaptive/harness.js.map +1 -0
  77. package/dist/test/adaptive/ingestion.test.d.ts +13 -0
  78. package/dist/test/adaptive/ingestion.test.d.ts.map +1 -0
  79. package/dist/test/adaptive/ingestion.test.js +306 -0
  80. package/dist/test/adaptive/ingestion.test.js.map +1 -0
  81. package/dist/test/adaptive/integration.test.d.ts +12 -0
  82. package/dist/test/adaptive/integration.test.d.ts.map +1 -0
  83. package/dist/test/adaptive/integration.test.js +247 -0
  84. package/dist/test/adaptive/integration.test.js.map +1 -0
  85. package/dist/test/adaptive/long-chronicle.test.d.ts +13 -0
  86. package/dist/test/adaptive/long-chronicle.test.d.ts.map +1 -0
  87. package/dist/test/adaptive/long-chronicle.test.js +186 -0
  88. package/dist/test/adaptive/long-chronicle.test.js.map +1 -0
  89. package/dist/test/adaptive/persistence.test.d.ts +11 -0
  90. package/dist/test/adaptive/persistence.test.d.ts.map +1 -0
  91. package/dist/test/adaptive/persistence.test.js +200 -0
  92. package/dist/test/adaptive/persistence.test.js.map +1 -0
  93. package/dist/test/adaptive/picker.test.d.ts +2 -0
  94. package/dist/test/adaptive/picker.test.d.ts.map +1 -0
  95. package/dist/test/adaptive/picker.test.js +333 -0
  96. package/dist/test/adaptive/picker.test.js.map +1 -0
  97. package/dist/test/adaptive/render.test.d.ts +2 -0
  98. package/dist/test/adaptive/render.test.d.ts.map +1 -0
  99. package/dist/test/adaptive/render.test.js +109 -0
  100. package/dist/test/adaptive/render.test.js.map +1 -0
  101. package/dist/test/adaptive/shard-immutability.test.d.ts +14 -0
  102. package/dist/test/adaptive/shard-immutability.test.d.ts.map +1 -0
  103. package/dist/test/adaptive/shard-immutability.test.js +184 -0
  104. package/dist/test/adaptive/shard-immutability.test.js.map +1 -0
  105. package/dist/test/adaptive/strategy-integration.test.d.ts +9 -0
  106. package/dist/test/adaptive/strategy-integration.test.d.ts.map +1 -0
  107. package/dist/test/adaptive/strategy-integration.test.js +293 -0
  108. package/dist/test/adaptive/strategy-integration.test.js.map +1 -0
  109. package/dist/test/message-store-sequence.test.d.ts +25 -0
  110. package/dist/test/message-store-sequence.test.d.ts.map +1 -0
  111. package/dist/test/message-store-sequence.test.js +157 -0
  112. package/dist/test/message-store-sequence.test.js.map +1 -0
  113. package/dist/tsconfig.tsbuildinfo +1 -1
  114. package/package.json +1 -1
  115. package/src/adaptive/chunker.ts +323 -0
  116. package/src/adaptive/folding-strategy.ts +129 -0
  117. package/src/adaptive/index.ts +51 -0
  118. package/src/adaptive/picker.ts +442 -0
  119. package/src/adaptive/render.ts +115 -0
  120. package/src/adaptive/strategies/flat-profile.ts +96 -0
  121. package/src/adaptive/strategies/oldest-first.ts +48 -0
  122. package/src/context-manager.ts +32 -0
  123. package/src/index.ts +1 -1
  124. package/src/message-store.ts +147 -8
  125. package/src/strategies/autobiographical.ts +1635 -38
  126. package/src/strategies/index.ts +1 -1
  127. package/src/types/message.ts +43 -0
  128. package/src/types/strategy.ts +122 -10
@@ -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":"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"}
@@ -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"}
@@ -0,0 +1,154 @@
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
+ import { describe, it, before, after, beforeEach } from 'node:test';
9
+ import assert from 'node:assert/strict';
10
+ import { rmSync, existsSync } from 'node:fs';
11
+ import { ContextManager, AutobiographicalStrategy } from '../../src/index.js';
12
+ import { OverBudgetError } from '../../src/adaptive/index.js';
13
+ const TEST_STORE_PATH = './test-adaptive-hard-fail-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}]` }],
26
+ };
27
+ },
28
+ get callCount() {
29
+ return callCount;
30
+ },
31
+ };
32
+ }
33
+ describe('AutobiographicalStrategy — adaptive OverBudgetError', () => {
34
+ before(() => cleanup());
35
+ after(() => cleanup());
36
+ beforeEach(() => cleanup());
37
+ it('throws OverBudgetError when tail alone exceeds budget', async () => {
38
+ const mock = makeMockMembrane();
39
+ const strategy = new AutobiographicalStrategy({
40
+ adaptiveResolution: true,
41
+ targetChunkTokens: 200,
42
+ // Large tail window: everything we add will be tail-resident, NOT
43
+ // foldable. The picker has nothing to do with it.
44
+ recentWindowTokens: 100_000,
45
+ });
46
+ const manager = await ContextManager.open({
47
+ path: TEST_STORE_PATH,
48
+ strategy,
49
+ membrane: mock,
50
+ });
51
+ // Add enough content that the tail alone is huge.
52
+ for (let i = 0; i < 30; i++) {
53
+ manager.addMessage('User', [{ type: 'text', text: `Msg ${i}. ` + 'word '.repeat(80) }]);
54
+ }
55
+ while (!manager.isReady()) {
56
+ await manager.tick();
57
+ }
58
+ // Budget so tight that even the tail can't fit. Picker has nothing it
59
+ // can fold (tail is treated as pinned).
60
+ await assert.rejects(() => manager.compile({ maxTokens: 500, reserveForResponse: 100 }), (err) => {
61
+ assert.ok(err instanceof OverBudgetError, `expected OverBudgetError, got ${err?.constructor?.name}`);
62
+ const e = err;
63
+ assert.ok(e.actual > e.budget, `actual ${e.actual} should exceed budget ${e.budget}`);
64
+ assert.ok(e.diagnostics.tailTokens > 0, 'diagnostics should include tail tokens');
65
+ return true;
66
+ });
67
+ manager.close();
68
+ });
69
+ it('does NOT throw when picker can fold its way under budget', async () => {
70
+ const mock = makeMockMembrane();
71
+ const strategy = new AutobiographicalStrategy({
72
+ adaptiveResolution: true,
73
+ targetChunkTokens: 100,
74
+ recentWindowTokens: 200,
75
+ });
76
+ const manager = await ContextManager.open({
77
+ path: TEST_STORE_PATH,
78
+ strategy,
79
+ membrane: mock,
80
+ });
81
+ for (let i = 0; i < 30; i++) {
82
+ manager.addMessage('User', [{ type: 'text', text: `Msg ${i}. ` + 'word '.repeat(40) }]);
83
+ }
84
+ while (!manager.isReady()) {
85
+ await manager.tick();
86
+ }
87
+ // Tight but reachable budget — picker should fold middle content to fit.
88
+ const compiled = await manager.compile({ maxTokens: 3000, reserveForResponse: 200 });
89
+ assert.ok(compiled.messages.length > 0);
90
+ manager.close();
91
+ });
92
+ it('does NOT throw under generous budget', async () => {
93
+ const mock = makeMockMembrane();
94
+ const strategy = new AutobiographicalStrategy({
95
+ adaptiveResolution: true,
96
+ targetChunkTokens: 100,
97
+ recentWindowTokens: 200,
98
+ });
99
+ const manager = await ContextManager.open({
100
+ path: TEST_STORE_PATH,
101
+ strategy,
102
+ membrane: mock,
103
+ });
104
+ for (let i = 0; i < 10; i++) {
105
+ manager.addMessage('User', [{ type: 'text', text: `Msg ${i}` }]);
106
+ }
107
+ const compiled = await manager.compile({ maxTokens: 100_000, reserveForResponse: 200 });
108
+ assert.ok(compiled.messages.length > 0);
109
+ manager.close();
110
+ });
111
+ it('error diagnostics include useful state info', async () => {
112
+ const mock = makeMockMembrane();
113
+ const strategy = new AutobiographicalStrategy({
114
+ adaptiveResolution: true,
115
+ targetChunkTokens: 200,
116
+ recentWindowTokens: 100_000,
117
+ });
118
+ const manager = await ContextManager.open({
119
+ path: TEST_STORE_PATH,
120
+ strategy,
121
+ membrane: mock,
122
+ });
123
+ for (let i = 0; i < 20; i++) {
124
+ manager.addMessage('User', [{ type: 'text', text: `Msg ${i}. ` + 'word '.repeat(80) }]);
125
+ }
126
+ while (!manager.isReady()) {
127
+ await manager.tick();
128
+ }
129
+ let caught = null;
130
+ try {
131
+ await manager.compile({ maxTokens: 400, reserveForResponse: 100 });
132
+ }
133
+ catch (err) {
134
+ if (err instanceof OverBudgetError)
135
+ caught = err;
136
+ }
137
+ assert.ok(caught, 'should have caught OverBudgetError');
138
+ if (!caught) {
139
+ manager.close();
140
+ return;
141
+ }
142
+ assert.equal(typeof caught.budget, 'number');
143
+ assert.equal(typeof caught.actual, 'number');
144
+ assert.equal(typeof caught.diagnostics.headTokens, 'number');
145
+ assert.equal(typeof caught.diagnostics.tailTokens, 'number');
146
+ assert.equal(typeof caught.diagnostics.middleTokens, 'number');
147
+ assert.equal(typeof caught.diagnostics.deepestLevel, 'number');
148
+ // The error message should be informative
149
+ assert.ok(caught.message.includes('exhausted'));
150
+ assert.ok(caught.message.includes('hard budget'));
151
+ manager.close();
152
+ });
153
+ });
154
+ //# sourceMappingURL=hard-fail.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hard-fail.test.js","sourceRoot":"","sources":["../../../test/adaptive/hard-fail.test.ts"],"names":[],"mappings":"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"}