@animalabs/context-manager 0.5.5 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/adaptive/kv-control.d.ts +69 -32
- package/dist/src/adaptive/kv-control.d.ts.map +1 -1
- package/dist/src/adaptive/kv-control.js +471 -172
- package/dist/src/adaptive/kv-control.js.map +1 -1
- package/dist/src/adaptive/picker.d.ts +8 -0
- package/dist/src/adaptive/picker.d.ts.map +1 -1
- package/dist/src/adaptive/picker.js.map +1 -1
- package/dist/src/adaptive/strategies/kv-stable.d.ts +12 -4
- package/dist/src/adaptive/strategies/kv-stable.d.ts.map +1 -1
- package/dist/src/adaptive/strategies/kv-stable.js +14 -5
- package/dist/src/adaptive/strategies/kv-stable.js.map +1 -1
- package/dist/src/context-log.d.ts.map +1 -1
- package/dist/src/context-log.js +11 -0
- package/dist/src/context-log.js.map +1 -1
- package/dist/src/context-manager.d.ts +28 -1
- package/dist/src/context-manager.d.ts.map +1 -1
- package/dist/src/context-manager.js +42 -0
- package/dist/src/context-manager.js.map +1 -1
- package/dist/src/index.d.ts +3 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/message-store.d.ts +60 -0
- package/dist/src/message-store.d.ts.map +1 -1
- package/dist/src/message-store.js +165 -10
- package/dist/src/message-store.js.map +1 -1
- package/dist/src/strategies/autobiographical.d.ts +207 -2
- package/dist/src/strategies/autobiographical.d.ts.map +1 -1
- package/dist/src/strategies/autobiographical.js +1283 -124
- package/dist/src/strategies/autobiographical.js.map +1 -1
- package/dist/src/strategies/index.d.ts +1 -1
- package/dist/src/strategies/index.d.ts.map +1 -1
- package/dist/src/strategies/index.js.map +1 -1
- package/dist/src/strategies/knowledge.d.ts +8 -0
- package/dist/src/strategies/knowledge.d.ts.map +1 -1
- package/dist/src/strategies/knowledge.js +23 -1
- package/dist/src/strategies/knowledge.js.map +1 -1
- package/dist/src/types/strategy.d.ts +82 -5
- package/dist/src/types/strategy.d.ts.map +1 -1
- package/dist/src/types/strategy.js.map +1 -1
- package/dist/test/adaptive/doc-plus-chat.test.js +7 -3
- package/dist/test/adaptive/doc-plus-chat.test.js.map +1 -1
- package/dist/test/adaptive/hard-fail.test.js +22 -0
- package/dist/test/adaptive/hard-fail.test.js.map +1 -1
- package/dist/test/adaptive/ingestion.test.js +3 -1
- package/dist/test/adaptive/ingestion.test.js.map +1 -1
- package/dist/test/adaptive/kv-control.test.js +17 -11
- package/dist/test/adaptive/kv-control.test.js.map +1 -1
- package/dist/test/adaptive/single-path-solve.test.d.ts +16 -0
- package/dist/test/adaptive/single-path-solve.test.d.ts.map +1 -0
- package/dist/test/adaptive/single-path-solve.test.js +204 -0
- package/dist/test/adaptive/single-path-solve.test.js.map +1 -0
- package/dist/test/anti-redundancy-budget.test.d.ts +17 -0
- package/dist/test/anti-redundancy-budget.test.d.ts.map +1 -0
- package/dist/test/anti-redundancy-budget.test.js +197 -0
- package/dist/test/anti-redundancy-budget.test.js.map +1 -0
- package/dist/test/chunk-persistence.test.d.ts +29 -0
- package/dist/test/chunk-persistence.test.d.ts.map +1 -0
- package/dist/test/chunk-persistence.test.js +290 -0
- package/dist/test/chunk-persistence.test.js.map +1 -0
- package/dist/test/compression-dedup.test.d.ts +20 -0
- package/dist/test/compression-dedup.test.d.ts.map +1 -0
- package/dist/test/compression-dedup.test.js +92 -0
- package/dist/test/compression-dedup.test.js.map +1 -0
- package/dist/test/compression-shape-invariants.test.js +40 -3
- package/dist/test/compression-shape-invariants.test.js.map +1 -1
- package/dist/test/head-window-order.test.d.ts +19 -0
- package/dist/test/head-window-order.test.d.ts.map +1 -0
- package/dist/test/head-window-order.test.js +159 -0
- package/dist/test/head-window-order.test.js.map +1 -0
- package/dist/test/image-strip-render-stats.test.js +25 -3
- package/dist/test/image-strip-render-stats.test.js.map +1 -1
- package/dist/test/knowledge-tool-boundary.test.d.ts +14 -0
- package/dist/test/knowledge-tool-boundary.test.d.ts.map +1 -0
- package/dist/test/knowledge-tool-boundary.test.js +93 -0
- package/dist/test/knowledge-tool-boundary.test.js.map +1 -0
- package/dist/test/l1-holdback.test.d.ts +15 -0
- package/dist/test/l1-holdback.test.d.ts.map +1 -0
- package/dist/test/l1-holdback.test.js +119 -0
- package/dist/test/l1-holdback.test.js.map +1 -0
- package/dist/test/merge-contiguity.test.d.ts +11 -0
- package/dist/test/merge-contiguity.test.d.ts.map +1 -0
- package/dist/test/merge-contiguity.test.js +74 -0
- package/dist/test/merge-contiguity.test.js.map +1 -0
- package/dist/test/message-store-window.test.d.ts +13 -0
- package/dist/test/message-store-window.test.d.ts.map +1 -0
- package/dist/test/message-store-window.test.js +177 -0
- package/dist/test/message-store-window.test.js.map +1 -0
- package/dist/test/speculation-cap.test.js +4 -0
- package/dist/test/speculation-cap.test.js.map +1 -1
- package/dist/test/summary-log-consistency.test.d.ts +18 -0
- package/dist/test/summary-log-consistency.test.d.ts.map +1 -0
- package/dist/test/summary-log-consistency.test.js +97 -0
- package/dist/test/summary-log-consistency.test.js.map +1 -0
- package/dist/test/tool-pairing-invariant.test.d.ts +15 -0
- package/dist/test/tool-pairing-invariant.test.d.ts.map +1 -0
- package/dist/test/tool-pairing-invariant.test.js +225 -0
- package/dist/test/tool-pairing-invariant.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -3
- package/src/adaptive/kv-control.ts +509 -184
- package/src/adaptive/picker.ts +8 -0
- package/src/adaptive/strategies/kv-stable.ts +22 -10
- package/src/context-log.ts +11 -0
- package/src/context-manager.ts +48 -2
- package/src/index.ts +3 -2
- package/src/message-store.ts +202 -9
- package/src/strategies/autobiographical.ts +1343 -148
- package/src/strategies/index.ts +1 -1
- package/src/strategies/knowledge.ts +25 -1
- package/src/types/strategy.ts +89 -5
package/src/strategies/index.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { PassthroughStrategy } from './passthrough.js';
|
|
2
|
-
export { AutobiographicalStrategy, type AutobiographicalProgressSnapshot } from './autobiographical.js';
|
|
2
|
+
export { AutobiographicalStrategy, type AutobiographicalProgressSnapshot, type Chunk } from './autobiographical.js';
|
|
@@ -41,6 +41,17 @@ export class KnowledgeStrategy extends AutobiographicalStrategy {
|
|
|
41
41
|
// Override: Semantic chunking
|
|
42
42
|
// ============================================================================
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* KnowledgeStrategy keeps the legacy recompute-every-rebuild chunker:
|
|
46
|
+
* its chunk boundaries are semantic (phase transitions), recomputed from
|
|
47
|
+
* message content, and its stores are offline mining artifacts — the
|
|
48
|
+
* restart-duplication failure mode that chunk persistence fixes does not
|
|
49
|
+
* apply, and persisted token-sum records would fight the phase chunker.
|
|
50
|
+
*/
|
|
51
|
+
protected get chunkPersistenceEnabled(): boolean {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
|
|
44
55
|
protected rebuildChunks(store: MessageStoreView): void {
|
|
45
56
|
const messagesToChunk = this.getCompressibleMessages(store);
|
|
46
57
|
|
|
@@ -81,7 +92,20 @@ export class KnowledgeStrategy extends AutobiographicalStrategy {
|
|
|
81
92
|
const phaseChanged = currentPhase !== null && phase !== currentPhase;
|
|
82
93
|
const maxTokens = this.getMaxChunkTokens(currentPhase ?? phase);
|
|
83
94
|
const sizeExceeded = currentTokens >= maxTokens;
|
|
84
|
-
|
|
95
|
+
// Same tool-pair boundary guard as the base chunker (rebuildChunks in
|
|
96
|
+
// AutobiographicalStrategy): never close a chunk whose LAST message
|
|
97
|
+
// contains a tool_use block — its matching tool_result lives in the
|
|
98
|
+
// immediately-following message (the one about to be pushed). Closing
|
|
99
|
+
// here would split the pair across chunks; when the earlier chunk
|
|
100
|
+
// compresses first, the raw orphan tool_result renders unpaired and
|
|
101
|
+
// the Anthropic API rejects the request. Deferring the close by one
|
|
102
|
+
// iteration pulls the tool_result into the same chunk. (Phase never
|
|
103
|
+
// changes between a tool_use and its tool_result — the result inherits
|
|
104
|
+
// lastToolPhase — so this defers sizeExceeded closes in practice.)
|
|
105
|
+
const shouldClose =
|
|
106
|
+
currentChunk.length >= 2 &&
|
|
107
|
+
(phaseChanged || sizeExceeded) &&
|
|
108
|
+
!this.lastMessageContainsToolUse(currentChunk);
|
|
85
109
|
|
|
86
110
|
if (shouldClose) {
|
|
87
111
|
const chunk = this.createChunk(
|
package/src/types/strategy.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { JsStore } from '@animalabs/chronicle';
|
|
2
|
-
import type { Membrane, ContentBlock } from '@animalabs/membrane';
|
|
2
|
+
import type { Membrane, ContentBlock, ToolDefinition } 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
|
|
|
@@ -19,6 +19,9 @@ export interface MessageStoreView {
|
|
|
19
19
|
length(): number;
|
|
20
20
|
/** Estimate tokens for a message */
|
|
21
21
|
estimateTokens(message: StoredMessage): number;
|
|
22
|
+
/** Closed-loop estimator calibration (optional — MessageStore provides it). */
|
|
23
|
+
setTokenCalibration?(factor: number): void;
|
|
24
|
+
getTokenCalibration?(): number;
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
/**
|
|
@@ -43,6 +46,16 @@ export interface ContextLogView {
|
|
|
43
46
|
export interface StrategyContext {
|
|
44
47
|
/** Read-only view of message store */
|
|
45
48
|
messageStore: MessageStoreView;
|
|
49
|
+
/**
|
|
50
|
+
* The agent's live tool definitions, as last supplied by the host (set on
|
|
51
|
+
* every activation via ContextManager.setToolDefinitions). Summarizer /
|
|
52
|
+
* compression requests MUST declare these: replaying a transcript full of
|
|
53
|
+
* tool_use/tool_result blocks with no `tools` param trips Anthropic's
|
|
54
|
+
* reasoning_extraction classifier (looks like a foreign agent trace being
|
|
55
|
+
* duplicated) and the whole compression pass gets deterministically
|
|
56
|
+
* refused. Optional because ticks can fire before the first activation.
|
|
57
|
+
*/
|
|
58
|
+
tools?: ToolDefinition[];
|
|
46
59
|
/** Read-only view of context log */
|
|
47
60
|
contextLog: ContextLogView;
|
|
48
61
|
/** Membrane instance for LLM calls (compression) */
|
|
@@ -329,6 +342,14 @@ export interface AutobiographicalConfig {
|
|
|
329
342
|
* this limit have their text/tool_result content truncated. 0 = no limit. */
|
|
330
343
|
maxMessageTokens: number;
|
|
331
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Fractional grace above the configured hard context budget before an
|
|
347
|
+
* exhausted adaptive picker rejects the compile. The solver still targets
|
|
348
|
+
* the original budget; this only absorbs coarse fold quanta and indivisible
|
|
349
|
+
* head/tail boundary overshoot. Default 0 (strict budget enforcement).
|
|
350
|
+
*/
|
|
351
|
+
overBudgetGraceRatio?: number;
|
|
352
|
+
|
|
332
353
|
// --- Live image policy ---
|
|
333
354
|
|
|
334
355
|
/** Maximum number of images kept "live" (sent as real image blocks) in the
|
|
@@ -342,6 +363,42 @@ export interface AutobiographicalConfig {
|
|
|
342
363
|
* Typically much shallower than recentWindowTokens. 0 = never strip by depth. */
|
|
343
364
|
imageStripDepthTokens?: number;
|
|
344
365
|
|
|
366
|
+
/**
|
|
367
|
+
* Merge grouping (2026-07-12 contiguity fix): break a merge run when the
|
|
368
|
+
* positional gap between consecutive unmerged candidates exceeds this many
|
|
369
|
+
* messages. Small holes (wiped/pruned nodes) bridge fine; cross-era gaps
|
|
370
|
+
* must not — a merge group spanning already-merged history can straddle
|
|
371
|
+
* the recent window and block its whole lineage from folding. Default 300.
|
|
372
|
+
*/
|
|
373
|
+
mergeContiguityGapLimit?: number;
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Byte wall for live images (2026-07-12): keep inline images newest-first
|
|
377
|
+
* only while their cumulative base64 size stays under this budget — on top
|
|
378
|
+
* of `maxLiveImages` / `imageStripDepthTokens`. Guarantees the compiled
|
|
379
|
+
* window fits the API's total request size cap (413 request_too_large), so
|
|
380
|
+
* membrane's oversize check is a true invariant, never a silent editor.
|
|
381
|
+
* Default 20MB (of base64; the API cap is 32MB total).
|
|
382
|
+
*/
|
|
383
|
+
maxLiveImageBytes?: number;
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Merge grouping: exclude candidates whose OWN source span exceeds this
|
|
387
|
+
* many messages (replay-era summaries can span the entire chronicle and
|
|
388
|
+
* would bridge any run they join). They stay on the frontier. Default 1500.
|
|
389
|
+
*/
|
|
390
|
+
mergeMaxSourceSpanMessages?: number;
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* L1 production holdback: keep the newest N closed chunks out of the
|
|
394
|
+
* speculative compression queue (default 1). The chunk at the live edge is
|
|
395
|
+
* the one most likely to still be in motion — summarize it only once a
|
|
396
|
+
* newer chunk has closed behind it. Speculative production of everything
|
|
397
|
+
* older proceeds ahead of need as usual. A picker `produce` op (real fold
|
|
398
|
+
* demand) bypasses the holdback. 0 = compress at close (old behavior).
|
|
399
|
+
*/
|
|
400
|
+
l1HoldbackChunks?: number;
|
|
401
|
+
|
|
345
402
|
// Legacy aliases (deprecated, use summary* instead)
|
|
346
403
|
/** @deprecated Use summarySystemPrompt */
|
|
347
404
|
diarySystemPrompt?: string;
|
|
@@ -387,6 +444,20 @@ export interface AutobiographicalConfig {
|
|
|
387
444
|
*/
|
|
388
445
|
compressionRecallBudgetTokens?: number;
|
|
389
446
|
|
|
447
|
+
/**
|
|
448
|
+
* Minimum substantive text (non-whitespace chars across a chunk's
|
|
449
|
+
* messages) below which L1 compression skips the LLM call and stores a
|
|
450
|
+
* mechanical stub summary instead (default: 200).
|
|
451
|
+
*
|
|
452
|
+
* A chunk of silent/skip turns and bare system traffic gives the
|
|
453
|
+
* summarizer nothing to remember; asked anyway, it confabulates —
|
|
454
|
+
* it reaches for the nearest salient content (head window, prior
|
|
455
|
+
* recall pairs) and narrates it as if it just happened (the
|
|
456
|
+
* "68 initiations" incident). Chunks containing any non-text blocks
|
|
457
|
+
* (tool cycles, images) are never stubbed. Set to 0 to disable.
|
|
458
|
+
*/
|
|
459
|
+
minChunkCharsForLLM?: number;
|
|
460
|
+
|
|
390
461
|
/**
|
|
391
462
|
* When true (default), each selected summary emits as its own positioned
|
|
392
463
|
* Q/A recall pair, sorted chronologically by source range. When false,
|
|
@@ -487,13 +558,26 @@ export interface AutobiographicalConfig {
|
|
|
487
558
|
foldingStrategy?: 'flat-profile' | 'oldest-first' | 'kv-stable';
|
|
488
559
|
|
|
489
560
|
/**
|
|
490
|
-
*
|
|
491
|
-
*
|
|
492
|
-
*
|
|
493
|
-
*
|
|
561
|
+
* Trust region P (tokens) for `foldingStrategy: 'kv-stable'` — bounds how
|
|
562
|
+
* much prefix re-read (exact kvCost) an ordinary turn may take; the solver
|
|
563
|
+
* adopts the relevance-ideal cut within it, amortizes bigger repairs across
|
|
564
|
+
* turns (suffix adoption), and exceeds it only with a recorded override
|
|
565
|
+
* (bootstrap / infeasible / quality-gap — logged as `[kv-escalation]`).
|
|
566
|
+
* See docs/adaptive-resolution-design.md §13. Default: the hard budget
|
|
567
|
+
* (a rendered layout never exceeds it, so the default never binds).
|
|
494
568
|
*/
|
|
495
569
|
kvStableReachTokens?: number;
|
|
496
570
|
|
|
571
|
+
/**
|
|
572
|
+
* Quality-gap override threshold for `foldingStrategy: 'kv-stable'`
|
|
573
|
+
* (design §13.4): a plan within the trust region is rejected — and the
|
|
574
|
+
* relevance-ideal cut adopted, paying the perturbation — when its
|
|
575
|
+
* salience-weighted misallocation loss exceeds the ideal's by more than
|
|
576
|
+
* this fraction of the ideal's. Also bounds how misallocated a dead-band
|
|
577
|
+
* hold may be before the solver self-heals. Default 0.35.
|
|
578
|
+
*/
|
|
579
|
+
kvStableQualityGapRatio?: number;
|
|
580
|
+
|
|
497
581
|
/**
|
|
498
582
|
* Slack ratio (hysteresis) for the picker. The picker folds until total
|
|
499
583
|
* tokens ≤ budget * (1 - slack), and stays quiet while between slack
|