@animalabs/context-manager 0.4.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 (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 +1479 -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 +94 -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 +1586 -38
  126. package/src/strategies/index.ts +1 -1
  127. package/src/types/message.ts +43 -0
  128. package/src/types/strategy.ts +109 -10
@@ -1,2 +1,2 @@
1
1
  export { PassthroughStrategy } from './passthrough.js';
2
- export { AutobiographicalStrategy } from './autobiographical.js';
2
+ export { AutobiographicalStrategy, type AutobiographicalProgressSnapshot } from './autobiographical.js';
@@ -47,6 +47,40 @@ export interface StoredMessage {
47
47
  timestamp: Date;
48
48
  /** IDs of messages that caused this one (from Chronicle causation) */
49
49
  causedBy?: MessageId[];
50
+
51
+ /**
52
+ * If this message is a shard of a larger logical message (chunked at
53
+ * ingestion because it exceeded `chunkThreshold`), this is the stable
54
+ * group id shared with sibling shards. Shards with the same id are
55
+ * concatenated into one API message at render time. Null/undefined
56
+ * for messages that fit in a single chunk. See
57
+ * `docs/adaptive-resolution-design.md` §3.6.
58
+ */
59
+ bodyGroupId?: string;
60
+
61
+ /**
62
+ * The shard's order within its bodyGroup, starting at 0. Only meaningful
63
+ * when `bodyGroupId` is set. Used to reassemble shards into byte-faithful
64
+ * order at render time.
65
+ */
66
+ shardIndex?: number;
67
+
68
+ /**
69
+ * Current display resolution for this chunk:
70
+ * - 0 = render raw content
71
+ * - k>0 = render the L_k summary that covers this chunk
72
+ *
73
+ * Set by the picker (or the agent in V2). Default 0. See
74
+ * `docs/adaptive-resolution-design.md` §3.3.
75
+ */
76
+ currentResolution?: number;
77
+
78
+ /**
79
+ * If true, the picker must not change `currentResolution` for this chunk.
80
+ * Set by `lockChunk()` (programmatic API) or, in V2, by the agent's
81
+ * `unfold` tool. Default false.
82
+ */
83
+ lockedByAgent?: boolean;
50
84
  }
51
85
 
52
86
  /**
@@ -85,6 +119,15 @@ export interface StoredMessageInternal {
85
119
  metadata?: MessageMetadata;
86
120
  timestamp: number; // Unix timestamp for storage
87
121
  causedBy?: MessageId[];
122
+
123
+ /** See StoredMessage.bodyGroupId */
124
+ bodyGroupId?: string;
125
+ /** See StoredMessage.shardIndex */
126
+ shardIndex?: number;
127
+ /** See StoredMessage.currentResolution */
128
+ currentResolution?: number;
129
+ /** See StoredMessage.lockedByAgent */
130
+ lockedByAgent?: boolean;
88
131
  }
89
132
 
90
133
  /**
@@ -1,5 +1,5 @@
1
1
  import type { JsStore } from '@animalabs/chronicle';
2
- import type { Membrane } from '@animalabs/membrane';
2
+ import type { Membrane, ContentBlock } from '@animalabs/membrane';
3
3
  import type { StoredMessage, MessageId, Sequence } from './message.js';
4
4
  import type { ContextEntry, TokenBudget, PendingWork } from './context.js';
5
5
 
@@ -125,6 +125,41 @@ export interface ContextStrategy {
125
125
  log: ContextLogView,
126
126
  budget: TokenBudget
127
127
  ): ContextEntry[];
128
+
129
+ /**
130
+ * Optional: at ingestion time, decide whether to split this incoming
131
+ * message into multiple shards (because it's too large to be a single
132
+ * fold unit). If returned, the framework stores each shard as a separate
133
+ * StoredMessage with the shared `bodyGroupId` and per-shard `shardIndex`,
134
+ * and the render path will reassemble them into one API message at
135
+ * compile time.
136
+ *
137
+ * Return null or undefined to skip chunking (message stored as one record).
138
+ *
139
+ * See `docs/adaptive-resolution-design.md` §3.6.
140
+ */
141
+ chunkIngressMessage?(
142
+ participant: string,
143
+ content: ContentBlock[]
144
+ ): IngressChunkResult | null;
145
+ }
146
+
147
+ /**
148
+ * Result of a strategy's ingestion-time chunking decision.
149
+ */
150
+ export interface IngressChunkResult {
151
+ /** Stable id shared by all shards of this message. */
152
+ bodyGroupId: string;
153
+ /**
154
+ * The shards in source order. Each becomes a separate StoredMessage.
155
+ * Concatenating the shards' text content must reproduce the original
156
+ * message body byte-for-byte.
157
+ */
158
+ shards: Array<{
159
+ content: ContentBlock[];
160
+ /** Order within the bodyGroup, starting at 0. */
161
+ shardIndex: number;
162
+ }>;
128
163
  }
129
164
 
130
165
  /**
@@ -379,35 +414,91 @@ export interface AutobiographicalConfig {
379
414
  * that overflow is rare, and when it does happen you want to know.
380
415
  */
381
416
  enforceBudget?: boolean;
417
+
418
+ // --- Adaptive resolution (per docs/adaptive-resolution-design.md) ---
419
+
420
+ /**
421
+ * Enable picker-driven adaptive resolution. When true, `select()` uses
422
+ * the FoldingStrategy + Picker to choose per-message resolution under
423
+ * token-budget pressure rather than the threshold-driven `checkMergeThreshold`
424
+ * path. Default: false (existing hierarchical behavior preserved).
425
+ */
426
+ adaptiveResolution?: boolean;
427
+
428
+ /**
429
+ * Folding strategy name when adaptiveResolution is on. One of:
430
+ * 'flat-profile' (default) — level-equalizing
431
+ * 'oldest-first' — chronological
432
+ * Custom strategies can be plugged in by the host application.
433
+ */
434
+ foldingStrategy?: 'flat-profile' | 'oldest-first';
435
+
436
+ /**
437
+ * Slack ratio (hysteresis) for the picker. The picker folds until total
438
+ * tokens ≤ budget * (1 - slack), and stays quiet while between slack
439
+ * and budget. Default 0.1.
440
+ */
441
+ compressionSlackRatio?: number;
442
+
443
+ /**
444
+ * Enable bottom-up speculative pre-production of higher-level summaries.
445
+ * When a new L_k summary is produced, if N siblings exist that would share
446
+ * an L_{k+1} parent, the L_{k+1} is enqueued for production immediately
447
+ * (no picker request needed). Default true when adaptiveResolution is on.
448
+ */
449
+ speculativeProduction?: boolean;
382
450
  }
383
451
 
384
452
  /**
385
453
  * Compression level in the hierarchical pyramid.
454
+ *
455
+ * Historically constrained to 1 | 2 | 3. As of the adaptive-resolution design
456
+ * (`docs/adaptive-resolution-design.md`), levels are unbounded: the picker
457
+ * can recursively produce L4, L5, ... as needed. The narrower literal type
458
+ * is kept as `LegacySummaryLevel` for code that still assumes the old shape.
386
459
  */
387
- export type SummaryLevel = 1 | 2 | 3;
460
+ export type SummaryLevel = number;
461
+
462
+ /**
463
+ * The narrow level type used by pre-adaptive-resolution code paths.
464
+ * Prefer `SummaryLevel` for new code.
465
+ */
466
+ export type LegacySummaryLevel = 1 | 2 | 3;
388
467
 
389
468
  /**
390
469
  * A summary entry in the hierarchical memory pyramid.
391
470
  * L1: compressed from raw message chunks.
392
- * L2: merged from mergeThreshold L1s.
393
- * L3: merged from mergeThreshold L2s.
471
+ * L_{k>1}: merged from mergeThreshold L_{k-1}s.
394
472
  */
395
473
  export interface SummaryEntry {
396
474
  /** Unique ID (e.g., "L1-0", "L2-3") */
397
475
  id: string;
398
- /** Compression level */
476
+ /** Compression level (1, 2, 3, ... — unbounded in the adaptive-resolution design) */
399
477
  level: SummaryLevel;
400
478
  /** The summary text */
401
479
  content: string;
402
- /** Estimated token count (content.length / 4) */
480
+ /** Estimated token count (content.length / 4 or tokenizer-cached) */
403
481
  tokens: number;
404
- /** Level of the sources: 0 = raw messages, 1 = L1s, 2 = L2s */
405
- sourceLevel: 0 | 1 | 2;
406
- /** IDs of source items (message IDs for L1, summary IDs for L2/L3) */
482
+ /**
483
+ * Level of the sources: 0 = raw messages, k = L_k summaries.
484
+ * Pre-adaptive code uses 0 | 1 | 2; new code may produce higher values.
485
+ */
486
+ sourceLevel: number;
487
+ /** IDs of source items (message IDs for L1, summary IDs for L_{k>1}) */
407
488
  sourceIds: string[];
408
489
  /** Range of original message IDs covered */
409
490
  sourceRange: { first: string; last: string };
410
- /** If merged into a higher-level summary, that summary's ID */
491
+ /**
492
+ * The L_{level+1} summary this one is a source for, if produced.
493
+ * Pure archive metadata in the adaptive-resolution design — display
494
+ * decisions live on per-chunk `currentResolution`, not here.
495
+ */
496
+ parentId?: string;
497
+ /**
498
+ * @deprecated Renamed to `parentId` in the adaptive-resolution design.
499
+ * Kept for read compatibility with chronicles produced by the old
500
+ * threshold-driven path. New writes should set `parentId` only.
501
+ */
411
502
  mergedInto?: string;
412
503
  /** Creation timestamp */
413
504
  created: number;
@@ -415,6 +506,14 @@ export interface SummaryEntry {
415
506
  phaseType?: string;
416
507
  }
417
508
 
509
+ /**
510
+ * Helper: read the parent pointer from a summary, accepting either the
511
+ * new `parentId` field or the deprecated `mergedInto` alias.
512
+ */
513
+ export function getSummaryParentId(s: SummaryEntry): string | undefined {
514
+ return s.parentId ?? s.mergedInto;
515
+ }
516
+
418
517
  /**
419
518
  * A range of messages protected from compression. Pins keep a span of raw
420
519
  * messages visible at their original position in the rendered context.