@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,357 @@
1
+ /**
2
+ * Picker orchestrator for the adaptive-resolution design.
3
+ *
4
+ * The picker is a thin loop: build a FoldingState, call strategy.selectNextFold
5
+ * until it returns null, applying 'raise'/'lower' ops as they come and recording
6
+ * 'produce' ops for the caller to enqueue.
7
+ *
8
+ * The picker is stateless across runs — all persistent state lives on the
9
+ * per-chunk fields. Each run builds a fresh FoldingState from the inputs.
10
+ *
11
+ * See `docs/adaptive-resolution-design.md` §5.
12
+ */
13
+ import { getSummaryParentId } from '../types/strategy.js';
14
+ /**
15
+ * Error raised by the strategy when the picker has folded everything it can
16
+ * and the resulting context still exceeds the hard token budget.
17
+ *
18
+ * The strategy throws this rather than silently dropping entries. The host
19
+ * application decides how to respond — typical responses: raise the budget,
20
+ * switch to a larger-context model, drop the head/tail windows explicitly,
21
+ * or surface a "context too large" error to the user.
22
+ *
23
+ * See `docs/adaptive-resolution-design.md` §3.10.
24
+ */
25
+ export class OverBudgetError extends Error {
26
+ /** The hard budget the strategy was trying to fit under. */
27
+ budget;
28
+ /** The token count the strategy could not reduce below `budget`. */
29
+ actual;
30
+ /** Diagnostic snapshot of the picker's final state. */
31
+ diagnostics;
32
+ constructor(opts) {
33
+ super(`Adaptive picker exhausted but ${opts.actual} tokens still exceed hard budget ${opts.budget}` +
34
+ ` (head=${opts.diagnostics.headTokens}, tail=${opts.diagnostics.tailTokens},` +
35
+ ` middle=${opts.diagnostics.middleTokens} across ${opts.diagnostics.middleChunkCount} chunks,` +
36
+ ` deepest fold level=L${opts.diagnostics.deepestLevel})`);
37
+ // Writable per Error convention so instanceof-by-name works across
38
+ // iframe / vm boundaries; the field stays writable on the prototype.
39
+ this.name = 'OverBudgetError';
40
+ this.budget = opts.budget;
41
+ this.actual = opts.actual;
42
+ this.diagnostics = opts.diagnostics;
43
+ }
44
+ }
45
+ /**
46
+ * Floor for the per-run loop bound. Scales with chronicle size to keep the
47
+ * picker from spuriously declaring non-convergence on large stores. See
48
+ * {@link iterationBound}.
49
+ */
50
+ const MIN_ITERATIONS = 1_000;
51
+ /**
52
+ * Compute the per-run loop bound from chronicle size. A well-behaved strategy
53
+ * converges in at most ~one op per chunk per level (`chunks.length * log_N`),
54
+ * so `chunks.length * 10` is a generous safety net at any reasonable N, and
55
+ * `MIN_ITERATIONS` ensures small chronicles still get adequate headroom for
56
+ * exploratory ops before the strategy commits to a fold.
57
+ *
58
+ * Returning a numeric bound rather than a constant means a 5K-chunk run no
59
+ * longer trips a fixed 10K ceiling that wasn't sized for it.
60
+ */
61
+ function iterationBound(chunkCount) {
62
+ return Math.max(MIN_ITERATIONS, chunkCount * 10);
63
+ }
64
+ export class Picker {
65
+ strategy;
66
+ constructor(strategy) {
67
+ this.strategy = strategy;
68
+ }
69
+ run(inputs, budget) {
70
+ const state = new MutableFoldingState(inputs);
71
+ const applied = [];
72
+ const produced = [];
73
+ let iterations = 0;
74
+ const maxIterations = iterationBound(inputs.chunks.length);
75
+ while (iterations < maxIterations) {
76
+ const op = this.strategy.selectNextFold(state, budget);
77
+ if (!op)
78
+ break;
79
+ iterations++;
80
+ if (op.kind === 'raise') {
81
+ state.applyRaise(op.groupRoot);
82
+ applied.push(op);
83
+ }
84
+ else if (op.kind === 'lower') {
85
+ state.applyLower(op.groupRoot);
86
+ applied.push(op);
87
+ }
88
+ else {
89
+ // produce — record and stop. Caller enqueues; next compile retries.
90
+ produced.push(op);
91
+ break;
92
+ }
93
+ }
94
+ if (iterations >= maxIterations) {
95
+ throw new Error(`Picker: strategy ${this.strategy.name} exceeded iteration bound (${maxIterations}` +
96
+ ` for ${inputs.chunks.length} chunks); likely non-converging`);
97
+ }
98
+ return {
99
+ finalResolutions: state.snapshotResolutions(),
100
+ applied,
101
+ produced,
102
+ finalTokens: state.tokenCount(),
103
+ budgetMet: state.tokenCount() <= budget.targetBudget,
104
+ exhausted: produced.length === 0 && state.tokenCount() > budget.targetBudget,
105
+ iterations,
106
+ };
107
+ }
108
+ }
109
+ // ---------------------------------------------------------------------------
110
+ /**
111
+ * Internal mutable state used during one picker run.
112
+ *
113
+ * Implements FoldingState (the strategy-facing view) and additional methods
114
+ * for applying fold ops.
115
+ */
116
+ class MutableFoldingState {
117
+ chunkById = new Map();
118
+ chunkOrder;
119
+ summaries;
120
+ recallPairTokens;
121
+ headChunkIds;
122
+ tailChunkIds;
123
+ headTokens;
124
+ tailTokens;
125
+ // Cached: chunks that are foldable (middle, not pinned, not locked).
126
+ // Updated lazily when needed.
127
+ foldableCache = null;
128
+ allChunkViews = null;
129
+ tokenCacheValid = false;
130
+ tokenCacheValue = 0;
131
+ // For each chunk, its current resolution (mirrors PickerChunk.currentResolution).
132
+ resolutions = new Map();
133
+ constructor(inputs) {
134
+ this.chunkOrder = [...inputs.chunks].sort((a, b) => a.sequence - b.sequence);
135
+ for (const c of this.chunkOrder) {
136
+ this.chunkById.set(c.id, c);
137
+ this.resolutions.set(c.id, c.currentResolution);
138
+ }
139
+ this.summaries = inputs.summaries;
140
+ this.recallPairTokens = inputs.recallPairTokens ?? new Map();
141
+ this.headChunkIds = inputs.headChunkIds;
142
+ this.tailChunkIds = inputs.tailChunkIds;
143
+ this.headTokens = inputs.headTokens;
144
+ this.tailTokens = inputs.tailTokens;
145
+ }
146
+ // ---- FoldingState interface ----
147
+ chunks() {
148
+ if (!this.allChunkViews) {
149
+ this.allChunkViews = this.chunkOrder.map((c) => this.makeView(c));
150
+ }
151
+ return this.allChunkViews;
152
+ }
153
+ foldableMiddle() {
154
+ if (this.foldableCache)
155
+ return this.foldableCache;
156
+ const out = [];
157
+ for (const c of this.chunkOrder) {
158
+ const inHead = this.headChunkIds.has(c.id);
159
+ const inTail = this.tailChunkIds.has(c.id);
160
+ if (inHead || inTail || c.pinned || c.lockedByAgent)
161
+ continue;
162
+ out.push(this.makeView(c));
163
+ }
164
+ this.foldableCache = out;
165
+ return out;
166
+ }
167
+ getSummary(id) {
168
+ return this.summaries.get(id) ?? null;
169
+ }
170
+ leavesUnder(groupRoot) {
171
+ const summary = this.summaries.get(groupRoot);
172
+ if (!summary)
173
+ return [];
174
+ const leafIds = this.collectLeafIds(summary);
175
+ const views = [];
176
+ for (const id of leafIds) {
177
+ const c = this.chunkById.get(id);
178
+ if (c)
179
+ views.push(this.makeView(c));
180
+ }
181
+ return views;
182
+ }
183
+ tokenCount() {
184
+ if (this.tokenCacheValid)
185
+ return this.tokenCacheValue;
186
+ this.tokenCacheValue = this.computeTokens();
187
+ this.tokenCacheValid = true;
188
+ return this.tokenCacheValue;
189
+ }
190
+ // ---- Mutation methods (picker-internal) ----
191
+ applyRaise(groupRoot) {
192
+ const summary = this.summaries.get(groupRoot);
193
+ if (!summary) {
194
+ throw new Error(`Picker: applyRaise: unknown groupRoot ${groupRoot}`);
195
+ }
196
+ const targetLevel = summary.level;
197
+ const leafIds = this.collectLeafIds(summary);
198
+ for (const id of leafIds) {
199
+ const chunk = this.chunkById.get(id);
200
+ if (!chunk)
201
+ continue;
202
+ // Skip chunks that the picker has no authority over for resolution.
203
+ // Pinned chunks always render raw (handled at render time), but we
204
+ // also avoid setting stale resolution state on them — the resolution
205
+ // field is meaningless while pinned and might be visited later if
206
+ // the pin is removed, which would be surprising.
207
+ if (chunk.pinned)
208
+ continue;
209
+ if (chunk.lockedByAgent)
210
+ continue;
211
+ if (this.headChunkIds.has(id) || this.tailChunkIds.has(id))
212
+ continue;
213
+ const current = this.resolutions.get(id) ?? 0;
214
+ if (current < targetLevel) {
215
+ this.resolutions.set(id, targetLevel);
216
+ }
217
+ }
218
+ this.invalidateCaches();
219
+ }
220
+ applyLower(groupRoot) {
221
+ const summary = this.summaries.get(groupRoot);
222
+ if (!summary) {
223
+ throw new Error(`Picker: applyLower: unknown groupRoot ${groupRoot}`);
224
+ }
225
+ // Lower every leaf under groupRoot by one level (clamped at 0).
226
+ const leafIds = this.collectLeafIds(summary);
227
+ for (const id of leafIds) {
228
+ const chunk = this.chunkById.get(id);
229
+ if (!chunk)
230
+ continue;
231
+ if (chunk.lockedByAgent)
232
+ continue;
233
+ const current = this.resolutions.get(id) ?? 0;
234
+ if (current > 0) {
235
+ this.resolutions.set(id, current - 1);
236
+ }
237
+ }
238
+ this.invalidateCaches();
239
+ }
240
+ snapshotResolutions() {
241
+ return new Map(this.resolutions);
242
+ }
243
+ // ---- Internals ----
244
+ invalidateCaches() {
245
+ this.foldableCache = null;
246
+ this.allChunkViews = null;
247
+ this.tokenCacheValid = false;
248
+ }
249
+ makeView(c) {
250
+ const self = this;
251
+ return {
252
+ id: c.id,
253
+ sequence: c.sequence,
254
+ rawTokens: c.rawTokens,
255
+ currentResolution: self.resolutions.get(c.id) ?? 0,
256
+ lockedByAgent: c.lockedByAgent,
257
+ bodyGroupId: c.bodyGroupId,
258
+ inHead: self.headChunkIds.has(c.id),
259
+ inTail: self.tailChunkIds.has(c.id),
260
+ pinned: c.pinned,
261
+ ancestorAt(level) {
262
+ return self.ancestorAt(c, level);
263
+ },
264
+ maxAvailableLevel() {
265
+ return self.maxAvailableLevel(c);
266
+ },
267
+ };
268
+ }
269
+ ancestorAt(chunk, level) {
270
+ if (level <= 0)
271
+ return null;
272
+ if (!chunk.l1Id)
273
+ return null;
274
+ let current = this.summaries.get(chunk.l1Id);
275
+ while (current && current.level < level) {
276
+ const parentId = getSummaryParentId(current);
277
+ if (!parentId)
278
+ return null;
279
+ current = this.summaries.get(parentId);
280
+ }
281
+ if (!current || current.level !== level)
282
+ return null;
283
+ return current;
284
+ }
285
+ maxAvailableLevel(chunk) {
286
+ if (!chunk.l1Id)
287
+ return 0;
288
+ let current = this.summaries.get(chunk.l1Id);
289
+ let max = 0;
290
+ while (current) {
291
+ max = current.level;
292
+ const parentId = getSummaryParentId(current);
293
+ if (!parentId)
294
+ break;
295
+ current = this.summaries.get(parentId);
296
+ }
297
+ return max;
298
+ }
299
+ collectLeafIds(summary) {
300
+ // Walk down the summary tree from `summary` to leaf chunks.
301
+ // sourceLevel === 0 means sourceIds are message ids (leaves).
302
+ // Otherwise sourceIds are summary ids and we recurse.
303
+ const out = [];
304
+ const visit = (s) => {
305
+ if (s.sourceLevel === 0) {
306
+ for (const mid of s.sourceIds)
307
+ out.push(mid);
308
+ }
309
+ else {
310
+ for (const sid of s.sourceIds) {
311
+ const child = this.summaries.get(sid);
312
+ if (child)
313
+ visit(child);
314
+ }
315
+ }
316
+ };
317
+ visit(summary);
318
+ return out;
319
+ }
320
+ /**
321
+ * Compute total tokens given current resolutions.
322
+ * Algorithm:
323
+ * - Head + tail are fixed.
324
+ * - For chunks in foldableMiddle: those at L0 contribute rawTokens.
325
+ * - Those at L_k (k>0): emit the recall pair for the chunk's L_k ancestor
326
+ * once per distinct ancestor (sibling chunks under the same ancestor
327
+ * share the same rendered recall pair).
328
+ */
329
+ computeTokens() {
330
+ let total = this.headTokens + this.tailTokens;
331
+ const renderedSummaries = new Set();
332
+ for (const c of this.chunkOrder) {
333
+ if (this.headChunkIds.has(c.id) || this.tailChunkIds.has(c.id))
334
+ continue;
335
+ // Pinned chunks render at L0 regardless of resolution.
336
+ const effectiveResolution = c.pinned ? 0 : this.resolutions.get(c.id) ?? 0;
337
+ if (effectiveResolution === 0) {
338
+ total += c.rawTokens;
339
+ continue;
340
+ }
341
+ const ancestor = this.ancestorAt(c, effectiveResolution);
342
+ if (!ancestor) {
343
+ // Resolution is set but summary doesn't exist — treat as L0 for
344
+ // accounting purposes (the renderer will need to make the same call).
345
+ total += c.rawTokens;
346
+ continue;
347
+ }
348
+ if (renderedSummaries.has(ancestor.id))
349
+ continue;
350
+ renderedSummaries.add(ancestor.id);
351
+ const tok = this.recallPairTokens.get(ancestor.id) ?? ancestor.tokens;
352
+ total += tok;
353
+ }
354
+ return total;
355
+ }
356
+ }
357
+ //# sourceMappingURL=picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"picker.js","sourceRoot":"","sources":["../../../src/adaptive/picker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Render helpers for the adaptive-resolution design.
3
+ *
4
+ * The main operation is "group consecutive same-bodyGroupId messages into
5
+ * a single API message via body concatenation," which is how a chunked
6
+ * document or large message is reassembled at the API boundary.
7
+ *
8
+ * See `docs/adaptive-resolution-design.md` §3.6.
9
+ */
10
+ import type { StoredMessage } from '../types/message.js';
11
+ /**
12
+ * Group consecutive messages that share a bodyGroupId into composite
13
+ * messages whose body is the byte-faithful concatenation of the shards'
14
+ * text content. Messages with a null/undefined bodyGroupId pass through
15
+ * unchanged.
16
+ *
17
+ * For a shard at non-zero currentResolution, the shard's text in the
18
+ * concatenation is replaced by `getRecallText(shard)`. The renderer is
19
+ * responsible for providing recall content that's appropriate for the
20
+ * level (an L_k recall pair, formatted however the deployment prefers).
21
+ *
22
+ * Properties:
23
+ * - **Byte-faithful** when all shards in a group are at L0 and getRecallText
24
+ * is not called: the concatenated body equals the original message body
25
+ * byte-for-byte. Verified by tests in test/adaptive/render.test.ts.
26
+ * - **One API message per group**, regardless of shard count. No turn
27
+ * markers between shards.
28
+ * - **Order preserved**: shards within a group are sorted by `shardIndex`
29
+ * before concatenation; if shardIndex is missing, the order in the input
30
+ * array is used.
31
+ */
32
+ export declare function concatBodyGroups(messages: readonly StoredMessage[], getRecallText: (shard: StoredMessage) => string): StoredMessage[];
33
+ /**
34
+ * Default getRecallText for testing or when the strategy hasn't provided
35
+ * a custom one. Returns a simple "[summary of N tokens]" placeholder so
36
+ * the concat doesn't accidentally include the raw shard text.
37
+ */
38
+ export declare function placeholderRecallText(shard: StoredMessage): string;
39
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/adaptive/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,SAAS,aAAa,EAAE,EAClC,aAAa,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,MAAM,GAC9C,aAAa,EAAE,CA+CjB;AAsBD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAGlE"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Render helpers for the adaptive-resolution design.
3
+ *
4
+ * The main operation is "group consecutive same-bodyGroupId messages into
5
+ * a single API message via body concatenation," which is how a chunked
6
+ * document or large message is reassembled at the API boundary.
7
+ *
8
+ * See `docs/adaptive-resolution-design.md` §3.6.
9
+ */
10
+ /**
11
+ * Group consecutive messages that share a bodyGroupId into composite
12
+ * messages whose body is the byte-faithful concatenation of the shards'
13
+ * text content. Messages with a null/undefined bodyGroupId pass through
14
+ * unchanged.
15
+ *
16
+ * For a shard at non-zero currentResolution, the shard's text in the
17
+ * concatenation is replaced by `getRecallText(shard)`. The renderer is
18
+ * responsible for providing recall content that's appropriate for the
19
+ * level (an L_k recall pair, formatted however the deployment prefers).
20
+ *
21
+ * Properties:
22
+ * - **Byte-faithful** when all shards in a group are at L0 and getRecallText
23
+ * is not called: the concatenated body equals the original message body
24
+ * byte-for-byte. Verified by tests in test/adaptive/render.test.ts.
25
+ * - **One API message per group**, regardless of shard count. No turn
26
+ * markers between shards.
27
+ * - **Order preserved**: shards within a group are sorted by `shardIndex`
28
+ * before concatenation; if shardIndex is missing, the order in the input
29
+ * array is used.
30
+ */
31
+ export function concatBodyGroups(messages, getRecallText) {
32
+ const out = [];
33
+ let i = 0;
34
+ while (i < messages.length) {
35
+ const m = messages[i];
36
+ if (!m.bodyGroupId) {
37
+ out.push(m);
38
+ i++;
39
+ continue;
40
+ }
41
+ // Collect all consecutive messages with the same bodyGroupId.
42
+ const groupId = m.bodyGroupId;
43
+ const groupStart = i;
44
+ while (i < messages.length && messages[i].bodyGroupId === groupId) {
45
+ i++;
46
+ }
47
+ const group = messages.slice(groupStart, i);
48
+ // Sort by shardIndex if present.
49
+ const sorted = [...group].sort((a, b) => (a.shardIndex ?? 0) - (b.shardIndex ?? 0));
50
+ const concatenated = sorted.map((shard) => {
51
+ const res = shard.currentResolution ?? 0;
52
+ if (res === 0) {
53
+ return extractTextContent(shard.content);
54
+ }
55
+ return getRecallText(shard);
56
+ }).join('');
57
+ // Build the composite message. Inherit id/participant/timestamp from
58
+ // the first shard; combine metadata; build a single text content block.
59
+ const composite = {
60
+ id: sorted[0].id,
61
+ sequence: sorted[0].sequence,
62
+ participant: sorted[0].participant,
63
+ content: [{ type: 'text', text: concatenated }],
64
+ metadata: {
65
+ ...(sorted[0].metadata ?? {}),
66
+ bodyGroupId: groupId,
67
+ shardCount: sorted.length,
68
+ },
69
+ timestamp: sorted[0].timestamp,
70
+ };
71
+ out.push(composite);
72
+ }
73
+ return out;
74
+ }
75
+ /**
76
+ * Extract text content from a message's content blocks. For shards we
77
+ * expect (and require) all content to be text — they were produced by
78
+ * the chunker, which only splits strings. If non-text blocks slip through,
79
+ * they're stringified as best-effort.
80
+ */
81
+ function extractTextContent(blocks) {
82
+ const out = [];
83
+ for (const b of blocks) {
84
+ if (b.type === 'text') {
85
+ out.push(b.text);
86
+ }
87
+ else {
88
+ // Non-text content in a sharded body shouldn't happen, but if it
89
+ // does, we serialize as a placeholder rather than crashing.
90
+ out.push(`[non-text content: ${b.type}]`);
91
+ }
92
+ }
93
+ return out.join('');
94
+ }
95
+ /**
96
+ * Default getRecallText for testing or when the strategy hasn't provided
97
+ * a custom one. Returns a simple "[summary of N tokens]" placeholder so
98
+ * the concat doesn't accidentally include the raw shard text.
99
+ */
100
+ export function placeholderRecallText(shard) {
101
+ const level = shard.currentResolution ?? 0;
102
+ return `\n[L${level} recall of chunk ${shard.id}]\n`;
103
+ }
104
+ //# sourceMappingURL=render.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.js","sourceRoot":"","sources":["../../../src/adaptive/render.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Default folding strategy: keep visible-item counts roughly equal across levels.
3
+ *
4
+ * On each call: if we're over the soft target, find the level with the most
5
+ * *rendered items* (distinct ancestors among chunks at that resolution),
6
+ * pick the oldest raisable group at that level, raise it. Tiebreak on level:
7
+ * lower level wins (fold finer detail before consolidating coarser regions).
8
+ *
9
+ * Monotonic (never emits 'lower'). Memory-fading by construction:
10
+ * a given chunk's resolution only ever increases.
11
+ *
12
+ * See `docs/adaptive-resolution-design.md` §3.7.
13
+ */
14
+ import type { FoldingStrategy, FoldingState, FoldingBudget, FoldOp } from '../folding-strategy.js';
15
+ export declare class FlatProfileStrategy implements FoldingStrategy {
16
+ readonly name = "flat-profile";
17
+ selectNextFold(state: FoldingState, budget: FoldingBudget): FoldOp | null;
18
+ }
19
+ //# sourceMappingURL=flat-profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flat-profile.d.ts","sourceRoot":"","sources":["../../../../src/adaptive/strategies/flat-profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,aAAa,EACb,MAAM,EAIP,MAAM,wBAAwB,CAAC;AAEhC,qBAAa,mBAAoB,YAAW,eAAe;IACzD,QAAQ,CAAC,IAAI,kBAAkB;IAE/B,cAAc,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,GAAG,IAAI;CAoE1E"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Default folding strategy: keep visible-item counts roughly equal across levels.
3
+ *
4
+ * On each call: if we're over the soft target, find the level with the most
5
+ * *rendered items* (distinct ancestors among chunks at that resolution),
6
+ * pick the oldest raisable group at that level, raise it. Tiebreak on level:
7
+ * lower level wins (fold finer detail before consolidating coarser regions).
8
+ *
9
+ * Monotonic (never emits 'lower'). Memory-fading by construction:
10
+ * a given chunk's resolution only ever increases.
11
+ *
12
+ * See `docs/adaptive-resolution-design.md` §3.7.
13
+ */
14
+ export class FlatProfileStrategy {
15
+ name = 'flat-profile';
16
+ selectNextFold(state, budget) {
17
+ if (state.tokenCount() <= budget.targetBudget)
18
+ return null;
19
+ const middle = state.foldableMiddle();
20
+ if (middle.length === 0)
21
+ return null;
22
+ // Count rendered items at each level.
23
+ // A "rendered item" at level k > 0 is a distinct L_k ancestor.
24
+ // At level 0, each raw chunk is its own item.
25
+ const visibleAtLevel = new Map();
26
+ for (const chunk of middle) {
27
+ const k = chunk.currentResolution;
28
+ if (!visibleAtLevel.has(k))
29
+ visibleAtLevel.set(k, new Set());
30
+ if (k === 0) {
31
+ visibleAtLevel.get(k).add(chunk.id);
32
+ }
33
+ else {
34
+ const ancestor = chunk.ancestorAt(k);
35
+ if (ancestor)
36
+ visibleAtLevel.get(k).add(ancestor.id);
37
+ }
38
+ }
39
+ // Pick most-populous level; tiebreak: lower wins.
40
+ let bestLevel = -1;
41
+ let bestCount = 0;
42
+ for (const [level, items] of visibleAtLevel) {
43
+ const count = items.size;
44
+ if (count > bestCount || (count === bestCount && (bestLevel < 0 || level < bestLevel))) {
45
+ bestLevel = level;
46
+ bestCount = count;
47
+ }
48
+ }
49
+ if (bestLevel < 0)
50
+ return null;
51
+ // Find the oldest raisable group at bestLevel. A "group" at level k is
52
+ // the set of chunks sharing an L_{k+1} ancestor. We want to raise that
53
+ // group all the way to L_{k+1}.
54
+ //
55
+ // The oldest group is the one containing the oldest chunk at level k.
56
+ const oldestChunk = middle.find((c) => c.currentResolution === bestLevel);
57
+ if (!oldestChunk)
58
+ return null;
59
+ const parentLevel = bestLevel + 1;
60
+ const parentSummary = oldestChunk.ancestorAt(parentLevel);
61
+ if (!parentSummary) {
62
+ // L_{k+1} not produced for this chunk's group yet — request it.
63
+ //
64
+ // Range semantics differ by level:
65
+ // - bestLevel === 0: the caller is asking for an L1 covering this
66
+ // raw chunk. In the autobio chunker model the chunk-to-L1 mapping
67
+ // is 1:1 — a chunk's message span IS the L1's source range — so
68
+ // a single-chunk range is the correct request. (Strategies that
69
+ // bundle N raw chunks into one L1 would override this.)
70
+ // - bestLevel > 0: the caller is asking for an L_{k+1} merge. We
71
+ // use the chunk's existing L_k ancestor's range as a request
72
+ // hint; the consumer expands it to cover the full sibling set
73
+ // at L_k that should consolidate into the missing L_{k+1}.
74
+ const lkAncestor = bestLevel === 0 ? null : oldestChunk.ancestorAt(bestLevel);
75
+ const range = lkAncestor
76
+ ? {
77
+ firstChunkId: lkAncestor.sourceRange.first,
78
+ lastChunkId: lkAncestor.sourceRange.last,
79
+ }
80
+ : { firstChunkId: oldestChunk.id, lastChunkId: oldestChunk.id };
81
+ return { kind: 'produce', level: parentLevel, range };
82
+ }
83
+ return { kind: 'raise', groupRoot: parentSummary.id };
84
+ }
85
+ }
86
+ //# sourceMappingURL=flat-profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flat-profile.js","sourceRoot":"","sources":["../../../../src/adaptive/strategies/flat-profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Oldest-first folding strategy.
3
+ *
4
+ * Always raise the chronologically-oldest raisable chunk's group, regardless
5
+ * of level distribution. This is the "memory fades chronologically" policy
6
+ * — the simplest possible monotonic strategy and the one originally proposed
7
+ * in rev 1 of the design doc.
8
+ *
9
+ * Kept for comparison against FlatProfileStrategy and as a fallback during
10
+ * early rollout.
11
+ *
12
+ * See `docs/adaptive-resolution-design.md` §3.5.
13
+ */
14
+ import type { FoldingStrategy, FoldingState, FoldingBudget, FoldOp } from '../folding-strategy.js';
15
+ export declare class OldestFirstStrategy implements FoldingStrategy {
16
+ readonly name = "oldest-first";
17
+ selectNextFold(state: FoldingState, budget: FoldingBudget): FoldOp | null;
18
+ }
19
+ //# sourceMappingURL=oldest-first.d.ts.map