@cortexkit/opencode-magic-context 0.13.0 → 0.13.2
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/README.md +1 -1
- package/dist/cli/prompts.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +21 -2
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts +36 -16
- package/dist/hooks/magic-context/compartment-runner-compressor.d.ts.map +1 -1
- package/dist/index.js +103 -49
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -335,7 +335,7 @@ On startup, Magic Context checks for common configuration problems — OpenCode'
|
|
|
335
335
|
A companion desktop app for browsing and managing Magic Context state outside of OpenCode.
|
|
336
336
|
|
|
337
337
|
<p align="center">
|
|
338
|
-
<a href="https://github.com/cortexkit/opencode-magic-context/releases/tag/dashboard-v0.
|
|
338
|
+
<a href="https://github.com/cortexkit/opencode-magic-context/releases/tag/dashboard-v0.3.0"><strong>⬇️ Download for macOS · Windows · Linux</strong></a></p>
|
|
339
339
|
|
|
340
340
|
**Features:**
|
|
341
341
|
- **Memory Browser** — search, filter, and edit project memories with category and project filtering
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/cli/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,EAEL,GAAG,EACH,IAAI,EACJ,KAAK,EAEL,OAAO,EACV,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../src/cli/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAGH,KAAK,EAEL,GAAG,EACH,IAAI,EACJ,KAAK,EAEL,OAAO,EACV,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AAiC5C,wBAAsB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,UAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAOlF;AAED,wBAAsB,IAAI,CACtB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IACL,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CAC/C,GACP,OAAO,CAAC,MAAM,CAAC,CAejB;AAED,wBAAsB,SAAS,CAC3B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,EAAE,GACnE,OAAO,CAAC,MAAM,CAAC,CAWjB"}
|
|
@@ -8,10 +8,29 @@ export declare function embedText(text: string): Promise<Float32Array | null>;
|
|
|
8
8
|
export declare function embedBatch(texts: string[]): Promise<(Float32Array | null)[]>;
|
|
9
9
|
export declare function embedUnembeddedMemories(db: Database, projectPath: string, config: EmbeddingConfig, batchSize?: number): Promise<number>;
|
|
10
10
|
/**
|
|
11
|
-
* Sweep ALL projects for unembedded memories,
|
|
12
|
-
*
|
|
11
|
+
* Sweep ALL projects for unembedded memories, draining each fully before
|
|
12
|
+
* moving to the next. Projects are ordered by most-recent memory activity
|
|
13
|
+
* (MAX(updated_at)), so the project you're actively working in gets
|
|
14
|
+
* embedded first after a provider switch.
|
|
15
|
+
*
|
|
16
|
+
* Within one invocation:
|
|
17
|
+
* - Each project is drained in batches of `batchSize` until `embedUnembeddedMemoriesForProject`
|
|
18
|
+
* returns 0 (nothing left, or a batch failure).
|
|
19
|
+
* - Wall-clock deadline + consecutive-empty fail-safe prevent runaway
|
|
20
|
+
* or infinite looping when the provider is unhealthy.
|
|
21
|
+
*
|
|
22
|
+
* Between invocations:
|
|
23
|
+
* - The module-level `sweepInProgress` flag guards against parallel runs
|
|
24
|
+
* from the same process. If a sweep is still running when the next
|
|
25
|
+
* 15-min tick fires, that tick is a no-op.
|
|
26
|
+
*
|
|
27
|
+
* Used by the dream timer for proactive embedding coverage. After a
|
|
28
|
+
* provider change wipes embeddings, this path drains the full backlog on
|
|
29
|
+
* a single tick (bounded by wall clock) instead of trickling 10/15min.
|
|
13
30
|
*/
|
|
14
31
|
export declare function embedAllUnembeddedMemories(db: Database, config: EmbeddingConfig, batchSize?: number): Promise<number>;
|
|
32
|
+
/** Test-only: reset the in-progress guard. */
|
|
33
|
+
export declare function _resetEmbeddingSweepGuard(): void;
|
|
15
34
|
export declare function getEmbeddingModelId(): string;
|
|
16
35
|
export { cosineSimilarity };
|
|
17
36
|
export declare function disposeEmbeddingModel(): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAG5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AA0GvD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAmBjE;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO7D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW1E;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,CAelF;AAED,wBAAsB,uBAAuB,CACzC,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,eAAe,EACvB,SAAS,SAAK,GACf,OAAO,CAAC,MAAM,CAAC,CAEjB;
|
|
1
|
+
{"version":3,"file":"embedding.d.ts","sourceRoot":"","sources":["../../../../src/features/magic-context/memory/embedding.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAG5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AA0GvD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAmBjE;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED,wBAAsB,oBAAoB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO7D;AAED,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAW1E;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,YAAY,GAAG,IAAI,CAAC,EAAE,CAAC,CAelF;AAED,wBAAsB,uBAAuB,CACzC,EAAE,EAAE,QAAQ,EACZ,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,eAAe,EACvB,SAAS,SAAK,GACf,OAAO,CAAC,MAAM,CAAC,CAEjB;AAgBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,0BAA0B,CAC5C,EAAE,EAAE,QAAQ,EACZ,MAAM,EAAE,eAAe,EACvB,SAAS,SAAK,GACf,OAAO,CAAC,MAAM,CAAC,CAsEjB;AAED,8CAA8C;AAC9C,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAmDD,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC;AAE5B,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAS3D"}
|
|
@@ -22,7 +22,6 @@ interface ScoredCompartment {
|
|
|
22
22
|
index: number;
|
|
23
23
|
tokenEstimate: number;
|
|
24
24
|
averageDepth: number;
|
|
25
|
-
score: number;
|
|
26
25
|
}
|
|
27
26
|
/**
|
|
28
27
|
* Check if the compartment block exceeds the history budget and run a compression pass if needed.
|
|
@@ -40,23 +39,44 @@ interface SelectionConstraints {
|
|
|
40
39
|
floorHeadroom: number;
|
|
41
40
|
}
|
|
42
41
|
/**
|
|
43
|
-
*
|
|
42
|
+
* Pick a contiguous same-depth band of compartments to compress next.
|
|
44
43
|
*
|
|
45
|
-
* Strategy
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
44
|
+
* Strategy (depth-first, oldest-within-tier):
|
|
45
|
+
* 1. Eligible scope = [0, scored.length - graceCompartments).
|
|
46
|
+
* Newest `graceCompartments` are never compressed (protects just-published
|
|
47
|
+
* historian output).
|
|
48
|
+
* 2. Within eligible scope, ignore compartments whose rounded depth is
|
|
49
|
+
* already at `maxMergeDepth` — they're done.
|
|
50
|
+
* 3. Find the **minimum** depth tier that still exists in scope.
|
|
51
|
+
* 4. Anchor on the **oldest** compartment at that minimum depth (lowest
|
|
52
|
+
* index). Extend forward while the next compartment has the same rounded
|
|
53
|
+
* depth, stopping at maxPickable / floorHeadroom / scope end.
|
|
54
|
+
* 5. Require runLen ≥ 2. If the oldest minimum-depth compartment can't form
|
|
55
|
+
* a run (neighbor has a different depth), the algorithm would stall —
|
|
56
|
+
* so fall back to finding the *next* oldest compartment at minDepth and
|
|
57
|
+
* retry. This preserves the old "skip singleton and move on" safety
|
|
58
|
+
* without abandoning the min-depth invariant.
|
|
51
59
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* -
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
60
|
+
* Why this shape:
|
|
61
|
+
* The previous algorithm was oldest-first regardless of depth. After the
|
|
62
|
+
* first pass compressed seq 0-14 to depth 1, the next pass picked seq 0-X
|
|
63
|
+
* AGAIN because they were still the oldest. The cascade ran depth 0→1→2→
|
|
64
|
+
* 3→4→5 on the same range within hours, crushing early compartments to
|
|
65
|
+
* empty title-only shells while the rest of history stayed at depth 0.
|
|
66
|
+
*
|
|
67
|
+
* Depth-first selection means: once seq 0-14 reach depth 1, the next pass
|
|
68
|
+
* prefers any depth-0 band elsewhere (seq 15+) before touching seq 0-14
|
|
69
|
+
* again. Old→new gets pushed down one tier at a time, producing a smooth
|
|
70
|
+
* depth gradient (old = deeper, recent = shallower) like memory decay.
|
|
71
|
+
*
|
|
72
|
+
* Grace window still protects the newest N from compression entirely so
|
|
73
|
+
* freshly-published historian output has time to settle.
|
|
74
|
+
*/
|
|
75
|
+
export declare function selectCompressionBand(scored: ScoredCompartment[], constraints: SelectionConstraints): ScoredCompartment[];
|
|
76
|
+
/**
|
|
77
|
+
* @deprecated Use {@link selectCompressionBand}. Kept as an export for the
|
|
78
|
+
* existing test suite that targets the older naming; semantics are identical.
|
|
59
79
|
*/
|
|
60
|
-
export declare
|
|
80
|
+
export declare const findOldestContiguousSameDepthBand: typeof selectCompressionBand;
|
|
61
81
|
export {};
|
|
62
82
|
//# sourceMappingURL=compartment-runner-compressor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compartment-runner-compressor.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/compartment-runner-compressor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAC;AAQpF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"compartment-runner-compressor.d.ts","sourceRoot":"","sources":["../../../src/hooks/magic-context/compartment-runner-compressor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAS3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kDAAkD,CAAC;AAQpF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAkBxD,MAAM,WAAW,cAAc;IAC3B,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,CAAC;IAChC,EAAE,EAAE,QAAQ,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,wEAAwE;IACxE,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,wEAAwE;IACxE,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAaD,UAAU,iBAAiB;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,CAyLvF;AAiCD,UAAU,oBAAoB;IAC1B,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,aAAa,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,uFAAuF;IACvF,aAAa,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,qBAAqB,CACjC,MAAM,EAAE,iBAAiB,EAAE,EAC3B,WAAW,EAAE,oBAAoB,GAClC,iBAAiB,EAAE,CA4DrB;AAED;;;GAGG;AACH,eAAO,MAAM,iCAAiC,8BAAwB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -16871,19 +16871,52 @@ async function embedBatch(texts) {
|
|
|
16871
16871
|
return currentProvider.embedBatch(texts);
|
|
16872
16872
|
}
|
|
16873
16873
|
async function embedAllUnembeddedMemories(db, config2, batchSize = 10) {
|
|
16874
|
-
|
|
16875
|
-
|
|
16874
|
+
if (sweepInProgress) {
|
|
16875
|
+
log("[magic-context] embedding sweep already in progress, skipping this tick");
|
|
16876
16876
|
return 0;
|
|
16877
|
-
const projects = db.prepare(`SELECT DISTINCT m.project_path FROM memories m
|
|
16878
|
-
WHERE m.status IN ('active', 'permanent')
|
|
16879
|
-
AND m.id NOT IN (SELECT memory_id FROM memory_embeddings)
|
|
16880
|
-
LIMIT 20`).all();
|
|
16881
|
-
let total = 0;
|
|
16882
|
-
for (const row of projects) {
|
|
16883
|
-
const count = await embedUnembeddedMemoriesForProject(db, row.project_path, config2, batchSize);
|
|
16884
|
-
total += count;
|
|
16885
16877
|
}
|
|
16886
|
-
|
|
16878
|
+
sweepInProgress = true;
|
|
16879
|
+
const startedAt = Date.now();
|
|
16880
|
+
const deadline = startedAt + SWEEP_MAX_WALL_CLOCK_MS;
|
|
16881
|
+
try {
|
|
16882
|
+
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
16883
|
+
if (resolvedConfig.provider === "off")
|
|
16884
|
+
return 0;
|
|
16885
|
+
const projects = db.prepare(`SELECT m.project_path, MAX(m.updated_at) AS latest
|
|
16886
|
+
FROM memories m
|
|
16887
|
+
WHERE m.status IN ('active', 'permanent')
|
|
16888
|
+
AND m.id NOT IN (SELECT memory_id FROM memory_embeddings)
|
|
16889
|
+
GROUP BY m.project_path
|
|
16890
|
+
ORDER BY latest DESC
|
|
16891
|
+
LIMIT 20`).all();
|
|
16892
|
+
let total = 0;
|
|
16893
|
+
let consecutiveEmpty = 0;
|
|
16894
|
+
outer:
|
|
16895
|
+
for (const project of projects) {
|
|
16896
|
+
while (Date.now() < deadline) {
|
|
16897
|
+
const count = await embedUnembeddedMemoriesForProject(db, project.project_path, config2, batchSize);
|
|
16898
|
+
if (count === 0) {
|
|
16899
|
+
consecutiveEmpty += 1;
|
|
16900
|
+
if (consecutiveEmpty >= SWEEP_MAX_CONSECUTIVE_EMPTY) {
|
|
16901
|
+
log(`[magic-context] embedding sweep: ${SWEEP_MAX_CONSECUTIVE_EMPTY} consecutive empty batches, stopping (total=${total})`);
|
|
16902
|
+
break outer;
|
|
16903
|
+
}
|
|
16904
|
+
break;
|
|
16905
|
+
}
|
|
16906
|
+
consecutiveEmpty = 0;
|
|
16907
|
+
total += count;
|
|
16908
|
+
if (count < batchSize)
|
|
16909
|
+
break;
|
|
16910
|
+
}
|
|
16911
|
+
if (Date.now() >= deadline) {
|
|
16912
|
+
log(`[magic-context] embedding sweep: wall-clock deadline reached after ${((Date.now() - startedAt) / 1000).toFixed(1)}s (total=${total})`);
|
|
16913
|
+
break;
|
|
16914
|
+
}
|
|
16915
|
+
}
|
|
16916
|
+
return total;
|
|
16917
|
+
} finally {
|
|
16918
|
+
sweepInProgress = false;
|
|
16919
|
+
}
|
|
16887
16920
|
}
|
|
16888
16921
|
async function embedUnembeddedMemoriesForProject(db, projectPath, config2, batchSize = 10) {
|
|
16889
16922
|
const normalizedBatchSize = Math.max(1, Math.floor(batchSize));
|
|
@@ -16922,7 +16955,7 @@ async function embedUnembeddedMemoriesForProject(db, projectPath, config2, batch
|
|
|
16922
16955
|
function getEmbeddingModelId() {
|
|
16923
16956
|
return getOrCreateProvider()?.modelId ?? "off";
|
|
16924
16957
|
}
|
|
16925
|
-
var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMemoriesStatements;
|
|
16958
|
+
var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMemoriesStatements, SWEEP_MAX_WALL_CLOCK_MS, SWEEP_MAX_CONSECUTIVE_EMPTY = 3, sweepInProgress = false;
|
|
16926
16959
|
var init_embedding = __esm(() => {
|
|
16927
16960
|
init_magic_context();
|
|
16928
16961
|
init_logger();
|
|
@@ -16935,6 +16968,7 @@ var init_embedding = __esm(() => {
|
|
|
16935
16968
|
};
|
|
16936
16969
|
embeddingConfig = DEFAULT_EMBEDDING_CONFIG;
|
|
16937
16970
|
loadUnembeddedMemoriesStatements = new WeakMap;
|
|
16971
|
+
SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
16938
16972
|
});
|
|
16939
16973
|
|
|
16940
16974
|
// src/features/magic-context/compression-depth-storage.ts
|
|
@@ -153507,12 +153541,23 @@ ${c.content}
|
|
|
153507
153541
|
const maxCompartmentsPerPass = deps.maxCompartmentsPerPass ?? DEFAULT_COMPRESSOR_MAX_COMPARTMENTS_PER_PASS;
|
|
153508
153542
|
const graceCompartments = deps.graceCompartments ?? DEFAULT_COMPRESSOR_GRACE_COMPARTMENTS;
|
|
153509
153543
|
const scored = scoreCompartments(db, sessionId, compartments);
|
|
153544
|
+
const depthHistogram = new Map;
|
|
153545
|
+
for (const s of scored) {
|
|
153546
|
+
const bucket = Math.round(s.averageDepth);
|
|
153547
|
+
depthHistogram.set(bucket, (depthHistogram.get(bucket) ?? 0) + 1);
|
|
153548
|
+
}
|
|
153549
|
+
const histText = [...depthHistogram.entries()].sort((a, b) => a[0] - b[0]).map(([d, n]) => `d${d}=${n}`).join(" ");
|
|
153550
|
+
const histKey = `${scored.length}|${histText}`;
|
|
153551
|
+
if (lastDepthHistogramBySession.get(sessionId) !== histKey) {
|
|
153552
|
+
lastDepthHistogramBySession.set(sessionId, histKey);
|
|
153553
|
+
sessionLog(sessionId, `compressor: depth histogram (${scored.length} total) ${histText}`);
|
|
153554
|
+
}
|
|
153510
153555
|
const floorHeadroom = compartments.length - floor;
|
|
153511
153556
|
if (floorHeadroom < 1) {
|
|
153512
153557
|
sessionLog(sessionId, `compressor: no floor headroom (${compartments.length} compartments, floor=${floor}), skipping`);
|
|
153513
153558
|
return false;
|
|
153514
153559
|
}
|
|
153515
|
-
const contiguous =
|
|
153560
|
+
const contiguous = selectCompressionBand(scored, {
|
|
153516
153561
|
maxPickable: maxCompartmentsPerPass,
|
|
153517
153562
|
maxMergeDepth,
|
|
153518
153563
|
graceCompartments,
|
|
@@ -153588,25 +153633,16 @@ ${c.content}
|
|
|
153588
153633
|
}
|
|
153589
153634
|
}
|
|
153590
153635
|
function scoreCompartments(db, sessionId, compartments) {
|
|
153591
|
-
let maxDepthAcrossSession = 0;
|
|
153592
|
-
for (const c of compartments) {
|
|
153593
|
-
const d = getAverageCompressionDepth(db, sessionId, c.startMessage, c.endMessage);
|
|
153594
|
-
if (d > maxDepthAcrossSession)
|
|
153595
|
-
maxDepthAcrossSession = d;
|
|
153596
|
-
}
|
|
153597
153636
|
return compartments.map((compartment, index) => {
|
|
153598
153637
|
const tokenEstimate = estimateTokens(`<compartment start="${compartment.startMessage}" end="${compartment.endMessage}" title="${compartment.title}">
|
|
153599
153638
|
${compartment.content}
|
|
153600
153639
|
</compartment>
|
|
153601
153640
|
`);
|
|
153602
153641
|
const averageDepth = getAverageCompressionDepth(db, sessionId, compartment.startMessage, compartment.endMessage);
|
|
153603
|
-
|
|
153604
|
-
const normalizedDepth = maxDepthAcrossSession > 0 ? 1 - averageDepth / maxDepthAcrossSession : 1;
|
|
153605
|
-
const score = 0.7 * normalizedAge + 0.3 * normalizedDepth;
|
|
153606
|
-
return { compartment, index, tokenEstimate, averageDepth, score };
|
|
153642
|
+
return { compartment, index, tokenEstimate, averageDepth };
|
|
153607
153643
|
});
|
|
153608
153644
|
}
|
|
153609
|
-
function
|
|
153645
|
+
function selectCompressionBand(scored, constraints) {
|
|
153610
153646
|
const { maxPickable, maxMergeDepth, graceCompartments, floorHeadroom } = constraints;
|
|
153611
153647
|
const hardMaxPick = Math.max(0, Math.min(maxPickable, floorHeadroom));
|
|
153612
153648
|
if (hardMaxPick < 2)
|
|
@@ -153614,32 +153650,49 @@ function findOldestContiguousSameDepthBand(scored, constraints) {
|
|
|
153614
153650
|
const scanEnd = Math.max(0, scored.length - graceCompartments);
|
|
153615
153651
|
if (scanEnd < 2)
|
|
153616
153652
|
return [];
|
|
153617
|
-
|
|
153618
|
-
|
|
153619
|
-
const
|
|
153620
|
-
if (!
|
|
153621
|
-
i++;
|
|
153653
|
+
const tiers = new Set;
|
|
153654
|
+
for (let i = 0;i < scanEnd; i++) {
|
|
153655
|
+
const entry = scored[i];
|
|
153656
|
+
if (!entry)
|
|
153622
153657
|
continue;
|
|
153658
|
+
if (entry.averageDepth >= maxMergeDepth)
|
|
153659
|
+
continue;
|
|
153660
|
+
tiers.add(Math.round(entry.averageDepth));
|
|
153661
|
+
}
|
|
153662
|
+
if (tiers.size === 0)
|
|
153663
|
+
return [];
|
|
153664
|
+
const orderedTiers = [...tiers].sort((a, b) => a - b);
|
|
153665
|
+
for (const targetDepth of orderedTiers) {
|
|
153666
|
+
let i = 0;
|
|
153667
|
+
while (i < scanEnd) {
|
|
153668
|
+
const anchor = scored[i];
|
|
153669
|
+
if (!anchor) {
|
|
153670
|
+
i++;
|
|
153671
|
+
continue;
|
|
153672
|
+
}
|
|
153673
|
+
if (anchor.averageDepth >= maxMergeDepth || Math.round(anchor.averageDepth) !== targetDepth) {
|
|
153674
|
+
i++;
|
|
153675
|
+
continue;
|
|
153676
|
+
}
|
|
153677
|
+
let j = i;
|
|
153678
|
+
while (j < scanEnd) {
|
|
153679
|
+
const entry = scored[j];
|
|
153680
|
+
if (!entry)
|
|
153681
|
+
break;
|
|
153682
|
+
if (entry.averageDepth >= maxMergeDepth)
|
|
153683
|
+
break;
|
|
153684
|
+
if (Math.round(entry.averageDepth) !== targetDepth)
|
|
153685
|
+
break;
|
|
153686
|
+
if (j - i >= hardMaxPick)
|
|
153687
|
+
break;
|
|
153688
|
+
j++;
|
|
153689
|
+
}
|
|
153690
|
+
const runLen = j - i;
|
|
153691
|
+
if (runLen >= 2) {
|
|
153692
|
+
return scored.slice(i, j);
|
|
153693
|
+
}
|
|
153694
|
+
i = Math.max(j, i + 1);
|
|
153623
153695
|
}
|
|
153624
|
-
const anchorDepth = Math.round(c.averageDepth);
|
|
153625
|
-
let j = i;
|
|
153626
|
-
while (j < scanEnd) {
|
|
153627
|
-
const entry = scored[j];
|
|
153628
|
-
if (!entry)
|
|
153629
|
-
break;
|
|
153630
|
-
if (entry.averageDepth >= maxMergeDepth)
|
|
153631
|
-
break;
|
|
153632
|
-
if (Math.round(entry.averageDepth) !== anchorDepth)
|
|
153633
|
-
break;
|
|
153634
|
-
if (j - i >= hardMaxPick)
|
|
153635
|
-
break;
|
|
153636
|
-
j++;
|
|
153637
|
-
}
|
|
153638
|
-
const runLen = j - i;
|
|
153639
|
-
if (runLen >= 2) {
|
|
153640
|
-
return scored.slice(i, j);
|
|
153641
|
-
}
|
|
153642
|
-
i = Math.max(j, i + 1);
|
|
153643
153696
|
}
|
|
153644
153697
|
return [];
|
|
153645
153698
|
}
|
|
@@ -153823,7 +153876,7 @@ async function runCompressorPass(args) {
|
|
|
153823
153876
|
}
|
|
153824
153877
|
}
|
|
153825
153878
|
}
|
|
153826
|
-
var HISTORIAN_AGENT2 = "historian";
|
|
153879
|
+
var HISTORIAN_AGENT2 = "historian", lastDepthHistogramBySession;
|
|
153827
153880
|
var init_compartment_runner_compressor = __esm(() => {
|
|
153828
153881
|
init_magic_context();
|
|
153829
153882
|
init_storage();
|
|
@@ -153834,6 +153887,7 @@ var init_compartment_runner_compressor = __esm(() => {
|
|
|
153834
153887
|
init_compartment_parser();
|
|
153835
153888
|
init_compartment_prompt();
|
|
153836
153889
|
init_read_session_formatting();
|
|
153890
|
+
lastDepthHistogramBySession = new Map;
|
|
153837
153891
|
});
|
|
153838
153892
|
|
|
153839
153893
|
// src/hooks/magic-context/compartment-runner-drop-queue.ts
|
package/package.json
CHANGED