@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.
- package/dist/bun/db.d.ts.map +1 -1
- package/dist/bun/distillation.d.ts +26 -0
- package/dist/bun/distillation.d.ts.map +1 -1
- package/dist/bun/gradient.d.ts.map +1 -1
- package/dist/bun/index.js +132 -27
- package/dist/bun/index.js.map +3 -3
- package/dist/bun/recall.d.ts.map +1 -1
- package/dist/bun/temporal.d.ts +15 -0
- package/dist/bun/temporal.d.ts.map +1 -1
- package/dist/node/db.d.ts.map +1 -1
- package/dist/node/distillation.d.ts +26 -0
- package/dist/node/distillation.d.ts.map +1 -1
- package/dist/node/gradient.d.ts.map +1 -1
- package/dist/node/index.js +132 -27
- package/dist/node/index.js.map +3 -3
- package/dist/node/recall.d.ts.map +1 -1
- package/dist/node/temporal.d.ts +15 -0
- package/dist/node/temporal.d.ts.map +1 -1
- package/dist/types/db.d.ts.map +1 -1
- package/dist/types/distillation.d.ts +26 -0
- package/dist/types/distillation.d.ts.map +1 -1
- package/dist/types/gradient.d.ts.map +1 -1
- package/dist/types/recall.d.ts.map +1 -1
- package/dist/types/temporal.d.ts +15 -0
- package/dist/types/temporal.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/db.ts +76 -8
- package/src/distillation.ts +125 -19
- package/src/gradient.ts +43 -9
- package/src/recall.ts +18 -0
- package/src/temporal.ts +39 -0
|
@@ -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,
|
|
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"}
|
package/dist/node/temporal.d.ts
CHANGED
|
@@ -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/dist/types/db.d.ts.map
CHANGED
|
@@ -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,
|
|
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;
|
|
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,
|
|
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"}
|
package/dist/types/temporal.d.ts
CHANGED
|
@@ -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
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
|
-
|
|
363
|
-
instance
|
|
364
|
-
|
|
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
|
-
|
|
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
|
-
|
|
372
|
-
migrate(
|
|
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)
|
|
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
|
-
|
|
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() {
|
package/src/distillation.ts
CHANGED
|
@@ -19,32 +19,125 @@ export { workerSessionIDs };
|
|
|
19
19
|
|
|
20
20
|
type TemporalMessage = temporal.TemporalMessage;
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
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
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
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:
|
|
1549
|
-
//
|
|
1550
|
-
//
|
|
1551
|
-
//
|
|
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
|
-
|
|
1554
|
-
|
|
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
|
-
|
|
1567
|
+
boundary = i;
|
|
1558
1568
|
break;
|
|
1559
1569
|
}
|
|
1560
1570
|
}
|
|
1561
|
-
if (
|
|
1562
|
-
|
|
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
|