@loreai/core 0.11.0 → 0.12.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.
@@ -1 +1 @@
1
- {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/recall.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAczC,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mFAAmF;IACnF,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CACrC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AA+JlC,wFAAwF;AACxF,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAqNzE;AAED,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,wiBAC8f,CAAC;AAEniB,mEAAmE;AACnE,eAAO,MAAM,yBAAyB;;;CAIrC,CAAC"}
1
+ {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/recall.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAczC,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mFAAmF;IACnF,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CACrC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AA+JlC,wFAAwF;AACxF,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAuOzE;AAED,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,wiBAC8f,CAAC;AAEniB,mEAAmE;AACnE,eAAO,MAAM,yBAAyB;;;CAIrC,CAAC"}
@@ -68,6 +68,21 @@ export declare function searchScored(input: {
68
68
  sessionID?: string;
69
69
  limit?: number;
70
70
  }): ScoredTemporalMessage[];
71
+ /**
72
+ * Normalized variance of relative-existence weights over message timestamps.
73
+ *
74
+ * Measures temporal attention imbalance: 0 means timestamps are evenly
75
+ * distributed (uniform attention), 1 means a single distant timestamp
76
+ * dominates (attention stuck in the past). Useful as a lightweight
77
+ * signal for distillation segmentation, recall time-biasing, and
78
+ * idle-resume awareness.
79
+ *
80
+ * Only meaningful for n ≥ 2. Returns 0 for 0 or 1 timestamps.
81
+ *
82
+ * Based on the "Temporal Clustering via Relative Existence" heuristic
83
+ * from D7x7z49/llm-context-idea.
84
+ */
85
+ export declare function temporalCnorm(timestamps: number[], now?: number): number;
71
86
  export declare function count(projectPath: string, sessionID?: string): number;
72
87
  export declare function undistilledCount(projectPath: string, sessionID?: string): number;
73
88
  export type PruneResult = {
@@ -1 +1 @@
1
- {"version":3,"file":"temporal.d.ts","sourceRoot":"","sources":["../../src/temporal.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQrD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,WAAS,CAAC;AAEvC;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAarD;AAiBD,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,QAqCA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,eAAe,EAAE,CASnB;AAED,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,eAAe,EAAE,CAOnB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAQ1C;AA2BD,wBAAgB,MAAM,CAAC,KAAK,EAAE;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,eAAe,EAAE,CA0CpB;AAED,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,qBAAqB,EAAE,CAgC1B;AAED,wBAAgB,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAWrE;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAWR;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,WAAW,CA0Ed"}
1
+ {"version":3,"file":"temporal.d.ts","sourceRoot":"","sources":["../../src/temporal.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQrD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,WAAS,CAAC;AAEvC;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAarD;AAiBD,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,QAqCA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,eAAe,EAAE,CASnB;AAED,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,eAAe,EAAE,CAOnB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAQ1C;AA2BD,wBAAgB,MAAM,CAAC,KAAK,EAAE;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,eAAe,EAAE,CA0CpB;AAED,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,qBAAqB,EAAE,CAgC1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAAE,EACpB,GAAG,GAAE,MAAmB,GACvB,MAAM,CAoBR;AAED,wBAAgB,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAWrE;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAWR;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,WAAW,CA0Ed"}
@@ -1 +1 @@
1
- {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAyVtC,wBAAgB,EAAE,IAAI,QAAQ,CA4B7B;AAqCD,wBAAgB,KAAK,SAKpB;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAYjE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK1D;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKrD;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAKpC;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAYxE"}
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAyVtC,wBAAgB,EAAE,IAAI,QAAQ,CAkC7B;AAmGD,wBAAgB,KAAK,SAKpB;AAGD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAYjE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAK1D;AAED,2DAA2D;AAC3D,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAKrD;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,OAAO,CAKpC;AAMD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAYxE"}
@@ -3,6 +3,32 @@ import { workerSessionIDs } from "./worker";
3
3
  import type { LLMClient } from "./types";
4
4
  export { workerSessionIDs };
5
5
  type TemporalMessage = temporal.TemporalMessage;
6
+ /**
7
+ * Compression health ratio: k / √N.
8
+ *
9
+ * k = distilled token count, N = source token count.
10
+ * Values < 1.0 signal likely lossy compression (below the square-root
11
+ * boundary). Values > 1.0 signal relatively faithful compression.
12
+ *
13
+ * Based on the "LLM Context Square Root Theory" heuristic from
14
+ * D7x7z49/llm-context-idea. The specific threshold is unvalidated —
15
+ * use as a diagnostic signal, not a hard gate.
16
+ */
17
+ export declare function compressionRatio(distilledTokens: number, sourceTokens: number): number;
18
+ /**
19
+ * Segment detection: group related messages into distillation-sized chunks.
20
+ *
21
+ * When the message count exceeds `maxSegment`, prefers splitting at the
22
+ * largest inter-message time gap (if it's ≥ 3× the median gap) to respect
23
+ * natural conversation boundaries. Falls back to count-based splitting at
24
+ * `maxSegment` when timestamps are uniform.
25
+ *
26
+ * Trailing segments with < 3 messages are merged into the previous segment
27
+ * to avoid tiny distillation inputs with too little context.
28
+ *
29
+ * Exported for testing; `run()` is the production caller.
30
+ */
31
+ export declare function detectSegments(messages: TemporalMessage[], maxSegment: number): TemporalMessage[][];
6
32
  /**
7
33
  * Truncate tool outputs within a `TemporalMessage.content` string (produced
8
34
  * by `temporal.partsToText`). Plain text and `[reasoning]` chunks pass
@@ -1 +1 @@
1
- {"version":3,"file":"distillation.d.ts","sourceRoot":"","sources":["../../src/distillation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AAWvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGzC,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAE5B,KAAK,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC;AAmDhD;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,MAAM,CAwBR;AAgBD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,eAAe,EAAE,EAC3B,kBAAkB,CAAC,EAAE,MAAM,GAC1B,MAAM,CAUR;AAED,KAAK,kBAAkB,GAAG;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAwBF;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAEpB;AAwBD,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAQpD;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,eAAe,UAAQ,GACtB,YAAY,EAAE,CAqBhB;AA0ID,wBAAsB,GAAG,CAAC,KAAK,EAAE;IAC/B,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA4DjD;AAsDD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE;IACvC,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA+ErC"}
1
+ {"version":3,"file":"distillation.d.ts","sourceRoot":"","sources":["../../src/distillation.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,QAAQ,MAAM,YAAY,CAAC;AAWvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAGzC,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAE5B,KAAK,eAAe,GAAG,QAAQ,CAAC,eAAe,CAAC;AAEhD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAC9B,eAAe,EAAE,MAAM,EACvB,YAAY,EAAE,MAAM,GACnB,MAAM,CAGR;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,eAAe,EAAE,EAC3B,UAAU,EAAE,MAAM,GACjB,eAAe,EAAE,EAAE,CAGrB;AAwGD;;;;;;;;;;;;GAYG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,MAAM,CAwBR;AAgBD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,eAAe,EAAE,EAC3B,kBAAkB,CAAC,EAAE,MAAM,GAC1B,MAAM,CAUR;AAED,KAAK,kBAAkB,GAAG;IACxB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAwBF;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,MAAM,GAAG,SAAS,CAEpB;AAwBD,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAQpD;AAED,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,eAAe,UAAQ,GACtB,YAAY,EAAE,CAqBhB;AA0ID,wBAAsB,GAAG,CAAC,KAAK,EAAE;IAC/B,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CA4DjD;AAmED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE;IACvC,GAAG,EAAE,SAAS,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CACjD,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA+ErC"}
@@ -1 +1 @@
1
- {"version":3,"file":"gradient.d.ts","sourceRoot":"","sources":["../../src/gradient.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"gradient.d.ts","sourceRoot":"","sources":["../../src/gradient.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/recall.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAczC,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mFAAmF;IACnF,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CACrC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AA+JlC,wFAAwF;AACxF,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAqNzE;AAED,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,wiBAC8f,CAAC;AAEniB,mEAAmE;AACnE,eAAO,MAAM,yBAAyB;;;CAIrC,CAAC"}
1
+ {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/recall.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAczC,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mFAAmF;IACnF,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CACrC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AA+JlC,wFAAwF;AACxF,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAuOzE;AAED,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,wiBAC8f,CAAC;AAEniB,mEAAmE;AACnE,eAAO,MAAM,yBAAyB;;;CAIrC,CAAC"}
@@ -68,6 +68,21 @@ export declare function searchScored(input: {
68
68
  sessionID?: string;
69
69
  limit?: number;
70
70
  }): ScoredTemporalMessage[];
71
+ /**
72
+ * Normalized variance of relative-existence weights over message timestamps.
73
+ *
74
+ * Measures temporal attention imbalance: 0 means timestamps are evenly
75
+ * distributed (uniform attention), 1 means a single distant timestamp
76
+ * dominates (attention stuck in the past). Useful as a lightweight
77
+ * signal for distillation segmentation, recall time-biasing, and
78
+ * idle-resume awareness.
79
+ *
80
+ * Only meaningful for n ≥ 2. Returns 0 for 0 or 1 timestamps.
81
+ *
82
+ * Based on the "Temporal Clustering via Relative Existence" heuristic
83
+ * from D7x7z49/llm-context-idea.
84
+ */
85
+ export declare function temporalCnorm(timestamps: number[], now?: number): number;
71
86
  export declare function count(projectPath: string, sessionID?: string): number;
72
87
  export declare function undistilledCount(projectPath: string, sessionID?: string): number;
73
88
  export type PruneResult = {
@@ -1 +1 @@
1
- {"version":3,"file":"temporal.d.ts","sourceRoot":"","sources":["../../src/temporal.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQrD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,WAAS,CAAC;AAEvC;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAarD;AAiBD,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,QAqCA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,eAAe,EAAE,CASnB;AAED,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,eAAe,EAAE,CAOnB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAQ1C;AA2BD,wBAAgB,MAAM,CAAC,KAAK,EAAE;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,eAAe,EAAE,CA0CpB;AAED,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,qBAAqB,EAAE,CAgC1B;AAED,wBAAgB,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAWrE;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAWR;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,WAAW,CA0Ed"}
1
+ {"version":3,"file":"temporal.d.ts","sourceRoot":"","sources":["../../src/temporal.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAQrD;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,WAAS,CAAC;AAEvC;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAarD;AAiBD,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,QAqCA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,WAAW,CACzB,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,eAAe,EAAE,CASnB;AAED,wBAAgB,SAAS,CACvB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,eAAe,EAAE,CAOnB;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,QAQ1C;AA2BD,wBAAgB,MAAM,CAAC,KAAK,EAAE;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,eAAe,EAAE,CA0CpB;AAED,MAAM,MAAM,qBAAqB,GAAG,eAAe,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvE;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,qBAAqB,EAAE,CAgC1B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAAE,EACpB,GAAG,GAAE,MAAmB,GACvB,MAAM,CAoBR;AAED,wBAAgB,KAAK,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAWrE;AAED,wBAAgB,gBAAgB,CAC9B,WAAW,EAAE,MAAM,EACnB,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAWR;AAED,MAAM,MAAM,WAAW,GAAG;IACxB,kFAAkF;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,WAAW,CA0Ed"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loreai/core",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Shared memory engine for Lore — three-tier storage, distillation, gradient context management",
package/src/db.ts CHANGED
@@ -359,17 +359,23 @@ export function db(): Database {
359
359
  // exist, so no special option is needed. (bun:sqlite's `{ create: true }`
360
360
  // exists only to opt INTO creation when you want readonly=false — which is
361
361
  // already the default for our case.)
362
- instance = new Database(path);
363
- instance.exec("PRAGMA journal_mode = WAL");
364
- instance.exec("PRAGMA foreign_keys = ON");
362
+ //
363
+ // IMPORTANT: Do NOT assign to `instance` until migrate() succeeds. If
364
+ // migrate() throws (SQLITE_BUSY, partial prior run, disk error), the
365
+ // module-level singleton must remain undefined so the next db() call
366
+ // retries initialization instead of returning an un-migrated handle.
367
+ const database = new Database(path);
368
+ database.exec("PRAGMA journal_mode = WAL");
369
+ database.exec("PRAGMA foreign_keys = ON");
365
370
  // Retry for up to 5s when another connection holds the write lock (e.g.
366
371
  // backgroundDistill's BEGIN IMMEDIATE overlapping with a recall query).
367
372
  // Default is 0ms which throws SQLITE_BUSY immediately.
368
- instance.exec("PRAGMA busy_timeout = 5000");
373
+ database.exec("PRAGMA busy_timeout = 5000");
369
374
  // Return freed pages to the OS incrementally on each transaction commit
370
375
  // instead of accumulating a free-page list that bloats the file.
371
- instance.exec("PRAGMA auto_vacuum = INCREMENTAL");
372
- migrate(instance);
376
+ database.exec("PRAGMA auto_vacuum = INCREMENTAL");
377
+ migrate(database);
378
+ instance = database;
373
379
  return instance;
374
380
  }
375
381
 
@@ -390,7 +396,13 @@ function migrate(database: Database) {
390
396
  }
391
397
  )?.version ?? 0)
392
398
  : 0;
393
- if (current >= MIGRATIONS.length) return;
399
+ if (current >= MIGRATIONS.length) {
400
+ // Schema is at the expected version but a prior partial run may have left
401
+ // holes (e.g. ALTER TABLE succeeded but CREATE TABLE in the same migration
402
+ // string was skipped). Run idempotent recovery for known fragile objects.
403
+ recoverMissingObjects(database);
404
+ return;
405
+ }
394
406
  for (let i = current; i < MIGRATIONS.length; i++) {
395
407
  if (i === VACUUM_MIGRATION_INDEX) {
396
408
  // VACUUM cannot run inside a transaction. Run it directly.
@@ -400,12 +412,68 @@ function migrate(database: Database) {
400
412
  database.exec("PRAGMA auto_vacuum = INCREMENTAL");
401
413
  database.exec("VACUUM");
402
414
  } else {
403
- database.exec(MIGRATIONS[i]);
415
+ try {
416
+ database.exec(MIGRATIONS[i]);
417
+ } catch (e: unknown) {
418
+ // Multi-statement migrations can partially fail when an early
419
+ // statement (e.g. ALTER TABLE ADD COLUMN) hits a duplicate-column
420
+ // error from a prior partial run. Swallow duplicate-column errors
421
+ // so the rest of the migration loop and the version bump proceed.
422
+ // Any genuinely new error is re-thrown.
423
+ if (
424
+ e instanceof Error &&
425
+ /duplicate column name/i.test(e.message)
426
+ ) {
427
+ // The ALTER TABLE already applied — run remaining statements in
428
+ // this migration by stripping the offending ALTER and re-exec'ing.
429
+ // (Important: migrate() in db.ts runs each migration via database.exec()
430
+ // which stops at the first error in a multi-statement string.)
431
+ const stripped = stripAppliedAlters(MIGRATIONS[i], database);
432
+ if (stripped.trim()) database.exec(stripped);
433
+ } else {
434
+ throw e;
435
+ }
436
+ }
404
437
  }
405
438
  }
406
439
  // Update version to latest. Migration 0 inserts version=1 via its own INSERT,
407
440
  // but subsequent migrations don't update it, so always normalize to MIGRATIONS.length.
408
441
  database.exec(`UPDATE schema_version SET version = ${MIGRATIONS.length}`);
442
+
443
+ // Also run recovery for existing DBs that are already at the latest version
444
+ // but have holes from past partial runs.
445
+ recoverMissingObjects(database);
446
+ }
447
+
448
+ /**
449
+ * Strip ALTER TABLE ADD COLUMN statements for columns that already exist.
450
+ * Returns the migration string with those statements removed.
451
+ */
452
+ function stripAppliedAlters(migration: string, database: Database): string {
453
+ return migration.replace(
454
+ /ALTER\s+TABLE\s+(\w+)\s+ADD\s+COLUMN\s+(\w+)\b[^;]*;/gi,
455
+ (match, table, column) => {
456
+ const cols = database
457
+ .query(`PRAGMA table_info(${table})`)
458
+ .all() as Array<{ name: string }>;
459
+ if (cols.some((c) => c.name === column)) return ""; // already exists
460
+ return match; // keep — this ALTER hasn't been applied
461
+ },
462
+ );
463
+ }
464
+
465
+ /**
466
+ * Idempotent recovery for objects that may be missing due to multi-statement
467
+ * migration partial failures (e.g. ALTER TABLE throws duplicate-column,
468
+ * aborting the exec before a subsequent CREATE TABLE in the same string).
469
+ */
470
+ function recoverMissingObjects(database: Database) {
471
+ database.exec(`
472
+ CREATE TABLE IF NOT EXISTS kv_meta (
473
+ key TEXT PRIMARY KEY,
474
+ value TEXT NOT NULL
475
+ );
476
+ `);
409
477
  }
410
478
 
411
479
  export function close() {
@@ -19,32 +19,125 @@ export { workerSessionIDs };
19
19
 
20
20
  type TemporalMessage = temporal.TemporalMessage;
21
21
 
22
- // Segment detection: group related messages together
23
- function detectSegments(
22
+ /**
23
+ * Compression health ratio: k / √N.
24
+ *
25
+ * k = distilled token count, N = source token count.
26
+ * Values < 1.0 signal likely lossy compression (below the square-root
27
+ * boundary). Values > 1.0 signal relatively faithful compression.
28
+ *
29
+ * Based on the "LLM Context Square Root Theory" heuristic from
30
+ * D7x7z49/llm-context-idea. The specific threshold is unvalidated —
31
+ * use as a diagnostic signal, not a hard gate.
32
+ */
33
+ export function compressionRatio(
34
+ distilledTokens: number,
35
+ sourceTokens: number,
36
+ ): number {
37
+ if (sourceTokens <= 0) return 0;
38
+ return distilledTokens / Math.sqrt(sourceTokens);
39
+ }
40
+
41
+ /**
42
+ * Segment detection: group related messages into distillation-sized chunks.
43
+ *
44
+ * When the message count exceeds `maxSegment`, prefers splitting at the
45
+ * largest inter-message time gap (if it's ≥ 3× the median gap) to respect
46
+ * natural conversation boundaries. Falls back to count-based splitting at
47
+ * `maxSegment` when timestamps are uniform.
48
+ *
49
+ * Trailing segments with < 3 messages are merged into the previous segment
50
+ * to avoid tiny distillation inputs with too little context.
51
+ *
52
+ * Exported for testing; `run()` is the production caller.
53
+ */
54
+ export function detectSegments(
24
55
  messages: TemporalMessage[],
25
56
  maxSegment: number,
26
57
  ): TemporalMessage[][] {
27
58
  if (messages.length <= maxSegment) return [messages];
28
- const segments: TemporalMessage[][] = [];
29
- let current: TemporalMessage[] = [];
30
-
31
- for (const msg of messages) {
32
- current.push(msg);
33
- // Split on segment size limit
34
- if (current.length >= maxSegment) {
35
- segments.push(current);
36
- current = [];
37
- }
59
+ return splitSegments(messages, maxSegment);
60
+ }
61
+
62
+ /** Minimum segment size segments smaller than this get merged. */
63
+ const MIN_SEGMENT = 3;
64
+
65
+ /**
66
+ * Multiplier for the median gap threshold: a time gap must be at least
67
+ * this many times the median gap to be used as a split point.
68
+ */
69
+ const GAP_THRESHOLD_MULTIPLIER = 3;
70
+
71
+ function splitSegments(
72
+ messages: TemporalMessage[],
73
+ maxSegment: number,
74
+ ): TemporalMessage[][] {
75
+ if (messages.length <= maxSegment) return [messages];
76
+
77
+ // Find the split point: prefer the largest time gap if it's significant
78
+ const splitIdx = findSplitIndex(messages, maxSegment);
79
+
80
+ const left = messages.slice(0, splitIdx);
81
+ const right = messages.slice(splitIdx);
82
+
83
+ // Recurse on both halves
84
+ const result = splitSegments(left, maxSegment);
85
+
86
+ if (right.length < MIN_SEGMENT) {
87
+ // Merge tiny trailing segment into the last segment
88
+ result[result.length - 1].push(...right);
89
+ } else {
90
+ result.push(...splitSegments(right, maxSegment));
91
+ }
92
+
93
+ return result;
94
+ }
95
+
96
+ /**
97
+ * Choose where to split an oversized message array.
98
+ *
99
+ * If there's a time gap ≥ 3× the median gap AND it falls within a range
100
+ * that would produce segments of at least MIN_SEGMENT size, use it.
101
+ * Otherwise fall back to the count-based boundary at `maxSegment`.
102
+ */
103
+ function findSplitIndex(
104
+ messages: TemporalMessage[],
105
+ maxSegment: number,
106
+ ): number {
107
+ // Compute consecutive time gaps
108
+ const gaps: Array<{ index: number; gap: number }> = [];
109
+ for (let i = 1; i < messages.length; i++) {
110
+ gaps.push({
111
+ index: i,
112
+ gap: messages[i].created_at - messages[i - 1].created_at,
113
+ });
38
114
  }
39
- if (current.length > 0) {
40
- // Merge small trailing segment with previous if too small
41
- if (current.length < 3 && segments.length > 0) {
42
- segments[segments.length - 1].push(...current);
43
- } else {
44
- segments.push(current);
115
+
116
+ if (gaps.length === 0) return maxSegment;
117
+
118
+ // Find median gap
119
+ const sortedGaps = gaps.map((g) => g.gap).sort((a, b) => a - b);
120
+ const medianGap = sortedGaps[Math.floor(sortedGaps.length / 2)];
121
+
122
+ // Find the largest gap that would produce viable segments (≥ MIN_SEGMENT on each side)
123
+ let bestGap = { index: -1, gap: 0 };
124
+ for (const g of gaps) {
125
+ if (
126
+ g.gap > bestGap.gap &&
127
+ g.index >= MIN_SEGMENT &&
128
+ messages.length - g.index >= MIN_SEGMENT
129
+ ) {
130
+ bestGap = g;
45
131
  }
46
132
  }
47
- return segments;
133
+
134
+ // Use the time gap if it's significantly larger than median
135
+ if (bestGap.index > 0 && bestGap.gap >= medianGap * GAP_THRESHOLD_MULTIPLIER) {
136
+ return bestGap.index;
137
+ }
138
+
139
+ // Fall back to count-based splitting
140
+ return maxSegment;
48
141
  }
49
142
 
50
143
  function formatTime(ms: number): string {
@@ -527,6 +620,19 @@ async function distillSegment(input: {
527
620
  });
528
621
  temporal.markDistilled(input.messages.map((m) => m.id));
529
622
 
623
+ // Diagnostic: log compression health and temporal clustering metrics.
624
+ // R_compression (k/√N): < 1.0 signals likely lossy distillation.
625
+ // C_norm: 0 = uniform timestamps, 1 = dominated by distant past.
626
+ const distilledTokens = Math.ceil(result.observations.length / 3);
627
+ const sourceTokens = input.messages.reduce((sum, m) => sum + m.tokens, 0);
628
+ const rComp = compressionRatio(distilledTokens, sourceTokens);
629
+ const cNorm = temporal.temporalCnorm(input.messages.map((m) => m.created_at));
630
+ log.info(
631
+ `distill segment: ${input.messages.length} msgs, ` +
632
+ `${sourceTokens}→${distilledTokens} tokens, ` +
633
+ `R=${rComp.toFixed(2)}, C_norm=${cNorm.toFixed(3)}`,
634
+ );
635
+
530
636
  // Fire-and-forget: embed the distillation for vector search
531
637
  if (embedding.isAvailable()) {
532
638
  embedding.embedDistillation(distillId, result.observations);
package/src/gradient.ts CHANGED
@@ -1322,6 +1322,7 @@ function transformInner(input: {
1322
1322
  const turnStart = currentTurnStart(input.messages);
1323
1323
  const dedupMessages = deduplicateToolOutputs(input.messages, turnStart);
1324
1324
 
1325
+
1325
1326
  const distillations = sid ? loadDistillations(input.projectPath, sid) : [];
1326
1327
 
1327
1328
  // Layer 1 uses the append-only cached prefix (Approach C) to keep the
@@ -1545,21 +1546,54 @@ export function estimateMessages(messages: MessageWithParts[]): number {
1545
1546
  return messages.reduce((sum, m) => sum + estimateMessage(m), 0);
1546
1547
  }
1547
1548
 
1548
- // Identify the current agentic turn: the last user message plus all subsequent
1549
- // assistant messages that share its ID as parentID. These messages form an atomic
1550
- // unit the model must see all of them or it will lose track of its own prior
1551
- // tool calls and re-issue them in an infinite loop.
1549
+ // Identify the current agentic turn: walk backwards from the end to find the
1550
+ // boundary where it's safe to strip tool outputs. The "current turn" includes:
1551
+ // 1. All messages from the last user message onwards (the explicit turn boundary)
1552
+ // 2. All messages that are part of an unfinished tool-call chain BEFORE that user
1553
+ // message — because subagent/child user messages can appear mid-chain, and the
1554
+ // parent's tool-call chain must be kept intact or the model re-issues tool calls.
1555
+ //
1556
+ // The heuristic: walk backwards from the last user message, and if we see assistant
1557
+ // messages with tool parts (tool-call chains), keep extending the boundary back.
1558
+ // Stop when we hit a user message that's followed by a non-tool assistant (a clean
1559
+ // conversational boundary, not a mid-chain subagent injection).
1552
1560
  function currentTurnStart(messages: MessageWithParts[]): number {
1553
- // Find the last user message
1554
- let lastUserIdx = -1;
1561
+ if (messages.length === 0) return 0;
1562
+
1563
+ // Start from the last user message
1564
+ let boundary = messages.length;
1555
1565
  for (let i = messages.length - 1; i >= 0; i--) {
1556
1566
  if (messages[i].info.role === "user") {
1557
- lastUserIdx = i;
1567
+ boundary = i;
1558
1568
  break;
1559
1569
  }
1560
1570
  }
1561
- if (lastUserIdx === -1) return 0; // no user message — treat all as current turn
1562
- return lastUserIdx;
1571
+ if (boundary === messages.length) return 0; // no user message — protect all
1572
+
1573
+ // Now walk backwards past any tool-call chains that precede this user message.
1574
+ // A tool-call chain looks like: ...assistant(tool-calls) → user(subagent) → ...
1575
+ // We keep extending boundary back while we see tool-bearing assistant messages.
1576
+ for (let i = boundary - 1; i >= 0; i--) {
1577
+ const msg = messages[i];
1578
+ const hasToolParts = msg.parts.some(isToolPart);
1579
+ if (hasToolParts) {
1580
+ // This assistant message has tools — it's part of an active chain.
1581
+ // Extend the boundary to include it.
1582
+ boundary = i;
1583
+ continue;
1584
+ }
1585
+ if (msg.info.role === "user") {
1586
+ // A user message with no tool-bearing assistant before it — this might be
1587
+ // another subagent injection. Keep walking back.
1588
+ boundary = i;
1589
+ continue;
1590
+ }
1591
+ // Non-tool assistant message (pure text response) — this is a clean boundary.
1592
+ // The chain above this point is a completed conversation turn.
1593
+ break;
1594
+ }
1595
+
1596
+ return boundary;
1563
1597
  }
1564
1598
 
1565
1599
  function tryFit(input: {
package/src/recall.ts CHANGED
@@ -322,6 +322,24 @@ export async function runRecall(input: RecallInput): Promise<RecallResult> {
322
322
  key: (r) => `t:${r.item.id}`,
323
323
  },
324
324
  );
325
+
326
+ // Recency-biased list for temporal results: same candidates re-ranked
327
+ // by created_at (newest first). RRF naturally boosts messages that
328
+ // appear in both the BM25 and recency lists — i.e. results that are
329
+ // both semantically relevant AND recent. Uses the same `t:` key prefix
330
+ // so RRF merges rather than duplicates.
331
+ if (temporalResults.length > 0) {
332
+ const recencySorted = [...temporalResults].sort(
333
+ (a, b) => b.created_at - a.created_at,
334
+ );
335
+ allRrfLists.push({
336
+ items: recencySorted.map((item) => ({
337
+ source: "temporal" as const,
338
+ item,
339
+ })),
340
+ key: (r) => `t:${r.item.id}`,
341
+ });
342
+ }
325
343
  }
326
344
 
327
345
  // Vector search on the original query (not expansions — avoid redundant embeds).
package/src/temporal.ts CHANGED
@@ -280,6 +280,45 @@ export function searchScored(input: {
280
280
  }
281
281
  }
282
282
 
283
+ /**
284
+ * Normalized variance of relative-existence weights over message timestamps.
285
+ *
286
+ * Measures temporal attention imbalance: 0 means timestamps are evenly
287
+ * distributed (uniform attention), 1 means a single distant timestamp
288
+ * dominates (attention stuck in the past). Useful as a lightweight
289
+ * signal for distillation segmentation, recall time-biasing, and
290
+ * idle-resume awareness.
291
+ *
292
+ * Only meaningful for n ≥ 2. Returns 0 for 0 or 1 timestamps.
293
+ *
294
+ * Based on the "Temporal Clustering via Relative Existence" heuristic
295
+ * from D7x7z49/llm-context-idea.
296
+ */
297
+ export function temporalCnorm(
298
+ timestamps: number[],
299
+ now: number = Date.now(),
300
+ ): number {
301
+ const n = timestamps.length;
302
+ if (n < 2) return 0;
303
+
304
+ // Existence durations: how long each piece has existed
305
+ const durations = timestamps.map((t) => now - t);
306
+ const totalDuration = durations.reduce((a, b) => a + b, 0);
307
+ if (totalDuration <= 0) return 0;
308
+
309
+ // Relative existence weights (positive, sum to 1)
310
+ const weights = durations.map((d) => d / totalDuration);
311
+
312
+ // Normalized variance: Var(w) / Var_max
313
+ // Var(w) = (1/n) * Σ(w_i - 1/n)²
314
+ // Var_max = (n-1) / n² (when one weight = 1, rest = 0)
315
+ const uniform = 1 / n;
316
+ const variance =
317
+ weights.reduce((sum, w) => sum + (w - uniform) ** 2, 0) / n;
318
+ const maxVariance = (n - 1) / (n * n);
319
+ return maxVariance === 0 ? 0 : variance / maxVariance;
320
+ }
321
+
283
322
  export function count(projectPath: string, sessionID?: string): number {
284
323
  const pid = ensureProject(projectPath);
285
324
  const query = sessionID