@cortexkit/opencode-magic-context 0.13.2 → 0.14.1
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 +23 -11
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli.js +59 -3
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +61 -22
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-storage.d.ts.map +1 -1
- package/dist/features/magic-context/git-commits/git-log-reader.d.ts +57 -0
- package/dist/features/magic-context/git-commits/git-log-reader.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/index.d.ts +7 -0
- package/dist/features/magic-context/git-commits/index.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/indexer.d.ts +44 -0
- package/dist/features/magic-context/git-commits/indexer.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/search-git-commits.d.ts +32 -0
- package/dist/features/magic-context/git-commits/search-git-commits.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts +18 -0
- package/dist/features/magic-context/git-commits/storage-git-commit-embeddings.d.ts.map +1 -0
- package/dist/features/magic-context/git-commits/storage-git-commits.d.ts +47 -0
- package/dist/features/magic-context/git-commits/storage-git-commits.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts +2 -2
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-openai.d.ts +25 -2
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-provider.d.ts +8 -2
- package/dist/features/magic-context/memory/embedding-provider.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +2 -2
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/overflow-detection.d.ts +51 -0
- package/dist/features/magic-context/overflow-detection.d.ts.map +1 -0
- package/dist/features/magic-context/search.d.ts +40 -9
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +40 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +1 -1
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-hint.d.ts +34 -0
- package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -0
- package/dist/hooks/magic-context/auto-search-runner.d.ts +51 -0
- package/dist/hooks/magic-context/auto-search-runner.d.ts.map +1 -0
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +29 -0
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +9 -0
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/drop-stale-reduce-calls.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-payloads.d.ts +15 -1
- package/dist/hooks/magic-context/event-payloads.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-resolvers.d.ts +20 -1
- package/dist/hooks/magic-context/event-resolvers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts +5 -2
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +14 -6
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +12 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/note-nudger.d.ts.map +1 -1
- package/dist/hooks/magic-context/nudger.d.ts +0 -3
- package/dist/hooks/magic-context/nudger.d.ts.map +1 -1
- package/dist/hooks/magic-context/reasoning-capability.d.ts +23 -0
- package/dist/hooks/magic-context/reasoning-capability.d.ts.map +1 -0
- package/dist/hooks/magic-context/sentinel.d.ts +53 -0
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -0
- package/dist/hooks/magic-context/strip-content.d.ts +66 -16
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-structural-noise.d.ts +14 -0
- package/dist/hooks/magic-context/strip-structural-noise.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts +18 -5
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts +2 -0
- package/dist/hooks/magic-context/transform-compartment-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +22 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +12 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2288 -738
- package/dist/plugin/dream-timer.d.ts +24 -7
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +4 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/tool-registry.d.ts.map +1 -1
- package/dist/shared/models-dev-cache.d.ts +20 -6
- package/dist/shared/models-dev-cache.d.ts.map +1 -1
- package/dist/tools/ctx-note/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/constants.d.ts +1 -1
- package/dist/tools/ctx-search/constants.d.ts.map +1 -1
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/types.d.ts +8 -0
- package/dist/tools/ctx-search/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/models-dev-cache.test.ts +57 -6
- package/src/shared/models-dev-cache.ts +119 -38
package/dist/index.js
CHANGED
|
@@ -14101,7 +14101,16 @@ var init_magic_context = __esm(() => {
|
|
|
14101
14101
|
max_runtime_minutes: exports_external.number().min(10).default(120),
|
|
14102
14102
|
tasks: exports_external.array(DreamingTaskSchema).default(DEFAULT_DREAMER_TASKS),
|
|
14103
14103
|
task_timeout_minutes: exports_external.number().min(5).default(20),
|
|
14104
|
-
inject_docs: exports_external.boolean().default(true)
|
|
14104
|
+
inject_docs: exports_external.boolean().default(true),
|
|
14105
|
+
user_memories: exports_external.object({
|
|
14106
|
+
enabled: exports_external.boolean().default(true),
|
|
14107
|
+
promotion_threshold: exports_external.number().min(2).max(20).default(3)
|
|
14108
|
+
}).default({ enabled: true, promotion_threshold: 3 }),
|
|
14109
|
+
pin_key_files: exports_external.object({
|
|
14110
|
+
enabled: exports_external.boolean().default(false),
|
|
14111
|
+
token_budget: exports_external.number().min(2000).max(30000).default(1e4),
|
|
14112
|
+
min_reads: exports_external.number().min(2).max(20).default(4)
|
|
14113
|
+
}).default({ enabled: false, token_budget: 1e4, min_reads: 4 })
|
|
14105
14114
|
}));
|
|
14106
14115
|
SidekickConfigSchema = AgentOverrideConfigSchema.extend({
|
|
14107
14116
|
enabled: exports_external.boolean().default(false),
|
|
@@ -14196,20 +14205,21 @@ var init_magic_context = __esm(() => {
|
|
|
14196
14205
|
model: DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
14197
14206
|
}),
|
|
14198
14207
|
experimental: exports_external.object({
|
|
14199
|
-
|
|
14208
|
+
temporal_awareness: exports_external.boolean().default(false),
|
|
14209
|
+
git_commit_indexing: exports_external.object({
|
|
14200
14210
|
enabled: exports_external.boolean().default(false),
|
|
14201
|
-
|
|
14202
|
-
|
|
14203
|
-
|
|
14211
|
+
since_days: exports_external.number().min(7).max(3650).default(365),
|
|
14212
|
+
max_commits: exports_external.number().min(100).max(20000).default(2000)
|
|
14213
|
+
}).default({ enabled: false, since_days: 365, max_commits: 2000 }),
|
|
14214
|
+
auto_search: exports_external.object({
|
|
14204
14215
|
enabled: exports_external.boolean().default(false),
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
}).default({ enabled: false,
|
|
14208
|
-
temporal_awareness: exports_external.boolean().default(false)
|
|
14216
|
+
score_threshold: exports_external.number().min(0.3).max(0.95).default(0.55),
|
|
14217
|
+
min_prompt_chars: exports_external.number().min(5).max(500).default(20)
|
|
14218
|
+
}).default({ enabled: false, score_threshold: 0.55, min_prompt_chars: 20 })
|
|
14209
14219
|
}).default({
|
|
14210
|
-
|
|
14211
|
-
|
|
14212
|
-
|
|
14220
|
+
temporal_awareness: false,
|
|
14221
|
+
git_commit_indexing: { enabled: false, since_days: 365, max_commits: 2000 },
|
|
14222
|
+
auto_search: { enabled: false, score_threshold: 0.55, min_prompt_chars: 20 }
|
|
14213
14223
|
}),
|
|
14214
14224
|
memory: exports_external.object({
|
|
14215
14225
|
enabled: exports_external.boolean().default(true),
|
|
@@ -14603,7 +14613,7 @@ function replaceSessionFacts(db, sessionId, facts) {
|
|
|
14603
14613
|
db.transaction(() => {
|
|
14604
14614
|
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
14605
14615
|
insertFactRows(db, sessionId, facts, now);
|
|
14606
|
-
db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE session_id = ?").run(sessionId);
|
|
14616
|
+
db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
|
|
14607
14617
|
})();
|
|
14608
14618
|
}
|
|
14609
14619
|
function getSessionFacts(db, sessionId) {
|
|
@@ -14617,7 +14627,7 @@ function replaceAllCompartmentState(db, sessionId, compartments, facts) {
|
|
|
14617
14627
|
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
14618
14628
|
insertCompartmentRows(db, sessionId, compartments, now);
|
|
14619
14629
|
insertFactRows(db, sessionId, facts, now);
|
|
14620
|
-
db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE session_id = ?").run(sessionId);
|
|
14630
|
+
db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE session_id = ?").run(sessionId);
|
|
14621
14631
|
})();
|
|
14622
14632
|
}
|
|
14623
14633
|
function buildCompartmentBlock(compartments, facts, memoryBlock, dateRanges) {
|
|
@@ -14705,7 +14715,7 @@ function promoteRecompStaging(db, sessionId) {
|
|
|
14705
14715
|
}
|
|
14706
14716
|
function invalidateAllMemoryBlockCaches(db) {
|
|
14707
14717
|
try {
|
|
14708
|
-
db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != ''").run();
|
|
14718
|
+
db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_ids = '' WHERE memory_block_cache != '' OR memory_block_ids != ''").run();
|
|
14709
14719
|
} catch {}
|
|
14710
14720
|
}
|
|
14711
14721
|
function clearRecompStaging(db, sessionId) {
|
|
@@ -16612,7 +16622,9 @@ class LocalEmbeddingProvider {
|
|
|
16612
16622
|
await this.initPromise;
|
|
16613
16623
|
return this.pipeline !== null;
|
|
16614
16624
|
}
|
|
16615
|
-
async embed(text) {
|
|
16625
|
+
async embed(text, signal) {
|
|
16626
|
+
if (signal?.aborted)
|
|
16627
|
+
return null;
|
|
16616
16628
|
if (!await this.initialize()) {
|
|
16617
16629
|
return null;
|
|
16618
16630
|
}
|
|
@@ -16631,10 +16643,13 @@ class LocalEmbeddingProvider {
|
|
|
16631
16643
|
return null;
|
|
16632
16644
|
}
|
|
16633
16645
|
}
|
|
16634
|
-
async embedBatch(texts) {
|
|
16646
|
+
async embedBatch(texts, signal) {
|
|
16635
16647
|
if (texts.length === 0) {
|
|
16636
16648
|
return [];
|
|
16637
16649
|
}
|
|
16650
|
+
if (signal?.aborted) {
|
|
16651
|
+
return Array.from({ length: texts.length }, () => null);
|
|
16652
|
+
}
|
|
16638
16653
|
if (!await this.initialize()) {
|
|
16639
16654
|
return Array.from({ length: texts.length }, () => null);
|
|
16640
16655
|
}
|
|
@@ -16695,6 +16710,10 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
16695
16710
|
model;
|
|
16696
16711
|
apiKey;
|
|
16697
16712
|
initialized = false;
|
|
16713
|
+
failureTimes = [];
|
|
16714
|
+
circuitOpenUntil = 0;
|
|
16715
|
+
openLogged = false;
|
|
16716
|
+
halfOpenProbeInFlight = false;
|
|
16698
16717
|
constructor(options) {
|
|
16699
16718
|
this.endpoint = normalizeEndpoint(options.endpoint);
|
|
16700
16719
|
this.model = options.model?.trim() ?? "";
|
|
@@ -16712,18 +16731,36 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
16712
16731
|
this.initialized = true;
|
|
16713
16732
|
return true;
|
|
16714
16733
|
}
|
|
16715
|
-
async embed(text) {
|
|
16716
|
-
const [embedding] = await this.embedBatch([text]);
|
|
16734
|
+
async embed(text, signal) {
|
|
16735
|
+
const [embedding] = await this.embedBatch([text], signal);
|
|
16717
16736
|
return embedding ?? null;
|
|
16718
16737
|
}
|
|
16719
|
-
async embedBatch(texts) {
|
|
16738
|
+
async embedBatch(texts, signal) {
|
|
16720
16739
|
if (texts.length === 0) {
|
|
16721
16740
|
return [];
|
|
16722
16741
|
}
|
|
16723
16742
|
if (!await this.initialize()) {
|
|
16724
16743
|
return Array.from({ length: texts.length }, () => null);
|
|
16725
16744
|
}
|
|
16745
|
+
if (signal?.aborted) {
|
|
16746
|
+
return Array.from({ length: texts.length }, () => null);
|
|
16747
|
+
}
|
|
16748
|
+
let isProbe = false;
|
|
16749
|
+
let internalController;
|
|
16750
|
+
let timeoutHandle;
|
|
16751
|
+
let onOuterAbort;
|
|
16726
16752
|
try {
|
|
16753
|
+
const claim = this.claimProbeOrShortCircuit();
|
|
16754
|
+
if (claim === "short_circuit") {
|
|
16755
|
+
return Array.from({ length: texts.length }, () => null);
|
|
16756
|
+
}
|
|
16757
|
+
isProbe = claim === "probe";
|
|
16758
|
+
internalController = new AbortController;
|
|
16759
|
+
timeoutHandle = setTimeout(() => internalController?.abort(), FETCH_TIMEOUT_MS);
|
|
16760
|
+
onOuterAbort = () => internalController?.abort();
|
|
16761
|
+
if (signal) {
|
|
16762
|
+
signal.addEventListener("abort", onOuterAbort, { once: true });
|
|
16763
|
+
}
|
|
16727
16764
|
const response = await fetch(`${this.endpoint}/embeddings`, {
|
|
16728
16765
|
method: "POST",
|
|
16729
16766
|
headers: {
|
|
@@ -16733,21 +16770,48 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
16733
16770
|
body: JSON.stringify({
|
|
16734
16771
|
model: this.model,
|
|
16735
16772
|
input: texts
|
|
16736
|
-
})
|
|
16773
|
+
}),
|
|
16774
|
+
signal: internalController.signal
|
|
16737
16775
|
});
|
|
16738
16776
|
if (!response.ok) {
|
|
16739
16777
|
log(`[magic-context] openai-compatible embedding request failed: ${response.status} ${response.statusText}`);
|
|
16778
|
+
this.recordFailure(isProbe);
|
|
16740
16779
|
return Array.from({ length: texts.length }, () => null);
|
|
16741
16780
|
}
|
|
16742
16781
|
const body = await response.json();
|
|
16743
16782
|
const items = Array.isArray(body.data) ? body.data : [];
|
|
16744
|
-
|
|
16783
|
+
const results = Array.from({ length: texts.length }, (_, index) => {
|
|
16745
16784
|
const embedding = items[index]?.embedding;
|
|
16746
16785
|
return Array.isArray(embedding) ? Float32Array.from(embedding) : null;
|
|
16747
16786
|
});
|
|
16787
|
+
if (results.every((r) => r === null)) {
|
|
16788
|
+
this.recordFailure(isProbe);
|
|
16789
|
+
} else {
|
|
16790
|
+
this.recordSuccess();
|
|
16791
|
+
}
|
|
16792
|
+
return results;
|
|
16748
16793
|
} catch (error48) {
|
|
16749
|
-
|
|
16794
|
+
const isAbort = error48 instanceof Error && (error48.name === "AbortError" || error48.message.includes("aborted"));
|
|
16795
|
+
if (isAbort) {
|
|
16796
|
+
if (signal?.aborted) {} else {
|
|
16797
|
+
log(`[magic-context] openai-compatible embedding request timed out after ${FETCH_TIMEOUT_MS}ms`);
|
|
16798
|
+
this.recordFailure(isProbe);
|
|
16799
|
+
}
|
|
16800
|
+
} else {
|
|
16801
|
+
log("[magic-context] openai-compatible embedding request failed:", error48);
|
|
16802
|
+
this.recordFailure(isProbe);
|
|
16803
|
+
}
|
|
16750
16804
|
return Array.from({ length: texts.length }, () => null);
|
|
16805
|
+
} finally {
|
|
16806
|
+
if (timeoutHandle !== undefined) {
|
|
16807
|
+
clearTimeout(timeoutHandle);
|
|
16808
|
+
}
|
|
16809
|
+
if (signal && onOuterAbort) {
|
|
16810
|
+
signal.removeEventListener("abort", onOuterAbort);
|
|
16811
|
+
}
|
|
16812
|
+
if (isProbe) {
|
|
16813
|
+
this.halfOpenProbeInFlight = false;
|
|
16814
|
+
}
|
|
16751
16815
|
}
|
|
16752
16816
|
}
|
|
16753
16817
|
async dispose() {
|
|
@@ -16756,9 +16820,73 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
16756
16820
|
isLoaded() {
|
|
16757
16821
|
return this.initialized;
|
|
16758
16822
|
}
|
|
16823
|
+
claimProbeOrShortCircuit() {
|
|
16824
|
+
if (this.circuitOpenUntil === 0) {
|
|
16825
|
+
return "allow";
|
|
16826
|
+
}
|
|
16827
|
+
if (Date.now() < this.circuitOpenUntil) {
|
|
16828
|
+
return "short_circuit";
|
|
16829
|
+
}
|
|
16830
|
+
if (this.halfOpenProbeInFlight) {
|
|
16831
|
+
return "short_circuit";
|
|
16832
|
+
}
|
|
16833
|
+
this.halfOpenProbeInFlight = true;
|
|
16834
|
+
log("[magic-context] openai-compatible embedding: circuit half-open, probing endpoint");
|
|
16835
|
+
return "probe";
|
|
16836
|
+
}
|
|
16837
|
+
recordFailure(isProbe) {
|
|
16838
|
+
if (isProbe) {
|
|
16839
|
+
this.circuitOpenUntil = Date.now() + OPEN_DURATION_MS;
|
|
16840
|
+
if (!this.openLogged) {
|
|
16841
|
+
log(`[magic-context] openai-compatible embedding: probe failed, re-opening circuit for ${OPEN_DURATION_MS / 60000}min`);
|
|
16842
|
+
this.openLogged = true;
|
|
16843
|
+
}
|
|
16844
|
+
this.failureTimes = [];
|
|
16845
|
+
return;
|
|
16846
|
+
}
|
|
16847
|
+
const now = Date.now();
|
|
16848
|
+
const cutoff = now - FAILURE_WINDOW_MS;
|
|
16849
|
+
this.failureTimes = this.failureTimes.filter((t) => t > cutoff);
|
|
16850
|
+
this.failureTimes.push(now);
|
|
16851
|
+
if (this.failureTimes.length >= FAILURE_THRESHOLD) {
|
|
16852
|
+
this.circuitOpenUntil = now + OPEN_DURATION_MS;
|
|
16853
|
+
if (!this.openLogged) {
|
|
16854
|
+
log(`[magic-context] openai-compatible embedding: opening circuit for ${OPEN_DURATION_MS / 60000}min after ${this.failureTimes.length} failures in ${FAILURE_WINDOW_MS / 1000}s`);
|
|
16855
|
+
this.openLogged = true;
|
|
16856
|
+
}
|
|
16857
|
+
this.failureTimes = [];
|
|
16858
|
+
}
|
|
16859
|
+
}
|
|
16860
|
+
recordSuccess() {
|
|
16861
|
+
if (this.failureTimes.length > 0 || this.circuitOpenUntil > 0 || this.openLogged) {
|
|
16862
|
+
log("[magic-context] openai-compatible embedding: endpoint recovered, circuit closed");
|
|
16863
|
+
}
|
|
16864
|
+
this.failureTimes = [];
|
|
16865
|
+
this.circuitOpenUntil = 0;
|
|
16866
|
+
this.openLogged = false;
|
|
16867
|
+
}
|
|
16868
|
+
_getCircuitState() {
|
|
16869
|
+
if (this.circuitOpenUntil === 0)
|
|
16870
|
+
return "closed";
|
|
16871
|
+
if (Date.now() < this.circuitOpenUntil) {
|
|
16872
|
+
return this.halfOpenProbeInFlight ? "half_open" : "open";
|
|
16873
|
+
}
|
|
16874
|
+
return "half_open";
|
|
16875
|
+
}
|
|
16876
|
+
_getFailureCount() {
|
|
16877
|
+
return this.failureTimes.length;
|
|
16878
|
+
}
|
|
16879
|
+
_resetCircuit() {
|
|
16880
|
+
this.failureTimes = [];
|
|
16881
|
+
this.circuitOpenUntil = 0;
|
|
16882
|
+
this.openLogged = false;
|
|
16883
|
+
this.halfOpenProbeInFlight = false;
|
|
16884
|
+
}
|
|
16759
16885
|
}
|
|
16886
|
+
var FAILURE_THRESHOLD = 3, FAILURE_WINDOW_MS = 60000, OPEN_DURATION_MS, FETCH_TIMEOUT_MS = 30000;
|
|
16760
16887
|
var init_embedding_openai = __esm(() => {
|
|
16761
16888
|
init_logger();
|
|
16889
|
+
OPEN_DURATION_MS = 5 * 60000;
|
|
16762
16890
|
});
|
|
16763
16891
|
|
|
16764
16892
|
// src/features/magic-context/memory/embedding.ts
|
|
@@ -16847,7 +16975,7 @@ function initializeEmbedding(config2) {
|
|
|
16847
16975
|
function isEmbeddingEnabled() {
|
|
16848
16976
|
return embeddingConfig.provider !== "off";
|
|
16849
16977
|
}
|
|
16850
|
-
async function embedText(text) {
|
|
16978
|
+
async function embedText(text, signal) {
|
|
16851
16979
|
const currentProvider = getOrCreateProvider();
|
|
16852
16980
|
if (!currentProvider) {
|
|
16853
16981
|
return null;
|
|
@@ -16855,9 +16983,9 @@ async function embedText(text) {
|
|
|
16855
16983
|
if (!await currentProvider.initialize()) {
|
|
16856
16984
|
return null;
|
|
16857
16985
|
}
|
|
16858
|
-
return currentProvider.embed(text);
|
|
16986
|
+
return currentProvider.embed(text, signal);
|
|
16859
16987
|
}
|
|
16860
|
-
async function embedBatch(texts) {
|
|
16988
|
+
async function embedBatch(texts, signal) {
|
|
16861
16989
|
if (texts.length === 0) {
|
|
16862
16990
|
return [];
|
|
16863
16991
|
}
|
|
@@ -16868,7 +16996,7 @@ async function embedBatch(texts) {
|
|
|
16868
16996
|
if (!await currentProvider.initialize()) {
|
|
16869
16997
|
return Array.from({ length: texts.length }, () => null);
|
|
16870
16998
|
}
|
|
16871
|
-
return currentProvider.embedBatch(texts);
|
|
16999
|
+
return currentProvider.embedBatch(texts, signal);
|
|
16872
17000
|
}
|
|
16873
17001
|
async function embedAllUnembeddedMemories(db, config2, batchSize = 10) {
|
|
16874
17002
|
if (sweepInProgress) {
|
|
@@ -16971,6 +17099,79 @@ var init_embedding = __esm(() => {
|
|
|
16971
17099
|
SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
16972
17100
|
});
|
|
16973
17101
|
|
|
17102
|
+
// src/features/magic-context/memory/storage-memory-fts.ts
|
|
17103
|
+
function getSearchStatement(db) {
|
|
17104
|
+
let stmt = searchStatements.get(db);
|
|
17105
|
+
if (!stmt) {
|
|
17106
|
+
const selectColumns = Object.entries(COLUMN_MAP).map(([property, column]) => `memories.${column} AS ${property}`).join(", ");
|
|
17107
|
+
stmt = db.prepare(`SELECT ${selectColumns} FROM memories_fts INNER JOIN memories ON memories.id = memories_fts.rowid WHERE memories.project_path = ? AND memories.status IN ('active', 'permanent') AND (memories.expires_at IS NULL OR memories.expires_at > ?) AND memories_fts MATCH ? ORDER BY bm25(memories_fts), memories.updated_at DESC, memories.id ASC LIMIT ?`);
|
|
17108
|
+
searchStatements.set(db, stmt);
|
|
17109
|
+
}
|
|
17110
|
+
return stmt;
|
|
17111
|
+
}
|
|
17112
|
+
function sanitizeFtsQuery(query) {
|
|
17113
|
+
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
17114
|
+
if (tokens.length === 0)
|
|
17115
|
+
return "";
|
|
17116
|
+
return tokens.map((token) => `"${token.replace(/"/g, '""')}"`).join(" ");
|
|
17117
|
+
}
|
|
17118
|
+
function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT) {
|
|
17119
|
+
const trimmedQuery = query.trim();
|
|
17120
|
+
if (trimmedQuery.length === 0 || limit <= 0) {
|
|
17121
|
+
return [];
|
|
17122
|
+
}
|
|
17123
|
+
const sanitized = sanitizeFtsQuery(trimmedQuery);
|
|
17124
|
+
if (sanitized.length === 0) {
|
|
17125
|
+
return [];
|
|
17126
|
+
}
|
|
17127
|
+
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
17128
|
+
return rows.map(toMemory);
|
|
17129
|
+
}
|
|
17130
|
+
var DEFAULT_SEARCH_LIMIT = 10, searchStatements;
|
|
17131
|
+
var init_storage_memory_fts = __esm(() => {
|
|
17132
|
+
init_storage_memory();
|
|
17133
|
+
searchStatements = new WeakMap;
|
|
17134
|
+
});
|
|
17135
|
+
|
|
17136
|
+
// src/features/magic-context/memory/project-identity.ts
|
|
17137
|
+
import { execSync } from "child_process";
|
|
17138
|
+
import path3 from "path";
|
|
17139
|
+
function getRootCommitHash(directory) {
|
|
17140
|
+
try {
|
|
17141
|
+
const hash2 = execSync("git rev-list --max-parents=0 HEAD", {
|
|
17142
|
+
cwd: directory,
|
|
17143
|
+
encoding: "utf-8",
|
|
17144
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
17145
|
+
timeout: GIT_TIMEOUT_MS2
|
|
17146
|
+
}).trim();
|
|
17147
|
+
const firstLine = hash2.split(`
|
|
17148
|
+
`)[0]?.trim();
|
|
17149
|
+
return firstLine && firstLine.length >= 7 ? firstLine : undefined;
|
|
17150
|
+
} catch {
|
|
17151
|
+
return;
|
|
17152
|
+
}
|
|
17153
|
+
}
|
|
17154
|
+
function directoryFallback(directory) {
|
|
17155
|
+
const canonical = path3.resolve(directory);
|
|
17156
|
+
const hash2 = Bun.hash(canonical).toString(16).slice(0, 12);
|
|
17157
|
+
return `dir:${hash2}`;
|
|
17158
|
+
}
|
|
17159
|
+
function resolveProjectIdentity(directory) {
|
|
17160
|
+
const resolved = path3.resolve(directory);
|
|
17161
|
+
const cached2 = resolvedCache.get(resolved);
|
|
17162
|
+
if (cached2 !== undefined) {
|
|
17163
|
+
return cached2;
|
|
17164
|
+
}
|
|
17165
|
+
const rootHash = getRootCommitHash(resolved);
|
|
17166
|
+
const identity = rootHash ? `git:${rootHash}` : directoryFallback(resolved);
|
|
17167
|
+
resolvedCache.set(resolved, identity);
|
|
17168
|
+
return identity;
|
|
17169
|
+
}
|
|
17170
|
+
var GIT_TIMEOUT_MS2 = 5000, resolvedCache;
|
|
17171
|
+
var init_project_identity = __esm(() => {
|
|
17172
|
+
resolvedCache = new Map;
|
|
17173
|
+
});
|
|
17174
|
+
|
|
16974
17175
|
// src/features/magic-context/compression-depth-storage.ts
|
|
16975
17176
|
function getIncrementDepthStatement(db) {
|
|
16976
17177
|
let stmt = incrementDepthStatements.get(db);
|
|
@@ -150227,6 +150428,62 @@ var init_migrations = __esm(() => {
|
|
|
150227
150428
|
CREATE INDEX IF NOT EXISTS idx_um_status ON user_memories(status);
|
|
150228
150429
|
`);
|
|
150229
150430
|
}
|
|
150431
|
+
},
|
|
150432
|
+
{
|
|
150433
|
+
version: 4,
|
|
150434
|
+
description: "Add git_commits + git_commit_embeddings + git_commits_fts tables",
|
|
150435
|
+
up: (db) => {
|
|
150436
|
+
db.exec(`
|
|
150437
|
+
CREATE TABLE IF NOT EXISTS git_commits (
|
|
150438
|
+
sha TEXT PRIMARY KEY,
|
|
150439
|
+
project_path TEXT NOT NULL,
|
|
150440
|
+
short_sha TEXT NOT NULL,
|
|
150441
|
+
message TEXT NOT NULL,
|
|
150442
|
+
author TEXT,
|
|
150443
|
+
committed_at INTEGER NOT NULL,
|
|
150444
|
+
indexed_at INTEGER NOT NULL
|
|
150445
|
+
);
|
|
150446
|
+
CREATE INDEX IF NOT EXISTS idx_git_commits_project_time
|
|
150447
|
+
ON git_commits(project_path, committed_at DESC);
|
|
150448
|
+
|
|
150449
|
+
CREATE TABLE IF NOT EXISTS git_commit_embeddings (
|
|
150450
|
+
sha TEXT PRIMARY KEY,
|
|
150451
|
+
embedding BLOB NOT NULL,
|
|
150452
|
+
model_id TEXT NOT NULL,
|
|
150453
|
+
created_at INTEGER NOT NULL,
|
|
150454
|
+
FOREIGN KEY(sha) REFERENCES git_commits(sha) ON DELETE CASCADE
|
|
150455
|
+
);
|
|
150456
|
+
|
|
150457
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS git_commits_fts USING fts5(
|
|
150458
|
+
sha UNINDEXED,
|
|
150459
|
+
project_path UNINDEXED,
|
|
150460
|
+
message,
|
|
150461
|
+
tokenize = 'porter unicode61'
|
|
150462
|
+
);
|
|
150463
|
+
|
|
150464
|
+
-- Mirror writes into FTS. We intentionally rebuild FTS rows on
|
|
150465
|
+
-- every INSERT OR REPLACE so amended commits or re-indexed
|
|
150466
|
+
-- messages update cleanly.
|
|
150467
|
+
CREATE TRIGGER IF NOT EXISTS git_commits_fts_insert
|
|
150468
|
+
AFTER INSERT ON git_commits BEGIN
|
|
150469
|
+
DELETE FROM git_commits_fts WHERE sha = NEW.sha;
|
|
150470
|
+
INSERT INTO git_commits_fts(sha, project_path, message)
|
|
150471
|
+
VALUES (NEW.sha, NEW.project_path, NEW.message);
|
|
150472
|
+
END;
|
|
150473
|
+
|
|
150474
|
+
CREATE TRIGGER IF NOT EXISTS git_commits_fts_delete
|
|
150475
|
+
AFTER DELETE ON git_commits BEGIN
|
|
150476
|
+
DELETE FROM git_commits_fts WHERE sha = OLD.sha;
|
|
150477
|
+
END;
|
|
150478
|
+
|
|
150479
|
+
CREATE TRIGGER IF NOT EXISTS git_commits_fts_update
|
|
150480
|
+
AFTER UPDATE OF message, project_path ON git_commits BEGIN
|
|
150481
|
+
DELETE FROM git_commits_fts WHERE sha = OLD.sha;
|
|
150482
|
+
INSERT INTO git_commits_fts(sha, project_path, message)
|
|
150483
|
+
VALUES (NEW.sha, NEW.project_path, NEW.message);
|
|
150484
|
+
END;
|
|
150485
|
+
`);
|
|
150486
|
+
}
|
|
150230
150487
|
}
|
|
150231
150488
|
];
|
|
150232
150489
|
});
|
|
@@ -150449,7 +150706,8 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
150449
150706
|
historian_last_failure_at INTEGER DEFAULT NULL,
|
|
150450
150707
|
system_prompt_hash TEXT DEFAULT '',
|
|
150451
150708
|
memory_block_cache TEXT DEFAULT '',
|
|
150452
|
-
memory_block_count INTEGER DEFAULT 0
|
|
150709
|
+
memory_block_count INTEGER DEFAULT 0,
|
|
150710
|
+
memory_block_ids TEXT DEFAULT ''
|
|
150453
150711
|
);
|
|
150454
150712
|
|
|
150455
150713
|
CREATE INDEX IF NOT EXISTS idx_tags_session_tag_number ON tags(session_id, tag_number);
|
|
@@ -150500,6 +150758,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
150500
150758
|
ensureColumn(db, "session_meta", "note_nudge_trigger_message_id", "TEXT DEFAULT ''");
|
|
150501
150759
|
ensureColumn(db, "session_meta", "note_nudge_sticky_text", "TEXT DEFAULT ''");
|
|
150502
150760
|
ensureColumn(db, "session_meta", "note_nudge_sticky_message_id", "TEXT DEFAULT ''");
|
|
150761
|
+
ensureColumn(db, "session_meta", "note_last_read_at", "INTEGER DEFAULT 0");
|
|
150503
150762
|
ensureColumn(db, "session_meta", "times_execute_threshold_reached", "INTEGER DEFAULT 0");
|
|
150504
150763
|
ensureColumn(db, "session_meta", "compartment_in_progress", "INTEGER DEFAULT 0");
|
|
150505
150764
|
ensureColumn(db, "session_meta", "historian_failure_count", "INTEGER DEFAULT 0");
|
|
@@ -150513,6 +150772,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
150513
150772
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
150514
150773
|
ensureColumn(db, "session_meta", "memory_block_cache", "TEXT DEFAULT ''");
|
|
150515
150774
|
ensureColumn(db, "session_meta", "memory_block_count", "INTEGER DEFAULT 0");
|
|
150775
|
+
ensureColumn(db, "session_meta", "memory_block_ids", "TEXT DEFAULT ''");
|
|
150516
150776
|
ensureColumn(db, "dream_queue", "retry_count", "INTEGER DEFAULT 0");
|
|
150517
150777
|
ensureColumn(db, "tags", "reasoning_byte_size", "INTEGER DEFAULT 0");
|
|
150518
150778
|
ensureColumn(db, "tags", "drop_mode", "TEXT DEFAULT 'full'");
|
|
@@ -150525,8 +150785,16 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
150525
150785
|
ensureColumn(db, "session_meta", "tool_call_tokens", "INTEGER DEFAULT 0");
|
|
150526
150786
|
ensureColumn(db, "session_meta", "recomp_partial_range_start", "INTEGER DEFAULT 0");
|
|
150527
150787
|
ensureColumn(db, "session_meta", "recomp_partial_range_end", "INTEGER DEFAULT 0");
|
|
150788
|
+
ensureColumn(db, "session_meta", "detected_context_limit", "INTEGER DEFAULT 0");
|
|
150789
|
+
ensureColumn(db, "session_meta", "needs_emergency_recovery", "INTEGER DEFAULT 0");
|
|
150528
150790
|
healNullTextColumns(db);
|
|
150529
150791
|
healNullIntegerColumns(db);
|
|
150792
|
+
healMissingMemoryBlockIds(db);
|
|
150793
|
+
}
|
|
150794
|
+
function healMissingMemoryBlockIds(db) {
|
|
150795
|
+
try {
|
|
150796
|
+
db.prepare("UPDATE session_meta SET memory_block_cache = '' WHERE memory_block_cache != '' AND (memory_block_ids IS NULL OR memory_block_ids = '') AND memory_block_count > 0").run();
|
|
150797
|
+
} catch {}
|
|
150530
150798
|
}
|
|
150531
150799
|
function healNullTextColumns(db) {
|
|
150532
150800
|
const columns = [
|
|
@@ -150543,6 +150811,7 @@ function healNullTextColumns(db) {
|
|
|
150543
150811
|
["system_prompt_hash", ""],
|
|
150544
150812
|
["stripped_placeholder_ids", ""],
|
|
150545
150813
|
["memory_block_cache", ""],
|
|
150814
|
+
["memory_block_ids", ""],
|
|
150546
150815
|
["compaction_marker_state", ""],
|
|
150547
150816
|
["key_files", ""]
|
|
150548
150817
|
];
|
|
@@ -150802,6 +151071,9 @@ function setPersistedReasoningWatermark(db, sessionId, tagNumber) {
|
|
|
150802
151071
|
ensureSessionMetaRow(db, sessionId);
|
|
150803
151072
|
db.prepare("UPDATE session_meta SET cleared_reasoning_through_tag = ? WHERE session_id = ?").run(tagNumber, sessionId);
|
|
150804
151073
|
}
|
|
151074
|
+
function clearPersistedReasoningWatermark(db, sessionId) {
|
|
151075
|
+
setPersistedReasoningWatermark(db, sessionId, 0);
|
|
151076
|
+
}
|
|
150805
151077
|
function getPersistedNudgePlacement(db, sessionId) {
|
|
150806
151078
|
const result = db.prepare("SELECT nudge_anchor_message_id, nudge_anchor_text FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
150807
151079
|
if (!isPersistedNudgePlacementRow(result)) {
|
|
@@ -150879,6 +151151,23 @@ function setPersistedDeliveredNoteNudge(db, sessionId, text, messageId = "") {
|
|
|
150879
151151
|
function clearPersistedNoteNudge(db, sessionId) {
|
|
150880
151152
|
db.prepare("UPDATE session_meta SET note_nudge_trigger_pending = 0, note_nudge_trigger_message_id = '', note_nudge_sticky_text = '', note_nudge_sticky_message_id = '' WHERE session_id = ?").run(sessionId);
|
|
150881
151153
|
}
|
|
151154
|
+
function getNoteLastReadAt(db, sessionId) {
|
|
151155
|
+
try {
|
|
151156
|
+
const result = db.prepare("SELECT note_last_read_at FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
151157
|
+
if (!result || typeof result !== "object")
|
|
151158
|
+
return 0;
|
|
151159
|
+
const value = result.note_last_read_at;
|
|
151160
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
151161
|
+
} catch {
|
|
151162
|
+
return 0;
|
|
151163
|
+
}
|
|
151164
|
+
}
|
|
151165
|
+
function setNoteLastReadAt(db, sessionId, at = Date.now()) {
|
|
151166
|
+
db.transaction(() => {
|
|
151167
|
+
ensureSessionMetaRow(db, sessionId);
|
|
151168
|
+
db.prepare("UPDATE session_meta SET note_last_read_at = ? WHERE session_id = ?").run(at, sessionId);
|
|
151169
|
+
})();
|
|
151170
|
+
}
|
|
150882
151171
|
function getHistorianFailureState(db, sessionId) {
|
|
150883
151172
|
const result = db.prepare("SELECT historian_failure_count, historian_last_error, historian_last_failure_at FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
150884
151173
|
if (!isPersistedHistorianFailureRow(result)) {
|
|
@@ -150903,6 +151192,37 @@ function clearHistorianFailureState(db, sessionId) {
|
|
|
150903
151192
|
db.prepare("UPDATE session_meta SET historian_failure_count = 0, historian_last_error = NULL, historian_last_failure_at = NULL WHERE session_id = ?").run(sessionId);
|
|
150904
151193
|
})();
|
|
150905
151194
|
}
|
|
151195
|
+
function getOverflowState(db, sessionId) {
|
|
151196
|
+
const result = db.prepare("SELECT detected_context_limit, needs_emergency_recovery FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
151197
|
+
if (!result) {
|
|
151198
|
+
return { detectedContextLimit: 0, needsEmergencyRecovery: false };
|
|
151199
|
+
}
|
|
151200
|
+
const limit = typeof result.detected_context_limit === "number" && result.detected_context_limit > 0 ? result.detected_context_limit : 0;
|
|
151201
|
+
const needs = typeof result.needs_emergency_recovery === "number" && result.needs_emergency_recovery > 0;
|
|
151202
|
+
return { detectedContextLimit: limit, needsEmergencyRecovery: needs };
|
|
151203
|
+
}
|
|
151204
|
+
function recordOverflowDetected(db, sessionId, reportedLimit) {
|
|
151205
|
+
db.transaction(() => {
|
|
151206
|
+
ensureSessionMetaRow(db, sessionId);
|
|
151207
|
+
if (typeof reportedLimit === "number" && reportedLimit > 0) {
|
|
151208
|
+
db.prepare("UPDATE session_meta SET detected_context_limit = ?, needs_emergency_recovery = 1 WHERE session_id = ?").run(reportedLimit, sessionId);
|
|
151209
|
+
} else {
|
|
151210
|
+
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 1 WHERE session_id = ?").run(sessionId);
|
|
151211
|
+
}
|
|
151212
|
+
})();
|
|
151213
|
+
}
|
|
151214
|
+
function clearEmergencyRecovery(db, sessionId) {
|
|
151215
|
+
db.transaction(() => {
|
|
151216
|
+
ensureSessionMetaRow(db, sessionId);
|
|
151217
|
+
db.prepare("UPDATE session_meta SET needs_emergency_recovery = 0 WHERE session_id = ?").run(sessionId);
|
|
151218
|
+
})();
|
|
151219
|
+
}
|
|
151220
|
+
function clearDetectedContextLimit(db, sessionId) {
|
|
151221
|
+
db.transaction(() => {
|
|
151222
|
+
ensureSessionMetaRow(db, sessionId);
|
|
151223
|
+
db.prepare("UPDATE session_meta SET detected_context_limit = 0 WHERE session_id = ?").run(sessionId);
|
|
151224
|
+
})();
|
|
151225
|
+
}
|
|
150906
151226
|
function getPersistedCompactionMarkerState(db, sessionId) {
|
|
150907
151227
|
const row = db.prepare("SELECT compaction_marker_state FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
150908
151228
|
const raw = row?.compaction_marker_state;
|
|
@@ -151308,8 +151628,33 @@ function resolveLimit(limit) {
|
|
|
151308
151628
|
return limit.context;
|
|
151309
151629
|
return;
|
|
151310
151630
|
}
|
|
151311
|
-
function
|
|
151312
|
-
|
|
151631
|
+
function resolveInterleavedField(interleaved) {
|
|
151632
|
+
if (interleaved && typeof interleaved === "object" && typeof interleaved.field === "string" && interleaved.field.length > 0) {
|
|
151633
|
+
return interleaved.field;
|
|
151634
|
+
}
|
|
151635
|
+
return;
|
|
151636
|
+
}
|
|
151637
|
+
function setCachedModelMetadata(cache, key, model) {
|
|
151638
|
+
const limit = resolveLimit(model?.limit);
|
|
151639
|
+
const interleavedField = resolveInterleavedField(model?.capabilities?.interleaved) ?? resolveInterleavedField(model?.interleaved);
|
|
151640
|
+
if (limit === undefined && interleavedField === undefined) {
|
|
151641
|
+
return;
|
|
151642
|
+
}
|
|
151643
|
+
const value = {};
|
|
151644
|
+
if (limit !== undefined)
|
|
151645
|
+
value.limit = limit;
|
|
151646
|
+
if (interleavedField !== undefined)
|
|
151647
|
+
value.interleavedField = interleavedField;
|
|
151648
|
+
cache.set(key, value);
|
|
151649
|
+
const modes = model?.experimental?.modes;
|
|
151650
|
+
if (modes && typeof modes === "object") {
|
|
151651
|
+
for (const mode of Object.keys(modes)) {
|
|
151652
|
+
cache.set(`${key}-${mode}`, value);
|
|
151653
|
+
}
|
|
151654
|
+
}
|
|
151655
|
+
}
|
|
151656
|
+
function loadModelsDevMetadataFromFile() {
|
|
151657
|
+
const metadata = new Map;
|
|
151313
151658
|
const modelsJsonPath = getModelsJsonPath();
|
|
151314
151659
|
let fileFound = false;
|
|
151315
151660
|
try {
|
|
@@ -151321,16 +151666,7 @@ function loadModelsDevLimitsFromFile() {
|
|
|
151321
151666
|
if (!provider2?.models || typeof provider2.models !== "object")
|
|
151322
151667
|
continue;
|
|
151323
151668
|
for (const [modelId, model] of Object.entries(provider2.models)) {
|
|
151324
|
-
|
|
151325
|
-
if (typeof effective === "number" && effective > 0) {
|
|
151326
|
-
limits.set(`${providerId}/${modelId}`, effective);
|
|
151327
|
-
const modes = model?.experimental?.modes;
|
|
151328
|
-
if (modes && typeof modes === "object") {
|
|
151329
|
-
for (const mode of Object.keys(modes)) {
|
|
151330
|
-
limits.set(`${providerId}/${modelId}-${mode}`, effective);
|
|
151331
|
-
}
|
|
151332
|
-
}
|
|
151333
|
-
}
|
|
151669
|
+
setCachedModelMetadata(metadata, `${providerId}/${modelId}`, model);
|
|
151334
151670
|
}
|
|
151335
151671
|
}
|
|
151336
151672
|
}
|
|
@@ -151348,10 +151684,7 @@ function loadModelsDevLimitsFromFile() {
|
|
|
151348
151684
|
if (!provider2?.models || typeof provider2.models !== "object")
|
|
151349
151685
|
continue;
|
|
151350
151686
|
for (const [modelId, model] of Object.entries(provider2.models)) {
|
|
151351
|
-
|
|
151352
|
-
if (typeof effective === "number" && effective > 0) {
|
|
151353
|
-
limits.set(`${providerId}/${modelId}`, effective);
|
|
151354
|
-
}
|
|
151687
|
+
setCachedModelMetadata(metadata, `${providerId}/${modelId}`, model);
|
|
151355
151688
|
}
|
|
151356
151689
|
}
|
|
151357
151690
|
}
|
|
@@ -151359,8 +151692,8 @@ function loadModelsDevLimitsFromFile() {
|
|
|
151359
151692
|
} catch (error48) {
|
|
151360
151693
|
sessionLog("global", "models-dev-cache: failed to read opencode config for custom models:", error48 instanceof Error ? error48.message : String(error48));
|
|
151361
151694
|
}
|
|
151362
|
-
sessionLog("global", `models-dev-cache: file-layer loaded ${
|
|
151363
|
-
return
|
|
151695
|
+
sessionLog("global", `models-dev-cache: file-layer loaded ${metadata.size} model metadata entries (modelsJsonPath=${modelsJsonPath}, found=${fileFound})`);
|
|
151696
|
+
return metadata;
|
|
151364
151697
|
}
|
|
151365
151698
|
async function refreshModelLimitsFromApi(client) {
|
|
151366
151699
|
try {
|
|
@@ -151377,17 +151710,14 @@ async function refreshModelLimitsFromApi(client) {
|
|
|
151377
151710
|
if (!p?.id || !p.models || typeof p.models !== "object")
|
|
151378
151711
|
continue;
|
|
151379
151712
|
for (const [modelId, model] of Object.entries(p.models)) {
|
|
151380
|
-
|
|
151381
|
-
if (typeof effective === "number" && effective > 0) {
|
|
151382
|
-
map2.set(`${p.id}/${modelId}`, effective);
|
|
151383
|
-
}
|
|
151713
|
+
setCachedModelMetadata(map2, `${p.id}/${modelId}`, model);
|
|
151384
151714
|
}
|
|
151385
151715
|
}
|
|
151386
151716
|
const previousSize = apiCache?.size ?? null;
|
|
151387
151717
|
apiCache = map2;
|
|
151388
151718
|
apiLoadedAt = Date.now();
|
|
151389
151719
|
if (previousSize === null || previousSize !== map2.size) {
|
|
151390
|
-
sessionLog("global", `models-dev-cache: API layer loaded ${map2.size} model
|
|
151720
|
+
sessionLog("global", `models-dev-cache: API layer loaded ${map2.size} model metadata entries${previousSize !== null ? ` (was ${previousSize})` : ""}`);
|
|
151391
151721
|
}
|
|
151392
151722
|
} catch (error48) {
|
|
151393
151723
|
sessionLog("global", "models-dev-cache: API refresh failed:", error48 instanceof Error ? error48.message : String(error48));
|
|
@@ -151396,16 +151726,32 @@ async function refreshModelLimitsFromApi(client) {
|
|
|
151396
151726
|
function getModelsDevContextLimit(providerID, modelID) {
|
|
151397
151727
|
const key = `${providerID}/${modelID}`;
|
|
151398
151728
|
if (apiCache) {
|
|
151399
|
-
const fromApi = apiCache.get(key);
|
|
151729
|
+
const fromApi = apiCache.get(key)?.limit;
|
|
151400
151730
|
if (typeof fromApi === "number")
|
|
151401
151731
|
return fromApi;
|
|
151402
151732
|
}
|
|
151403
151733
|
const now = Date.now();
|
|
151404
151734
|
if (!fileCache || now - fileLastAttempt > RELOAD_INTERVAL_MS) {
|
|
151405
151735
|
fileLastAttempt = now;
|
|
151406
|
-
fileCache =
|
|
151736
|
+
fileCache = loadModelsDevMetadataFromFile();
|
|
151737
|
+
}
|
|
151738
|
+
return fileCache.get(key)?.limit;
|
|
151739
|
+
}
|
|
151740
|
+
function getModelsDevInterleavedField(providerID, modelID) {
|
|
151741
|
+
const key = `${providerID}/${modelID}`;
|
|
151742
|
+
if (apiCache) {
|
|
151743
|
+
const fromApi = apiCache.get(key)?.interleavedField;
|
|
151744
|
+
if (typeof fromApi === "string" && fromApi.length > 0) {
|
|
151745
|
+
return fromApi;
|
|
151746
|
+
}
|
|
151747
|
+
}
|
|
151748
|
+
const now = Date.now();
|
|
151749
|
+
if (!fileCache || now - fileLastAttempt > RELOAD_INTERVAL_MS) {
|
|
151750
|
+
fileLastAttempt = now;
|
|
151751
|
+
fileCache = loadModelsDevMetadataFromFile();
|
|
151407
151752
|
}
|
|
151408
|
-
|
|
151753
|
+
const fromFile = fileCache.get(key)?.interleavedField;
|
|
151754
|
+
return typeof fromFile === "string" && fromFile.length > 0 ? fromFile : undefined;
|
|
151409
151755
|
}
|
|
151410
151756
|
var RELOAD_INTERVAL_MS, apiCache = null, apiLoadedAt = 0, fileCache = null, fileLastAttempt = 0;
|
|
151411
151757
|
var init_models_dev_cache = __esm(() => {
|
|
@@ -151413,45 +151759,6 @@ var init_models_dev_cache = __esm(() => {
|
|
|
151413
151759
|
RELOAD_INTERVAL_MS = 5 * 60 * 1000;
|
|
151414
151760
|
});
|
|
151415
151761
|
|
|
151416
|
-
// src/features/magic-context/memory/project-identity.ts
|
|
151417
|
-
import { execSync } from "child_process";
|
|
151418
|
-
import path3 from "path";
|
|
151419
|
-
function getRootCommitHash(directory) {
|
|
151420
|
-
try {
|
|
151421
|
-
const hash2 = execSync("git rev-list --max-parents=0 HEAD", {
|
|
151422
|
-
cwd: directory,
|
|
151423
|
-
encoding: "utf-8",
|
|
151424
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
151425
|
-
timeout: GIT_TIMEOUT_MS
|
|
151426
|
-
}).trim();
|
|
151427
|
-
const firstLine = hash2.split(`
|
|
151428
|
-
`)[0]?.trim();
|
|
151429
|
-
return firstLine && firstLine.length >= 7 ? firstLine : undefined;
|
|
151430
|
-
} catch {
|
|
151431
|
-
return;
|
|
151432
|
-
}
|
|
151433
|
-
}
|
|
151434
|
-
function directoryFallback(directory) {
|
|
151435
|
-
const canonical = path3.resolve(directory);
|
|
151436
|
-
const hash2 = Bun.hash(canonical).toString(16).slice(0, 12);
|
|
151437
|
-
return `dir:${hash2}`;
|
|
151438
|
-
}
|
|
151439
|
-
function resolveProjectIdentity(directory) {
|
|
151440
|
-
const resolved = path3.resolve(directory);
|
|
151441
|
-
const cached2 = resolvedCache.get(resolved);
|
|
151442
|
-
if (cached2 !== undefined) {
|
|
151443
|
-
return cached2;
|
|
151444
|
-
}
|
|
151445
|
-
const rootHash = getRootCommitHash(resolved);
|
|
151446
|
-
const identity = rootHash ? `git:${rootHash}` : directoryFallback(resolved);
|
|
151447
|
-
resolvedCache.set(resolved, identity);
|
|
151448
|
-
return identity;
|
|
151449
|
-
}
|
|
151450
|
-
var GIT_TIMEOUT_MS = 5000, resolvedCache;
|
|
151451
|
-
var init_project_identity = __esm(() => {
|
|
151452
|
-
resolvedCache = new Map;
|
|
151453
|
-
});
|
|
151454
|
-
|
|
151455
151762
|
// src/shared/rpc-notifications.ts
|
|
151456
151763
|
var exports_rpc_notifications = {};
|
|
151457
151764
|
__export(exports_rpc_notifications, {
|
|
@@ -152141,6 +152448,25 @@ var init_temporal_awareness = __esm(() => {
|
|
|
152141
152448
|
function clearInjectionCache(sessionId) {
|
|
152142
152449
|
injectionCache.delete(sessionId);
|
|
152143
152450
|
}
|
|
152451
|
+
function getVisibleMemoryIds(db, sessionId) {
|
|
152452
|
+
try {
|
|
152453
|
+
const row = db.prepare("SELECT memory_block_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
152454
|
+
if (!row?.memory_block_ids)
|
|
152455
|
+
return null;
|
|
152456
|
+
const parsed = JSON.parse(row.memory_block_ids);
|
|
152457
|
+
if (!Array.isArray(parsed))
|
|
152458
|
+
return null;
|
|
152459
|
+
const ids = new Set;
|
|
152460
|
+
for (const value of parsed) {
|
|
152461
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
152462
|
+
ids.add(value);
|
|
152463
|
+
}
|
|
152464
|
+
}
|
|
152465
|
+
return ids.size > 0 ? ids : null;
|
|
152466
|
+
} catch {
|
|
152467
|
+
return null;
|
|
152468
|
+
}
|
|
152469
|
+
}
|
|
152144
152470
|
function renderMemoryBlock(memories) {
|
|
152145
152471
|
const byCategory = new Map;
|
|
152146
152472
|
for (const m of memories) {
|
|
@@ -152236,8 +152562,9 @@ function prepareCompartmentInjection(db, sessionId, messages, isCacheBusting, pr
|
|
|
152236
152562
|
}
|
|
152237
152563
|
memoryCount = memories.length;
|
|
152238
152564
|
memoryBlock = renderMemoryBlock(memories) ?? undefined;
|
|
152565
|
+
const renderedIds = memories.map((m) => m.id);
|
|
152239
152566
|
try {
|
|
152240
|
-
db.prepare("UPDATE session_meta SET memory_block_cache = ?, memory_block_count = ? WHERE session_id = ?").run(memoryBlock ?? "", memoryCount, sessionId);
|
|
152567
|
+
db.prepare("UPDATE session_meta SET memory_block_cache = ?, memory_block_count = ?, memory_block_ids = ? WHERE session_id = ?").run(memoryBlock ?? "", memoryCount, JSON.stringify(renderedIds), sessionId);
|
|
152241
152568
|
} catch (error48) {
|
|
152242
152569
|
const code = error48?.code;
|
|
152243
152570
|
if (code === "SQLITE_BUSY") {
|
|
@@ -152614,6 +152941,7 @@ async function executePartialRecompInternal(deps, range) {
|
|
|
152614
152941
|
setRecompPartialRange(db, sessionId, null);
|
|
152615
152942
|
clearCompressionDepthRange(db, sessionId, snapStart, snapEnd);
|
|
152616
152943
|
clearInjectionCache(sessionId);
|
|
152944
|
+
deps.onInjectionCacheCleared?.(sessionId);
|
|
152617
152945
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
152618
152946
|
return { compartmentCount: merged.length, lastEndMessage: lastEnd };
|
|
152619
152947
|
};
|
|
@@ -153006,6 +153334,8 @@ var init_compaction_marker = __esm(() => {
|
|
|
153006
153334
|
});
|
|
153007
153335
|
|
|
153008
153336
|
// src/hooks/magic-context/compaction-marker-manager.ts
|
|
153337
|
+
import { Database as SqliteDb } from "bun:sqlite";
|
|
153338
|
+
import { join as join14 } from "path";
|
|
153009
153339
|
function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, directory) {
|
|
153010
153340
|
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
153011
153341
|
if (existing) {
|
|
@@ -153047,10 +153377,63 @@ function removeCompactionMarkerForSession(db, sessionId) {
|
|
|
153047
153377
|
}
|
|
153048
153378
|
}
|
|
153049
153379
|
}
|
|
153380
|
+
function checkCompactionMarkerConsistency(db) {
|
|
153381
|
+
const opencodeDbPath = join14(getDataDir(), "opencode", "opencode.db");
|
|
153382
|
+
let opencodeDb;
|
|
153383
|
+
try {
|
|
153384
|
+
opencodeDb = new SqliteDb(opencodeDbPath, { readonly: true });
|
|
153385
|
+
} catch (error48) {
|
|
153386
|
+
log(`[magic-context] compaction-marker consistency check skipped: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
153387
|
+
return;
|
|
153388
|
+
}
|
|
153389
|
+
try {
|
|
153390
|
+
const persistedRows = db.prepare("SELECT session_id, compaction_marker_state FROM session_meta WHERE compaction_marker_state IS NOT NULL AND compaction_marker_state != ''").all();
|
|
153391
|
+
if (persistedRows.length === 0)
|
|
153392
|
+
return;
|
|
153393
|
+
const checkMessage = opencodeDb.prepare("SELECT 1 FROM message WHERE id = ? LIMIT 1");
|
|
153394
|
+
const checkPart = opencodeDb.prepare("SELECT 1 FROM part WHERE id = ? LIMIT 1");
|
|
153395
|
+
let reconciledCount = 0;
|
|
153396
|
+
for (const row of persistedRows) {
|
|
153397
|
+
const state = getPersistedCompactionMarkerState(db, row.session_id);
|
|
153398
|
+
if (!state)
|
|
153399
|
+
continue;
|
|
153400
|
+
const boundaryExists = checkMessage.get(state.boundaryMessageId) !== null;
|
|
153401
|
+
const summaryMessageExists = checkMessage.get(state.summaryMessageId) !== null;
|
|
153402
|
+
const compactionPartExists = checkPart.get(state.compactionPartId) !== null;
|
|
153403
|
+
const summaryPartExists = checkPart.get(state.summaryPartId) !== null;
|
|
153404
|
+
const allPresent = boundaryExists && summaryMessageExists && compactionPartExists && summaryPartExists;
|
|
153405
|
+
if (allPresent)
|
|
153406
|
+
continue;
|
|
153407
|
+
let removedOk = false;
|
|
153408
|
+
try {
|
|
153409
|
+
removedOk = removeCompactionMarker(state);
|
|
153410
|
+
} catch (error48) {
|
|
153411
|
+
sessionLog(row.session_id, "compaction-marker consistency: partial cleanup of half-written marker failed:", error48);
|
|
153412
|
+
}
|
|
153413
|
+
if (removedOk) {
|
|
153414
|
+
setPersistedCompactionMarkerState(db, row.session_id, null);
|
|
153415
|
+
sessionLog(row.session_id, `compaction-marker consistency: cleared orphaned state (boundary=${boundaryExists} summary=${summaryMessageExists} cPart=${compactionPartExists} sPart=${summaryPartExists}); next publication will re-inject`);
|
|
153416
|
+
reconciledCount++;
|
|
153417
|
+
} else {
|
|
153418
|
+
sessionLog(row.session_id, `compaction-marker consistency: cleanup failed for orphaned state (boundary=${boundaryExists} summary=${summaryMessageExists} cPart=${compactionPartExists} sPart=${summaryPartExists}); will retry on next startup`);
|
|
153419
|
+
}
|
|
153420
|
+
}
|
|
153421
|
+
if (reconciledCount > 0) {
|
|
153422
|
+
log(`[magic-context] compaction-marker consistency: reconciled ${reconciledCount} session(s) with orphaned marker state at startup`);
|
|
153423
|
+
}
|
|
153424
|
+
} catch (error48) {
|
|
153425
|
+
log(`[magic-context] compaction-marker consistency check failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
153426
|
+
} finally {
|
|
153427
|
+
try {
|
|
153428
|
+
opencodeDb.close(false);
|
|
153429
|
+
} catch {}
|
|
153430
|
+
}
|
|
153431
|
+
}
|
|
153050
153432
|
var MARKER_SUMMARY_TEXT = "[Compacted by magic-context \u2014 session history is managed by the plugin]";
|
|
153051
153433
|
var init_compaction_marker_manager = __esm(() => {
|
|
153052
153434
|
init_compaction_marker();
|
|
153053
153435
|
init_storage_meta_persisted();
|
|
153436
|
+
init_data_path();
|
|
153054
153437
|
init_logger();
|
|
153055
153438
|
});
|
|
153056
153439
|
|
|
@@ -153084,23 +153467,42 @@ function peekNoteNudgeText(db, sessionId, currentUserMessageId, projectIdentity)
|
|
|
153084
153467
|
return null;
|
|
153085
153468
|
}
|
|
153086
153469
|
const notes = getSessionNotes(db, sessionId);
|
|
153087
|
-
const
|
|
153088
|
-
const totalCount = notes.length +
|
|
153470
|
+
const readySmartNotes = projectIdentity ? getReadySmartNotes(db, projectIdentity) : [];
|
|
153471
|
+
const totalCount = notes.length + readySmartNotes.length;
|
|
153089
153472
|
if (totalCount === 0) {
|
|
153090
153473
|
sessionLog(sessionId, "note-nudge: triggerPending but no notes found, skipping");
|
|
153091
153474
|
clearPersistedNoteNudge(db, sessionId);
|
|
153092
153475
|
return null;
|
|
153093
153476
|
}
|
|
153477
|
+
const lastReadAt = getNoteLastReadAt(db, sessionId);
|
|
153478
|
+
if (lastReadAt > 0) {
|
|
153479
|
+
const mostRecentNoteActivity = maxNoteActivityTime([...notes, ...readySmartNotes]);
|
|
153480
|
+
if (mostRecentNoteActivity > 0 && lastReadAt > mostRecentNoteActivity) {
|
|
153481
|
+
sessionLog(sessionId, `note-nudge: suppressing \u2014 agent already ran ctx_note(read) at ${new Date(lastReadAt).toISOString()}, no new notes since ${new Date(mostRecentNoteActivity).toISOString()}`);
|
|
153482
|
+
clearPersistedNoteNudge(db, sessionId);
|
|
153483
|
+
return null;
|
|
153484
|
+
}
|
|
153485
|
+
}
|
|
153094
153486
|
const parts = [];
|
|
153095
153487
|
if (notes.length > 0) {
|
|
153096
153488
|
parts.push(`${notes.length} deferred note${notes.length === 1 ? "" : "s"}`);
|
|
153097
153489
|
}
|
|
153098
|
-
if (
|
|
153099
|
-
parts.push(`${
|
|
153490
|
+
if (readySmartNotes.length > 0) {
|
|
153491
|
+
parts.push(`${readySmartNotes.length} ready smart note${readySmartNotes.length === 1 ? "" : "s"}`);
|
|
153100
153492
|
}
|
|
153101
153493
|
sessionLog(sessionId, `note-nudge: delivering nudge for ${parts.join(" and ")}`);
|
|
153102
153494
|
return `You have ${parts.join(" and ")}. Review with ctx_note read \u2014 some may be actionable now.`;
|
|
153103
153495
|
}
|
|
153496
|
+
function maxNoteActivityTime(notes) {
|
|
153497
|
+
let max = 0;
|
|
153498
|
+
for (const note of notes) {
|
|
153499
|
+
if (note.updatedAt > max)
|
|
153500
|
+
max = note.updatedAt;
|
|
153501
|
+
if (note.readyAt !== null && note.readyAt > max)
|
|
153502
|
+
max = note.readyAt;
|
|
153503
|
+
}
|
|
153504
|
+
return max;
|
|
153505
|
+
}
|
|
153104
153506
|
function markNoteNudgeDelivered(db, sessionId, text, messageId) {
|
|
153105
153507
|
setPersistedDeliveredNoteNudge(db, sessionId, messageId ? text : "", messageId ?? "");
|
|
153106
153508
|
recordNoteNudgeDeliveryTime(sessionId);
|
|
@@ -153216,40 +153618,6 @@ var init_promotion = __esm(() => {
|
|
|
153216
153618
|
init_storage_memory();
|
|
153217
153619
|
init_storage_memory_embeddings();
|
|
153218
153620
|
});
|
|
153219
|
-
|
|
153220
|
-
// src/features/magic-context/memory/storage-memory-fts.ts
|
|
153221
|
-
function getSearchStatement(db) {
|
|
153222
|
-
let stmt = searchStatements.get(db);
|
|
153223
|
-
if (!stmt) {
|
|
153224
|
-
const selectColumns = Object.entries(COLUMN_MAP).map(([property, column]) => `memories.${column} AS ${property}`).join(", ");
|
|
153225
|
-
stmt = db.prepare(`SELECT ${selectColumns} FROM memories_fts INNER JOIN memories ON memories.id = memories_fts.rowid WHERE memories.project_path = ? AND memories.status IN ('active', 'permanent') AND (memories.expires_at IS NULL OR memories.expires_at > ?) AND memories_fts MATCH ? ORDER BY bm25(memories_fts), memories.updated_at DESC, memories.id ASC LIMIT ?`);
|
|
153226
|
-
searchStatements.set(db, stmt);
|
|
153227
|
-
}
|
|
153228
|
-
return stmt;
|
|
153229
|
-
}
|
|
153230
|
-
function sanitizeFtsQuery(query) {
|
|
153231
|
-
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
153232
|
-
if (tokens.length === 0)
|
|
153233
|
-
return "";
|
|
153234
|
-
return tokens.map((token) => `"${token.replace(/"/g, '""')}"`).join(" ");
|
|
153235
|
-
}
|
|
153236
|
-
function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT) {
|
|
153237
|
-
const trimmedQuery = query.trim();
|
|
153238
|
-
if (trimmedQuery.length === 0 || limit <= 0) {
|
|
153239
|
-
return [];
|
|
153240
|
-
}
|
|
153241
|
-
const sanitized = sanitizeFtsQuery(trimmedQuery);
|
|
153242
|
-
if (sanitized.length === 0) {
|
|
153243
|
-
return [];
|
|
153244
|
-
}
|
|
153245
|
-
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
153246
|
-
return rows.map(toMemory);
|
|
153247
|
-
}
|
|
153248
|
-
var DEFAULT_SEARCH_LIMIT = 10, searchStatements;
|
|
153249
|
-
var init_storage_memory_fts = __esm(() => {
|
|
153250
|
-
init_storage_memory();
|
|
153251
|
-
searchStatements = new WeakMap;
|
|
153252
|
-
});
|
|
153253
153621
|
// src/features/magic-context/memory/index.ts
|
|
153254
153622
|
var init_memory = __esm(() => {
|
|
153255
153623
|
init_project_identity();
|
|
@@ -154024,8 +154392,10 @@ No new compartments or facts were written. Check the historian model/output and
|
|
|
154024
154392
|
appendCompartments(db, sessionId, newCompartments);
|
|
154025
154393
|
replaceSessionFacts(db, sessionId, validatedPass.facts ?? []);
|
|
154026
154394
|
clearHistorianFailureState(db, sessionId);
|
|
154395
|
+
clearEmergencyRecovery(db, sessionId);
|
|
154027
154396
|
})();
|
|
154028
154397
|
clearInjectionCache(sessionId);
|
|
154398
|
+
deps.onInjectionCacheCleared?.(sessionId);
|
|
154029
154399
|
if (deps.directory) {
|
|
154030
154400
|
promoteSessionFactsToMemory(db, sessionId, resolveProjectIdentity(deps.directory), validatedPass.facts ?? []);
|
|
154031
154401
|
}
|
|
@@ -154129,6 +154499,7 @@ async function executeContextRecompInternal(deps) {
|
|
|
154129
154499
|
return null;
|
|
154130
154500
|
clearCompressionDepth(db, sessionId);
|
|
154131
154501
|
clearInjectionCache(sessionId);
|
|
154502
|
+
deps.onInjectionCacheCleared?.(sessionId);
|
|
154132
154503
|
if (deps.directory) {
|
|
154133
154504
|
promoteSessionFactsToMemory(db, sessionId, resolveProjectIdentity(deps.directory), promoted2.facts);
|
|
154134
154505
|
}
|
|
@@ -154297,6 +154668,7 @@ Nothing was written.`;
|
|
|
154297
154668
|
}
|
|
154298
154669
|
clearCompressionDepth(db, sessionId);
|
|
154299
154670
|
clearInjectionCache(sessionId);
|
|
154671
|
+
deps.onInjectionCacheCleared?.(sessionId);
|
|
154300
154672
|
const finalCompartments = promoted?.compartments ?? candidateCompartments;
|
|
154301
154673
|
const finalFacts = promoted?.facts ?? candidateFacts;
|
|
154302
154674
|
if (deps.directory) {
|
|
@@ -162030,10 +162402,10 @@ var require_stringify = __commonJS((exports, module) => {
|
|
|
162030
162402
|
replacer = null;
|
|
162031
162403
|
indent = EMPTY;
|
|
162032
162404
|
};
|
|
162033
|
-
var
|
|
162405
|
+
var join17 = (one, two, gap) => one ? two ? one + two.trim() + LF + gap : one.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(one, gap)), gap) : two ? two.trimRight() + repeat_line_breaks(Math.max(1, count_trailing_line_breaks(two, gap)), gap) : EMPTY;
|
|
162034
162406
|
var join_content = (inside, value, gap) => {
|
|
162035
162407
|
const comment = process_comments(value, PREFIX_BEFORE, gap + indent, true);
|
|
162036
|
-
return
|
|
162408
|
+
return join17(comment, inside, gap);
|
|
162037
162409
|
};
|
|
162038
162410
|
var stringify_string = (holder, key, value) => {
|
|
162039
162411
|
const raw = get_raw_string_literal(holder, key);
|
|
@@ -162055,13 +162427,13 @@ var require_stringify = __commonJS((exports, module) => {
|
|
|
162055
162427
|
if (i !== 0) {
|
|
162056
162428
|
inside += COMMA;
|
|
162057
162429
|
}
|
|
162058
|
-
const before =
|
|
162430
|
+
const before = join17(after_comma, process_comments(value, BEFORE(i), deeper_gap), deeper_gap);
|
|
162059
162431
|
inside += before || LF + deeper_gap;
|
|
162060
162432
|
inside += stringify(i, value, deeper_gap) || STR_NULL;
|
|
162061
162433
|
inside += process_comments(value, AFTER_VALUE(i), deeper_gap);
|
|
162062
162434
|
after_comma = process_comments(value, AFTER(i), deeper_gap);
|
|
162063
162435
|
}
|
|
162064
|
-
inside +=
|
|
162436
|
+
inside += join17(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
|
|
162065
162437
|
return BRACKET_OPEN + join_content(inside, value, gap) + BRACKET_CLOSE;
|
|
162066
162438
|
};
|
|
162067
162439
|
var object_stringify = (value, gap) => {
|
|
@@ -162082,13 +162454,13 @@ var require_stringify = __commonJS((exports, module) => {
|
|
|
162082
162454
|
inside += COMMA;
|
|
162083
162455
|
}
|
|
162084
162456
|
first = false;
|
|
162085
|
-
const before =
|
|
162457
|
+
const before = join17(after_comma, process_comments(value, BEFORE(key), deeper_gap), deeper_gap);
|
|
162086
162458
|
inside += before || LF + deeper_gap;
|
|
162087
162459
|
inside += quote(key) + process_comments(value, AFTER_PROP(key), deeper_gap) + COLON + process_comments(value, AFTER_COLON(key), deeper_gap) + SPACE + sv + process_comments(value, AFTER_VALUE(key), deeper_gap);
|
|
162088
162460
|
after_comma = process_comments(value, AFTER(key), deeper_gap);
|
|
162089
162461
|
};
|
|
162090
162462
|
keys.forEach(iteratee);
|
|
162091
|
-
inside +=
|
|
162463
|
+
inside += join17(after_comma, process_comments(value, PREFIX_AFTER, deeper_gap), deeper_gap);
|
|
162092
162464
|
return CURLY_BRACKET_OPEN + join_content(inside, value, gap) + CURLY_BRACKET_CLOSE;
|
|
162093
162465
|
};
|
|
162094
162466
|
function stringify(key, holder, gap) {
|
|
@@ -162186,11 +162558,11 @@ __export(exports_tui_config, {
|
|
|
162186
162558
|
ensureTuiPluginEntry: () => ensureTuiPluginEntry
|
|
162187
162559
|
});
|
|
162188
162560
|
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
162189
|
-
import { dirname as dirname3, join as
|
|
162561
|
+
import { dirname as dirname3, join as join17 } from "path";
|
|
162190
162562
|
function resolveTuiConfigPath() {
|
|
162191
162563
|
const configDir = getOpenCodeConfigPaths({ binary: "opencode" }).configDir;
|
|
162192
|
-
const jsoncPath =
|
|
162193
|
-
const jsonPath =
|
|
162564
|
+
const jsoncPath = join17(configDir, "tui.jsonc");
|
|
162565
|
+
const jsonPath = join17(configDir, "tui.json");
|
|
162194
162566
|
if (existsSync8(jsoncPath))
|
|
162195
162567
|
return jsoncPath;
|
|
162196
162568
|
if (existsSync8(jsonPath))
|
|
@@ -162379,15 +162751,75 @@ function redactConfigValue(value) {
|
|
|
162379
162751
|
}
|
|
162380
162752
|
return typeof value;
|
|
162381
162753
|
}
|
|
162754
|
+
function migrateLegacyExperimental(rawConfig, warnings) {
|
|
162755
|
+
const experimental = rawConfig.experimental;
|
|
162756
|
+
if (typeof experimental !== "object" || experimental === null) {
|
|
162757
|
+
return rawConfig;
|
|
162758
|
+
}
|
|
162759
|
+
const exp = experimental;
|
|
162760
|
+
const hasUM = "user_memories" in exp;
|
|
162761
|
+
const hasPKF = "pin_key_files" in exp;
|
|
162762
|
+
if (!hasUM && !hasPKF) {
|
|
162763
|
+
return rawConfig;
|
|
162764
|
+
}
|
|
162765
|
+
const patched = { ...rawConfig };
|
|
162766
|
+
const dreamer = typeof patched.dreamer === "object" && patched.dreamer !== null ? { ...patched.dreamer } : {};
|
|
162767
|
+
const newExperimental = { ...exp };
|
|
162768
|
+
const coerceToObject = (value) => {
|
|
162769
|
+
if (typeof value === "boolean") {
|
|
162770
|
+
return { enabled: value };
|
|
162771
|
+
}
|
|
162772
|
+
if (typeof value === "object" && value !== null) {
|
|
162773
|
+
return { ...value };
|
|
162774
|
+
}
|
|
162775
|
+
return;
|
|
162776
|
+
};
|
|
162777
|
+
if (hasUM) {
|
|
162778
|
+
const oldUM = coerceToObject(exp.user_memories);
|
|
162779
|
+
if (oldUM !== undefined) {
|
|
162780
|
+
if (dreamer.user_memories === undefined) {
|
|
162781
|
+
dreamer.user_memories = oldUM;
|
|
162782
|
+
warnings.push('Migrated "experimental.user_memories" \u2192 "dreamer.user_memories" in-memory (run `doctor` to persist).');
|
|
162783
|
+
} else if (typeof dreamer.user_memories === "object" && dreamer.user_memories !== null) {
|
|
162784
|
+
dreamer.user_memories = {
|
|
162785
|
+
...oldUM,
|
|
162786
|
+
...dreamer.user_memories
|
|
162787
|
+
};
|
|
162788
|
+
}
|
|
162789
|
+
}
|
|
162790
|
+
delete newExperimental.user_memories;
|
|
162791
|
+
}
|
|
162792
|
+
if (hasPKF) {
|
|
162793
|
+
const oldPKF = coerceToObject(exp.pin_key_files);
|
|
162794
|
+
if (oldPKF !== undefined) {
|
|
162795
|
+
if (dreamer.pin_key_files === undefined) {
|
|
162796
|
+
dreamer.pin_key_files = oldPKF;
|
|
162797
|
+
warnings.push('Migrated "experimental.pin_key_files" \u2192 "dreamer.pin_key_files" in-memory (run `doctor` to persist).');
|
|
162798
|
+
} else if (typeof dreamer.pin_key_files === "object" && dreamer.pin_key_files !== null) {
|
|
162799
|
+
dreamer.pin_key_files = {
|
|
162800
|
+
...oldPKF,
|
|
162801
|
+
...dreamer.pin_key_files
|
|
162802
|
+
};
|
|
162803
|
+
}
|
|
162804
|
+
}
|
|
162805
|
+
delete newExperimental.pin_key_files;
|
|
162806
|
+
}
|
|
162807
|
+
patched.experimental = newExperimental;
|
|
162808
|
+
patched.dreamer = dreamer;
|
|
162809
|
+
return patched;
|
|
162810
|
+
}
|
|
162382
162811
|
function parsePluginConfig(rawConfig) {
|
|
162383
|
-
const
|
|
162812
|
+
const preMigrationWarnings = [];
|
|
162813
|
+
const migrated = migrateLegacyExperimental(rawConfig, preMigrationWarnings);
|
|
162814
|
+
const parsed = MagicContextConfigSchema.safeParse(migrated);
|
|
162384
162815
|
const disabledHooks = Array.isArray(rawConfig.disabled_hooks) ? rawConfig.disabled_hooks.filter((value) => typeof value === "string") : undefined;
|
|
162385
162816
|
const command = typeof rawConfig.command === "object" && rawConfig.command !== null ? rawConfig.command : undefined;
|
|
162386
162817
|
if (parsed.success) {
|
|
162387
162818
|
return {
|
|
162388
162819
|
...parsed.data,
|
|
162389
162820
|
disabled_hooks: disabledHooks,
|
|
162390
|
-
command
|
|
162821
|
+
command,
|
|
162822
|
+
...preMigrationWarnings.length > 0 ? { configWarnings: preMigrationWarnings } : {}
|
|
162391
162823
|
};
|
|
162392
162824
|
}
|
|
162393
162825
|
const defaults = MagicContextConfigSchema.parse({});
|
|
@@ -162411,17 +162843,23 @@ function parsePluginConfig(rawConfig) {
|
|
|
162411
162843
|
warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultVal)}.`);
|
|
162412
162844
|
}
|
|
162413
162845
|
}
|
|
162414
|
-
const
|
|
162846
|
+
const retryMigrated = migrateLegacyExperimental(patched, preMigrationWarnings);
|
|
162847
|
+
const retryParsed = MagicContextConfigSchema.safeParse(retryMigrated);
|
|
162415
162848
|
if (retryParsed.success) {
|
|
162416
162849
|
return {
|
|
162417
162850
|
...retryParsed.data,
|
|
162418
162851
|
disabled_hooks: disabledHooks,
|
|
162419
162852
|
command,
|
|
162420
|
-
configWarnings: warnings
|
|
162853
|
+
configWarnings: [...preMigrationWarnings, ...warnings]
|
|
162421
162854
|
};
|
|
162422
162855
|
}
|
|
162423
162856
|
warnings.push("Config recovery failed, using all defaults.");
|
|
162424
|
-
return {
|
|
162857
|
+
return {
|
|
162858
|
+
...defaults,
|
|
162859
|
+
disabled_hooks: disabledHooks,
|
|
162860
|
+
command,
|
|
162861
|
+
configWarnings: [...preMigrationWarnings, ...warnings]
|
|
162862
|
+
};
|
|
162425
162863
|
}
|
|
162426
162864
|
function loadPluginConfig(directory) {
|
|
162427
162865
|
const userDetected = detectConfigFile(getUserConfigBasePath());
|
|
@@ -164199,36 +164637,562 @@ function checkScheduleAndEnqueue(db, schedule) {
|
|
|
164199
164637
|
}
|
|
164200
164638
|
return enqueued;
|
|
164201
164639
|
}
|
|
164640
|
+
// src/features/magic-context/git-commits/git-log-reader.ts
|
|
164641
|
+
init_logger();
|
|
164642
|
+
import { execFile } from "child_process";
|
|
164643
|
+
import { promisify } from "util";
|
|
164644
|
+
var execFileAsync = promisify(execFile);
|
|
164645
|
+
var GIT_TIMEOUT_MS = 1e4;
|
|
164646
|
+
var DEFAULT_MAX_COMMITS = 5000;
|
|
164647
|
+
var RECORD_SEPARATOR = "\x1E";
|
|
164648
|
+
var FIELD_SEPARATOR = "\x1F";
|
|
164649
|
+
async function readGitCommits(directory, options = {}) {
|
|
164650
|
+
const args = [
|
|
164651
|
+
"log",
|
|
164652
|
+
options.branch ?? "HEAD",
|
|
164653
|
+
"--no-merges",
|
|
164654
|
+
`--max-count=${options.maxCommits ?? DEFAULT_MAX_COMMITS}`,
|
|
164655
|
+
`--format=%H${FIELD_SEPARATOR}%s${FIELD_SEPARATOR}%ae${FIELD_SEPARATOR}%ct${FIELD_SEPARATOR}%b${RECORD_SEPARATOR}`
|
|
164656
|
+
];
|
|
164657
|
+
if (options.sinceMs !== undefined && options.sinceMs > 0) {
|
|
164658
|
+
const iso = new Date(options.sinceMs).toISOString();
|
|
164659
|
+
args.push(`--since=${iso}`);
|
|
164660
|
+
}
|
|
164661
|
+
let stdout;
|
|
164662
|
+
try {
|
|
164663
|
+
const result = await execFileAsync("git", args, {
|
|
164664
|
+
cwd: directory,
|
|
164665
|
+
timeout: GIT_TIMEOUT_MS,
|
|
164666
|
+
maxBuffer: 32 * 1024 * 1024,
|
|
164667
|
+
encoding: "utf8"
|
|
164668
|
+
});
|
|
164669
|
+
stdout = result.stdout;
|
|
164670
|
+
} catch (error48) {
|
|
164671
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
164672
|
+
log(`[git-commits] readGitCommits failed at cwd=${directory}: ${message.slice(0, 500)}`);
|
|
164673
|
+
return [];
|
|
164674
|
+
}
|
|
164675
|
+
if (stdout.trim().length === 0) {
|
|
164676
|
+
log(`[git-commits] readGitCommits returned empty stdout at cwd=${directory} (sinceMs=${options.sinceMs ?? "none"} args=${args.slice(0, 4).join(" ")})`);
|
|
164677
|
+
}
|
|
164678
|
+
return parseGitLogOutput(stdout);
|
|
164679
|
+
}
|
|
164680
|
+
function parseGitLogOutput(stdout) {
|
|
164681
|
+
const commits = [];
|
|
164682
|
+
const records = stdout.split(RECORD_SEPARATOR);
|
|
164683
|
+
for (const rawRecord of records) {
|
|
164684
|
+
const record2 = rawRecord.replace(/^\s+/, "");
|
|
164685
|
+
if (!record2)
|
|
164686
|
+
continue;
|
|
164687
|
+
const fields = [];
|
|
164688
|
+
let remaining = record2;
|
|
164689
|
+
for (let i = 0;i < 4; i++) {
|
|
164690
|
+
const idx = remaining.indexOf(FIELD_SEPARATOR);
|
|
164691
|
+
if (idx < 0)
|
|
164692
|
+
break;
|
|
164693
|
+
fields.push(remaining.slice(0, idx));
|
|
164694
|
+
remaining = remaining.slice(idx + FIELD_SEPARATOR.length);
|
|
164695
|
+
}
|
|
164696
|
+
fields.push(remaining);
|
|
164697
|
+
if (fields.length < 5)
|
|
164698
|
+
continue;
|
|
164699
|
+
const sha = fields[0].trim();
|
|
164700
|
+
const subject = fields[1].trim();
|
|
164701
|
+
const author = fields[2].trim();
|
|
164702
|
+
const timeSec = Number.parseInt(fields[3].trim(), 10);
|
|
164703
|
+
const body = fields[4].trim();
|
|
164704
|
+
if (sha.length !== 40 || !Number.isFinite(timeSec) || timeSec <= 0) {
|
|
164705
|
+
continue;
|
|
164706
|
+
}
|
|
164707
|
+
const message = body.length > 0 ? `${subject}
|
|
164708
|
+
|
|
164709
|
+
${body}` : subject;
|
|
164710
|
+
commits.push({
|
|
164711
|
+
sha,
|
|
164712
|
+
shortSha: sha.slice(0, 7),
|
|
164713
|
+
message,
|
|
164714
|
+
author: author.length > 0 ? author : null,
|
|
164715
|
+
committedAtMs: timeSec * 1000
|
|
164716
|
+
});
|
|
164717
|
+
}
|
|
164718
|
+
return commits;
|
|
164719
|
+
}
|
|
164720
|
+
// src/features/magic-context/git-commits/indexer.ts
|
|
164721
|
+
init_logger();
|
|
164722
|
+
init_embedding();
|
|
164723
|
+
|
|
164724
|
+
// src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
|
|
164725
|
+
var saveStatements = new WeakMap;
|
|
164726
|
+
var loadProjectStatements = new WeakMap;
|
|
164727
|
+
var loadUnembeddedStatements = new WeakMap;
|
|
164728
|
+
var countEmbeddedStatements = new WeakMap;
|
|
164729
|
+
var clearProjectStatements = new WeakMap;
|
|
164730
|
+
function getSaveStatement(db) {
|
|
164731
|
+
let stmt = saveStatements.get(db);
|
|
164732
|
+
if (!stmt) {
|
|
164733
|
+
stmt = db.prepare(`INSERT INTO git_commit_embeddings (sha, embedding, model_id, created_at)
|
|
164734
|
+
VALUES (?, ?, ?, ?)
|
|
164735
|
+
ON CONFLICT(sha) DO UPDATE SET
|
|
164736
|
+
embedding = excluded.embedding,
|
|
164737
|
+
model_id = excluded.model_id,
|
|
164738
|
+
created_at = excluded.created_at`);
|
|
164739
|
+
saveStatements.set(db, stmt);
|
|
164740
|
+
}
|
|
164741
|
+
return stmt;
|
|
164742
|
+
}
|
|
164743
|
+
function getLoadProjectStatement(db) {
|
|
164744
|
+
let stmt = loadProjectStatements.get(db);
|
|
164745
|
+
if (!stmt) {
|
|
164746
|
+
stmt = db.prepare(`SELECT e.sha AS sha, e.embedding AS embedding, e.model_id AS model_id
|
|
164747
|
+
FROM git_commit_embeddings e
|
|
164748
|
+
JOIN git_commits c ON c.sha = e.sha
|
|
164749
|
+
WHERE c.project_path = ?`);
|
|
164750
|
+
loadProjectStatements.set(db, stmt);
|
|
164751
|
+
}
|
|
164752
|
+
return stmt;
|
|
164753
|
+
}
|
|
164754
|
+
function getLoadUnembeddedStatement(db) {
|
|
164755
|
+
let stmt = loadUnembeddedStatements.get(db);
|
|
164756
|
+
if (!stmt) {
|
|
164757
|
+
stmt = db.prepare(`SELECT c.sha AS sha, c.message AS message
|
|
164758
|
+
FROM git_commits c
|
|
164759
|
+
LEFT JOIN git_commit_embeddings e ON c.sha = e.sha
|
|
164760
|
+
WHERE c.project_path = ? AND e.sha IS NULL
|
|
164761
|
+
ORDER BY c.committed_at DESC
|
|
164762
|
+
LIMIT ?`);
|
|
164763
|
+
loadUnembeddedStatements.set(db, stmt);
|
|
164764
|
+
}
|
|
164765
|
+
return stmt;
|
|
164766
|
+
}
|
|
164767
|
+
function getCountEmbeddedStatement(db) {
|
|
164768
|
+
let stmt = countEmbeddedStatements.get(db);
|
|
164769
|
+
if (!stmt) {
|
|
164770
|
+
stmt = db.prepare(`SELECT COUNT(*) AS count FROM git_commit_embeddings e
|
|
164771
|
+
JOIN git_commits c ON c.sha = e.sha WHERE c.project_path = ?`);
|
|
164772
|
+
countEmbeddedStatements.set(db, stmt);
|
|
164773
|
+
}
|
|
164774
|
+
return stmt;
|
|
164775
|
+
}
|
|
164776
|
+
function saveCommitEmbedding(db, sha, embedding, modelId) {
|
|
164777
|
+
const bytes = new Uint8Array(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
164778
|
+
getSaveStatement(db).run(sha, bytes, modelId, Date.now());
|
|
164779
|
+
}
|
|
164780
|
+
function loadProjectCommitEmbeddings(db, projectPath) {
|
|
164781
|
+
const rows = getLoadProjectStatement(db).all(projectPath);
|
|
164782
|
+
const map2 = new Map;
|
|
164783
|
+
for (const row of rows) {
|
|
164784
|
+
const buffer2 = row.embedding.buffer.slice(row.embedding.byteOffset, row.embedding.byteOffset + row.embedding.byteLength);
|
|
164785
|
+
map2.set(row.sha, new Float32Array(buffer2));
|
|
164786
|
+
}
|
|
164787
|
+
return map2;
|
|
164788
|
+
}
|
|
164789
|
+
function loadUnembeddedCommits(db, projectPath, limit) {
|
|
164790
|
+
return getLoadUnembeddedStatement(db).all(projectPath, limit);
|
|
164791
|
+
}
|
|
164792
|
+
function countEmbeddedCommits(db, projectPath) {
|
|
164793
|
+
const row = getCountEmbeddedStatement(db).get(projectPath);
|
|
164794
|
+
return row?.count ?? 0;
|
|
164795
|
+
}
|
|
164796
|
+
|
|
164797
|
+
// src/features/magic-context/git-commits/storage-git-commits.ts
|
|
164798
|
+
init_logger();
|
|
164799
|
+
var insertStatements = new WeakMap;
|
|
164800
|
+
var existingShasStatements = new WeakMap;
|
|
164801
|
+
var projectCountStatements = new WeakMap;
|
|
164802
|
+
var evictStatements = new WeakMap;
|
|
164803
|
+
var latestCommitTimeStatements = new WeakMap;
|
|
164804
|
+
function getInsertStatement(db) {
|
|
164805
|
+
let stmt = insertStatements.get(db);
|
|
164806
|
+
if (!stmt) {
|
|
164807
|
+
stmt = db.prepare(`INSERT INTO git_commits (sha, project_path, short_sha, message, author, committed_at, indexed_at)
|
|
164808
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
164809
|
+
ON CONFLICT(sha) DO UPDATE SET
|
|
164810
|
+
project_path = excluded.project_path,
|
|
164811
|
+
short_sha = excluded.short_sha,
|
|
164812
|
+
message = excluded.message,
|
|
164813
|
+
author = excluded.author,
|
|
164814
|
+
committed_at = excluded.committed_at,
|
|
164815
|
+
indexed_at = excluded.indexed_at
|
|
164816
|
+
WHERE git_commits.message != excluded.message`);
|
|
164817
|
+
insertStatements.set(db, stmt);
|
|
164818
|
+
}
|
|
164819
|
+
return stmt;
|
|
164820
|
+
}
|
|
164821
|
+
function getExistingShasStatement(db) {
|
|
164822
|
+
let stmt = existingShasStatements.get(db);
|
|
164823
|
+
if (!stmt) {
|
|
164824
|
+
stmt = db.prepare("SELECT sha FROM git_commits WHERE project_path = ?");
|
|
164825
|
+
existingShasStatements.set(db, stmt);
|
|
164826
|
+
}
|
|
164827
|
+
return stmt;
|
|
164828
|
+
}
|
|
164829
|
+
function getProjectCountStatement(db) {
|
|
164830
|
+
let stmt = projectCountStatements.get(db);
|
|
164831
|
+
if (!stmt) {
|
|
164832
|
+
stmt = db.prepare("SELECT COUNT(*) AS count FROM git_commits WHERE project_path = ?");
|
|
164833
|
+
projectCountStatements.set(db, stmt);
|
|
164834
|
+
}
|
|
164835
|
+
return stmt;
|
|
164836
|
+
}
|
|
164837
|
+
function getLatestCommitTimeStatement(db) {
|
|
164838
|
+
let stmt = latestCommitTimeStatements.get(db);
|
|
164839
|
+
if (!stmt) {
|
|
164840
|
+
stmt = db.prepare("SELECT MAX(committed_at) AS latest FROM git_commits WHERE project_path = ?");
|
|
164841
|
+
latestCommitTimeStatements.set(db, stmt);
|
|
164842
|
+
}
|
|
164843
|
+
return stmt;
|
|
164844
|
+
}
|
|
164845
|
+
function getEvictStatement(db) {
|
|
164846
|
+
let stmt = evictStatements.get(db);
|
|
164847
|
+
if (!stmt) {
|
|
164848
|
+
stmt = db.prepare(`DELETE FROM git_commits
|
|
164849
|
+
WHERE sha IN (
|
|
164850
|
+
SELECT sha FROM git_commits
|
|
164851
|
+
WHERE project_path = ?
|
|
164852
|
+
ORDER BY committed_at ASC
|
|
164853
|
+
LIMIT ?
|
|
164854
|
+
)`);
|
|
164855
|
+
evictStatements.set(db, stmt);
|
|
164856
|
+
}
|
|
164857
|
+
return stmt;
|
|
164858
|
+
}
|
|
164859
|
+
function upsertCommits(db, projectPath, commits) {
|
|
164860
|
+
if (commits.length === 0)
|
|
164861
|
+
return { inserted: 0, updated: 0 };
|
|
164862
|
+
const existing = new Set;
|
|
164863
|
+
for (const row of getExistingShasStatement(db).all(projectPath)) {
|
|
164864
|
+
existing.add(row.sha);
|
|
164865
|
+
}
|
|
164866
|
+
let inserted = 0;
|
|
164867
|
+
let updated = 0;
|
|
164868
|
+
const now = Date.now();
|
|
164869
|
+
const insertStmt = getInsertStatement(db);
|
|
164870
|
+
db.transaction(() => {
|
|
164871
|
+
for (const commit of commits) {
|
|
164872
|
+
const result = insertStmt.run(commit.sha, projectPath, commit.shortSha, commit.message, commit.author, commit.committedAtMs, now);
|
|
164873
|
+
if (result.changes > 0) {
|
|
164874
|
+
if (existing.has(commit.sha)) {
|
|
164875
|
+
updated++;
|
|
164876
|
+
} else {
|
|
164877
|
+
inserted++;
|
|
164878
|
+
existing.add(commit.sha);
|
|
164879
|
+
}
|
|
164880
|
+
}
|
|
164881
|
+
}
|
|
164882
|
+
})();
|
|
164883
|
+
return { inserted, updated };
|
|
164884
|
+
}
|
|
164885
|
+
function getCommitCount(db, projectPath) {
|
|
164886
|
+
const row = getProjectCountStatement(db).get(projectPath);
|
|
164887
|
+
return row?.count ?? 0;
|
|
164888
|
+
}
|
|
164889
|
+
function getLatestIndexedCommitTimeMs(db, projectPath) {
|
|
164890
|
+
const row = getLatestCommitTimeStatement(db).get(projectPath);
|
|
164891
|
+
return row?.latest ?? null;
|
|
164892
|
+
}
|
|
164893
|
+
function evictOldestCommits(db, projectPath, excess) {
|
|
164894
|
+
if (excess <= 0)
|
|
164895
|
+
return 0;
|
|
164896
|
+
const before = getCommitCount(db, projectPath);
|
|
164897
|
+
getEvictStatement(db).run(projectPath, excess);
|
|
164898
|
+
const after = getCommitCount(db, projectPath);
|
|
164899
|
+
return Math.max(0, before - after);
|
|
164900
|
+
}
|
|
164901
|
+
function enforceProjectCap(db, projectPath, maxCommits) {
|
|
164902
|
+
if (maxCommits <= 0)
|
|
164903
|
+
return 0;
|
|
164904
|
+
const count = getCommitCount(db, projectPath);
|
|
164905
|
+
if (count <= maxCommits)
|
|
164906
|
+
return 0;
|
|
164907
|
+
const excess = count - maxCommits;
|
|
164908
|
+
const evicted = evictOldestCommits(db, projectPath, excess);
|
|
164909
|
+
if (evicted > 0) {
|
|
164910
|
+
log(`[git-commits] evicted ${evicted} oldest commits for project ${projectPath} (cap=${maxCommits}, was=${count})`);
|
|
164911
|
+
}
|
|
164912
|
+
return evicted;
|
|
164913
|
+
}
|
|
164914
|
+
|
|
164915
|
+
// src/features/magic-context/git-commits/indexer.ts
|
|
164916
|
+
var MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
164917
|
+
var EMBED_BATCH_SIZE = 16;
|
|
164918
|
+
var EMBED_MAX_PER_SWEEP = 500;
|
|
164919
|
+
var EMBED_SWEEP_MAX_WALL_CLOCK_MS = 5 * 60 * 1000;
|
|
164920
|
+
var indexInProgress = new Set;
|
|
164921
|
+
var embedInProgress = new Set;
|
|
164922
|
+
async function indexCommitsForProject(db, projectPath, directory, embeddingConfig2, options) {
|
|
164923
|
+
const result = {
|
|
164924
|
+
scanned: 0,
|
|
164925
|
+
inserted: 0,
|
|
164926
|
+
updated: 0,
|
|
164927
|
+
evicted: 0,
|
|
164928
|
+
embedded: 0
|
|
164929
|
+
};
|
|
164930
|
+
if (indexInProgress.has(projectPath)) {
|
|
164931
|
+
log(`[git-commits] index already in progress for ${projectPath}, skipping`);
|
|
164932
|
+
return result;
|
|
164933
|
+
}
|
|
164934
|
+
indexInProgress.add(projectPath);
|
|
164935
|
+
try {
|
|
164936
|
+
const latestIndexed = getLatestIndexedCommitTimeMs(db, projectPath);
|
|
164937
|
+
const sinceMs = latestIndexed !== null ? Math.max(latestIndexed - 60000, Date.now() - options.sinceDays * MS_PER_DAY) : Date.now() - options.sinceDays * MS_PER_DAY;
|
|
164938
|
+
const commits = await readGitCommits(directory, {
|
|
164939
|
+
sinceMs,
|
|
164940
|
+
maxCommits: options.maxCommits
|
|
164941
|
+
});
|
|
164942
|
+
result.scanned = commits.length;
|
|
164943
|
+
if (commits.length === 0) {
|
|
164944
|
+
result.evicted = enforceProjectCap(db, projectPath, options.maxCommits);
|
|
164945
|
+
log(`[git-commits] no new commits for ${projectPath} (sinceMs=${sinceMs} latestIndexed=${latestIndexed ?? "none"} evicted=${result.evicted})`);
|
|
164946
|
+
return result;
|
|
164947
|
+
}
|
|
164948
|
+
log(`[git-commits] read ${commits.length} commits for ${projectPath} (sinceMs=${sinceMs} latestIndexed=${latestIndexed ?? "none"})`);
|
|
164949
|
+
const upsert = upsertCommits(db, projectPath, commits);
|
|
164950
|
+
result.inserted = upsert.inserted;
|
|
164951
|
+
result.updated = upsert.updated;
|
|
164952
|
+
result.evicted = enforceProjectCap(db, projectPath, options.maxCommits);
|
|
164953
|
+
if (options.skipEmbed || !isEmbeddingEnabled()) {
|
|
164954
|
+
log(`[git-commits] indexed ${projectPath}: scanned=${result.scanned} inserted=${result.inserted} updated=${result.updated} evicted=${result.evicted} embedded=0 (embedding skipped: skipEmbed=${options.skipEmbed === true} embeddingEnabled=${isEmbeddingEnabled()})`);
|
|
164955
|
+
return result;
|
|
164956
|
+
}
|
|
164957
|
+
result.embedded = await embedUnembeddedCommits(db, projectPath, embeddingConfig2);
|
|
164958
|
+
log(`[git-commits] indexed ${projectPath}: scanned=${result.scanned} inserted=${result.inserted} updated=${result.updated} evicted=${result.evicted} embedded=${result.embedded}`);
|
|
164959
|
+
return result;
|
|
164960
|
+
} finally {
|
|
164961
|
+
indexInProgress.delete(projectPath);
|
|
164962
|
+
}
|
|
164963
|
+
}
|
|
164964
|
+
async function embedUnembeddedCommits(db, projectPath, _config) {
|
|
164965
|
+
if (embedInProgress.has(projectPath)) {
|
|
164966
|
+
return 0;
|
|
164967
|
+
}
|
|
164968
|
+
if (!isEmbeddingEnabled()) {
|
|
164969
|
+
return 0;
|
|
164970
|
+
}
|
|
164971
|
+
embedInProgress.add(projectPath);
|
|
164972
|
+
const startedAt = Date.now();
|
|
164973
|
+
const deadline = startedAt + EMBED_SWEEP_MAX_WALL_CLOCK_MS;
|
|
164974
|
+
let total = 0;
|
|
164975
|
+
try {
|
|
164976
|
+
while (Date.now() < deadline && total < EMBED_MAX_PER_SWEEP) {
|
|
164977
|
+
const rows = loadUnembeddedCommits(db, projectPath, EMBED_BATCH_SIZE);
|
|
164978
|
+
if (rows.length === 0)
|
|
164979
|
+
break;
|
|
164980
|
+
let embeddedThisBatch = 0;
|
|
164981
|
+
try {
|
|
164982
|
+
const embeddings = await embedBatch(rows.map((row) => row.message));
|
|
164983
|
+
const modelId = getEmbeddingModelId();
|
|
164984
|
+
if (modelId === "off")
|
|
164985
|
+
break;
|
|
164986
|
+
db.transaction(() => {
|
|
164987
|
+
for (const [index, row] of rows.entries()) {
|
|
164988
|
+
const embedding = embeddings[index];
|
|
164989
|
+
if (!embedding)
|
|
164990
|
+
continue;
|
|
164991
|
+
saveCommitEmbedding(db, row.sha, embedding, modelId);
|
|
164992
|
+
embeddedThisBatch += 1;
|
|
164993
|
+
}
|
|
164994
|
+
})();
|
|
164995
|
+
} catch (error48) {
|
|
164996
|
+
log(`[git-commits] embed batch failed for ${projectPath}: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
164997
|
+
break;
|
|
164998
|
+
}
|
|
164999
|
+
if (embeddedThisBatch === 0)
|
|
165000
|
+
break;
|
|
165001
|
+
total += embeddedThisBatch;
|
|
165002
|
+
if (embeddedThisBatch < rows.length)
|
|
165003
|
+
break;
|
|
165004
|
+
}
|
|
165005
|
+
if (total > 0) {
|
|
165006
|
+
const totalEmbedded = countEmbeddedCommits(db, projectPath);
|
|
165007
|
+
log(`[git-commits] embedded ${total} commits for ${projectPath} (total embedded: ${totalEmbedded})`);
|
|
165008
|
+
}
|
|
165009
|
+
return total;
|
|
165010
|
+
} finally {
|
|
165011
|
+
embedInProgress.delete(projectPath);
|
|
165012
|
+
}
|
|
165013
|
+
}
|
|
165014
|
+
// src/features/magic-context/git-commits/search-git-commits.ts
|
|
165015
|
+
init_logger();
|
|
165016
|
+
init_storage_memory_fts();
|
|
165017
|
+
var ftsStatements = new WeakMap;
|
|
165018
|
+
var ftsPlainStatements = new WeakMap;
|
|
165019
|
+
var getBySHAStatements = new WeakMap;
|
|
165020
|
+
function rowToCommit(row) {
|
|
165021
|
+
return {
|
|
165022
|
+
sha: row.sha,
|
|
165023
|
+
shortSha: row.short_sha,
|
|
165024
|
+
projectPath: row.project_path,
|
|
165025
|
+
message: row.message,
|
|
165026
|
+
author: row.author,
|
|
165027
|
+
committedAtMs: row.committed_at,
|
|
165028
|
+
indexedAtMs: row.indexed_at
|
|
165029
|
+
};
|
|
165030
|
+
}
|
|
165031
|
+
function getFtsStatement(db) {
|
|
165032
|
+
let stmt = ftsStatements.get(db);
|
|
165033
|
+
if (!stmt) {
|
|
165034
|
+
stmt = db.prepare(`SELECT c.sha AS sha, c.project_path AS project_path, c.short_sha AS short_sha,
|
|
165035
|
+
c.message AS message, c.author AS author,
|
|
165036
|
+
c.committed_at AS committed_at, c.indexed_at AS indexed_at
|
|
165037
|
+
FROM git_commits_fts
|
|
165038
|
+
INNER JOIN git_commits c ON c.sha = git_commits_fts.sha
|
|
165039
|
+
WHERE c.project_path = ? AND git_commits_fts MATCH ?
|
|
165040
|
+
ORDER BY bm25(git_commits_fts) LIMIT ?`);
|
|
165041
|
+
ftsStatements.set(db, stmt);
|
|
165042
|
+
}
|
|
165043
|
+
return stmt;
|
|
165044
|
+
}
|
|
165045
|
+
function getLikeFallbackStatement(db) {
|
|
165046
|
+
let stmt = ftsPlainStatements.get(db);
|
|
165047
|
+
if (!stmt) {
|
|
165048
|
+
stmt = db.prepare(`SELECT sha, project_path, short_sha, message, author, committed_at, indexed_at
|
|
165049
|
+
FROM git_commits
|
|
165050
|
+
WHERE project_path = ? AND lower(message) LIKE '%' || lower(?) || '%'
|
|
165051
|
+
ORDER BY committed_at DESC LIMIT ?`);
|
|
165052
|
+
ftsPlainStatements.set(db, stmt);
|
|
165053
|
+
}
|
|
165054
|
+
return stmt;
|
|
165055
|
+
}
|
|
165056
|
+
function getBySHAStatement(db) {
|
|
165057
|
+
let stmt = getBySHAStatements.get(db);
|
|
165058
|
+
if (!stmt) {
|
|
165059
|
+
stmt = db.prepare(`SELECT sha, project_path, short_sha, message, author, committed_at, indexed_at
|
|
165060
|
+
FROM git_commits WHERE sha = ?`);
|
|
165061
|
+
getBySHAStatements.set(db, stmt);
|
|
165062
|
+
}
|
|
165063
|
+
return stmt;
|
|
165064
|
+
}
|
|
165065
|
+
function clamp01(value) {
|
|
165066
|
+
if (!Number.isFinite(value))
|
|
165067
|
+
return 0;
|
|
165068
|
+
return Math.min(1, Math.max(0, value));
|
|
165069
|
+
}
|
|
165070
|
+
function searchGitCommitsSync(db, projectPath, query, options) {
|
|
165071
|
+
const trimmed = query.trim();
|
|
165072
|
+
if (trimmed.length === 0 || options.limit <= 0)
|
|
165073
|
+
return [];
|
|
165074
|
+
const semanticWeight = options.semanticWeight ?? 0.7;
|
|
165075
|
+
const ftsWeight = options.ftsWeight ?? 0.3;
|
|
165076
|
+
const singleSourcePenalty = options.singleSourcePenalty ?? 0.8;
|
|
165077
|
+
const fetchLimit = Math.max(options.limit * 3, 30);
|
|
165078
|
+
const ftsCandidates = [];
|
|
165079
|
+
const sanitized = sanitizeFtsQuery(trimmed);
|
|
165080
|
+
if (sanitized.length > 0) {
|
|
165081
|
+
try {
|
|
165082
|
+
for (const row of getFtsStatement(db).all(projectPath, sanitized, fetchLimit)) {
|
|
165083
|
+
ftsCandidates.push(rowToCommit(row));
|
|
165084
|
+
}
|
|
165085
|
+
} catch (error48) {
|
|
165086
|
+
log(`[git-commits] FTS query failed for "${trimmed}": ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
165087
|
+
}
|
|
165088
|
+
}
|
|
165089
|
+
if (ftsCandidates.length === 0) {
|
|
165090
|
+
for (const row of getLikeFallbackStatement(db).all(projectPath, trimmed, fetchLimit)) {
|
|
165091
|
+
ftsCandidates.push(rowToCommit(row));
|
|
165092
|
+
}
|
|
165093
|
+
}
|
|
165094
|
+
const ftsScores = new Map;
|
|
165095
|
+
ftsCandidates.forEach((commit, rank) => {
|
|
165096
|
+
ftsScores.set(commit.sha, 1 / (rank + 1));
|
|
165097
|
+
});
|
|
165098
|
+
const semanticScores = new Map;
|
|
165099
|
+
if (options.queryEmbedding) {
|
|
165100
|
+
const embeddings = loadProjectCommitEmbeddings(db, projectPath);
|
|
165101
|
+
for (const [sha, embedding] of embeddings.entries()) {
|
|
165102
|
+
const similarity = clamp01(cosineSimilarity(options.queryEmbedding, embedding));
|
|
165103
|
+
if (similarity > 0) {
|
|
165104
|
+
semanticScores.set(sha, similarity);
|
|
165105
|
+
}
|
|
165106
|
+
}
|
|
165107
|
+
}
|
|
165108
|
+
const bySha = new Map;
|
|
165109
|
+
for (const commit of ftsCandidates)
|
|
165110
|
+
bySha.set(commit.sha, commit);
|
|
165111
|
+
const getCommitStmt = getBySHAStatement(db);
|
|
165112
|
+
for (const sha of semanticScores.keys()) {
|
|
165113
|
+
if (bySha.has(sha))
|
|
165114
|
+
continue;
|
|
165115
|
+
const row = getCommitStmt.get(sha);
|
|
165116
|
+
if (row && row.project_path === projectPath) {
|
|
165117
|
+
bySha.set(sha, rowToCommit(row));
|
|
165118
|
+
}
|
|
165119
|
+
}
|
|
165120
|
+
const results = [];
|
|
165121
|
+
for (const [sha, commit] of bySha.entries()) {
|
|
165122
|
+
const sem = semanticScores.get(sha);
|
|
165123
|
+
const fts = ftsScores.get(sha);
|
|
165124
|
+
let score = 0;
|
|
165125
|
+
let matchType = "fts";
|
|
165126
|
+
if (sem !== undefined && fts !== undefined) {
|
|
165127
|
+
score = semanticWeight * sem + ftsWeight * fts;
|
|
165128
|
+
matchType = "hybrid";
|
|
165129
|
+
} else if (sem !== undefined) {
|
|
165130
|
+
score = sem * singleSourcePenalty;
|
|
165131
|
+
matchType = "semantic";
|
|
165132
|
+
} else if (fts !== undefined) {
|
|
165133
|
+
score = fts * singleSourcePenalty;
|
|
165134
|
+
matchType = "fts";
|
|
165135
|
+
}
|
|
165136
|
+
if (score <= 0)
|
|
165137
|
+
continue;
|
|
165138
|
+
results.push({ commit, score, matchType });
|
|
165139
|
+
}
|
|
165140
|
+
results.sort((left, right) => {
|
|
165141
|
+
if (right.score !== left.score)
|
|
165142
|
+
return right.score - left.score;
|
|
165143
|
+
return right.commit.committedAtMs - left.commit.committedAtMs;
|
|
165144
|
+
});
|
|
165145
|
+
return results.slice(0, options.limit);
|
|
165146
|
+
}
|
|
164202
165147
|
// src/plugin/dream-timer.ts
|
|
164203
165148
|
init_embedding();
|
|
165149
|
+
init_project_identity();
|
|
164204
165150
|
init_storage();
|
|
164205
165151
|
init_logger();
|
|
164206
165152
|
var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
|
|
164207
165153
|
var activeTimer = null;
|
|
164208
|
-
var
|
|
165154
|
+
var registeredProjects = new Map;
|
|
164209
165155
|
function startDreamScheduleTimer(args) {
|
|
164210
|
-
|
|
164211
|
-
|
|
164212
|
-
|
|
164213
|
-
|
|
164214
|
-
const {
|
|
164215
|
-
client,
|
|
164216
|
-
dreamerConfig,
|
|
164217
|
-
embeddingConfig: embeddingConfig2,
|
|
164218
|
-
memoryEnabled,
|
|
164219
|
-
experimentalUserMemories,
|
|
164220
|
-
experimentalPinKeyFiles
|
|
164221
|
-
} = args;
|
|
164222
|
-
const dreamingEnabled = Boolean(dreamerConfig?.enabled && dreamerConfig.schedule?.trim());
|
|
164223
|
-
const embeddingSweepEnabled = memoryEnabled && embeddingConfig2.provider !== "off";
|
|
164224
|
-
if (!dreamingEnabled && !embeddingSweepEnabled) {
|
|
165156
|
+
const dreamingEnabled = Boolean(args.dreamerConfig?.enabled && args.dreamerConfig.schedule?.trim());
|
|
165157
|
+
const embeddingSweepEnabled = args.memoryEnabled && args.embeddingConfig.provider !== "off";
|
|
165158
|
+
const commitIndexingEnabled = args.gitCommitIndexing?.enabled === true;
|
|
165159
|
+
if (!dreamingEnabled && !embeddingSweepEnabled && !commitIndexingEnabled) {
|
|
164225
165160
|
return;
|
|
164226
165161
|
}
|
|
164227
|
-
const
|
|
164228
|
-
|
|
164229
|
-
|
|
164230
|
-
|
|
164231
|
-
|
|
165162
|
+
const isNewRegistration = !registeredProjects.has(args.directory);
|
|
165163
|
+
registeredProjects.set(args.directory, args);
|
|
165164
|
+
if (isNewRegistration) {
|
|
165165
|
+
log(`[dreamer] registered project ${args.directory} (dreaming=${dreamingEnabled} embeddings=${embeddingSweepEnabled} commits=${commitIndexingEnabled}; total=${registeredProjects.size})`);
|
|
165166
|
+
}
|
|
165167
|
+
if (!activeTimer) {
|
|
165168
|
+
log(`[dreamer] started independent schedule timer (every ${DREAM_TIMER_INTERVAL_MS / 60000}m)`);
|
|
165169
|
+
runTick("startup");
|
|
165170
|
+
const timer = setInterval(() => runTick("interval"), DREAM_TIMER_INTERVAL_MS);
|
|
165171
|
+
if (typeof timer === "object" && "unref" in timer) {
|
|
165172
|
+
timer.unref();
|
|
165173
|
+
}
|
|
165174
|
+
activeTimer = timer;
|
|
165175
|
+
} else if (isNewRegistration) {
|
|
165176
|
+
sweepProject(args, "startup");
|
|
165177
|
+
}
|
|
165178
|
+
return () => {
|
|
165179
|
+
registeredProjects.delete(args.directory);
|
|
165180
|
+
log(`[dreamer] unregistered project ${args.directory} (remaining=${registeredProjects.size})`);
|
|
165181
|
+
if (registeredProjects.size === 0 && activeTimer) {
|
|
165182
|
+
clearInterval(activeTimer);
|
|
165183
|
+
activeTimer = null;
|
|
165184
|
+
log("[dreamer] stopped dream schedule timer (no projects left)");
|
|
165185
|
+
}
|
|
165186
|
+
};
|
|
165187
|
+
}
|
|
165188
|
+
function runTick(origin) {
|
|
165189
|
+
log(`[dreamer] timer tick (${origin}) \u2014 projects=${registeredProjects.size}`);
|
|
165190
|
+
try {
|
|
165191
|
+
const anyEmbeddingEnabled = Array.from(registeredProjects.values()).some((r) => r.memoryEnabled && r.embeddingConfig.provider !== "off");
|
|
165192
|
+
if (anyEmbeddingEnabled) {
|
|
165193
|
+
const first = registeredProjects.values().next().value;
|
|
165194
|
+
if (first) {
|
|
165195
|
+
embedAllUnembeddedMemories(openDatabase(), first.embeddingConfig).then((embeddedCount) => {
|
|
164232
165196
|
if (embeddedCount > 0) {
|
|
164233
165197
|
log(`[magic-context] proactively embedded ${embeddedCount} ${embeddedCount === 1 ? "memory" : "memories"} across all projects`);
|
|
164234
165198
|
}
|
|
@@ -164236,41 +165200,65 @@ function startDreamScheduleTimer(args) {
|
|
|
164236
165200
|
log("[magic-context] periodic memory embedding sweep failed:", error48);
|
|
164237
165201
|
});
|
|
164238
165202
|
}
|
|
164239
|
-
if (!dreamingEnabled || !dreamerConfig?.schedule?.trim()) {
|
|
164240
|
-
log("[dreamer] timer tick \u2014 dreaming disabled, skipping schedule check");
|
|
164241
|
-
return;
|
|
164242
|
-
}
|
|
164243
|
-
const db = openDatabase();
|
|
164244
|
-
log(`[dreamer] timer tick \u2014 checking schedule window "${dreamerConfig.schedule}"`);
|
|
164245
|
-
checkScheduleAndEnqueue(db, dreamerConfig.schedule);
|
|
164246
|
-
processDreamQueue({
|
|
164247
|
-
db,
|
|
164248
|
-
client,
|
|
164249
|
-
tasks: dreamerConfig.tasks,
|
|
164250
|
-
taskTimeoutMinutes: dreamerConfig.task_timeout_minutes,
|
|
164251
|
-
maxRuntimeMinutes: dreamerConfig.max_runtime_minutes,
|
|
164252
|
-
experimentalUserMemories,
|
|
164253
|
-
experimentalPinKeyFiles
|
|
164254
|
-
}).catch((error48) => {
|
|
164255
|
-
log("[dreamer] timer-triggered queue processing failed:", error48);
|
|
164256
|
-
});
|
|
164257
|
-
} catch (error48) {
|
|
164258
|
-
log("[magic-context] timer-triggered maintenance check failed:", error48);
|
|
164259
165203
|
}
|
|
164260
|
-
|
|
164261
|
-
|
|
164262
|
-
|
|
165204
|
+
for (const reg of registeredProjects.values()) {
|
|
165205
|
+
sweepProject(reg, origin);
|
|
165206
|
+
}
|
|
165207
|
+
} catch (error48) {
|
|
165208
|
+
log("[magic-context] timer-triggered maintenance check failed:", error48);
|
|
165209
|
+
}
|
|
165210
|
+
}
|
|
165211
|
+
async function sweepProject(reg, origin) {
|
|
165212
|
+
const dreamingEnabled = Boolean(reg.dreamerConfig?.enabled && reg.dreamerConfig.schedule?.trim());
|
|
165213
|
+
const commitIndexingEnabled = reg.gitCommitIndexing?.enabled === true;
|
|
165214
|
+
if (commitIndexingEnabled && reg.gitCommitIndexing) {
|
|
165215
|
+
await sweepGitCommits({
|
|
165216
|
+
directory: reg.directory,
|
|
165217
|
+
gitCommitIndexing: reg.gitCommitIndexing,
|
|
165218
|
+
embeddingConfig: reg.embeddingConfig
|
|
165219
|
+
});
|
|
165220
|
+
}
|
|
165221
|
+
if (!dreamingEnabled || !reg.dreamerConfig?.schedule?.trim()) {
|
|
165222
|
+
return;
|
|
165223
|
+
}
|
|
165224
|
+
try {
|
|
165225
|
+
const db = openDatabase();
|
|
165226
|
+
log(`[dreamer] timer tick (${origin}) ${reg.directory} \u2014 checking schedule window "${reg.dreamerConfig.schedule}"`);
|
|
165227
|
+
checkScheduleAndEnqueue(db, reg.dreamerConfig.schedule);
|
|
165228
|
+
await processDreamQueue({
|
|
165229
|
+
db,
|
|
165230
|
+
client: reg.client,
|
|
165231
|
+
tasks: reg.dreamerConfig.tasks,
|
|
165232
|
+
taskTimeoutMinutes: reg.dreamerConfig.task_timeout_minutes,
|
|
165233
|
+
maxRuntimeMinutes: reg.dreamerConfig.max_runtime_minutes,
|
|
165234
|
+
experimentalUserMemories: reg.experimentalUserMemories,
|
|
165235
|
+
experimentalPinKeyFiles: reg.experimentalPinKeyFiles
|
|
165236
|
+
});
|
|
165237
|
+
} catch (error48) {
|
|
165238
|
+
log(`[dreamer] timer-triggered queue processing failed for ${reg.directory}:`, error48);
|
|
165239
|
+
}
|
|
165240
|
+
}
|
|
165241
|
+
async function sweepGitCommits(args) {
|
|
165242
|
+
const { directory, gitCommitIndexing, embeddingConfig: embeddingConfig2 } = args;
|
|
165243
|
+
const startedAt = Date.now();
|
|
165244
|
+
log(`[git-commits] sweep starting for ${directory} (sinceDays=${gitCommitIndexing.since_days} maxCommits=${gitCommitIndexing.max_commits} embedding=${embeddingConfig2.provider})`);
|
|
165245
|
+
try {
|
|
165246
|
+
const db = openDatabase();
|
|
165247
|
+
const projectPath = resolveProjectIdentity(directory);
|
|
165248
|
+
const result = await indexCommitsForProject(db, projectPath, directory, embeddingConfig2, {
|
|
165249
|
+
sinceDays: gitCommitIndexing.since_days,
|
|
165250
|
+
maxCommits: gitCommitIndexing.max_commits
|
|
165251
|
+
});
|
|
165252
|
+
let drainedEmbeddings = 0;
|
|
165253
|
+
if (embeddingConfig2.provider !== "off" && result.embedded > 0) {
|
|
165254
|
+
drainedEmbeddings = await embedUnembeddedCommits(db, projectPath, embeddingConfig2);
|
|
165255
|
+
}
|
|
165256
|
+
const elapsedMs = Date.now() - startedAt;
|
|
165257
|
+
log(`[git-commits] sweep finished for ${projectPath} in ${elapsedMs}ms: scanned=${result.scanned} inserted=${result.inserted} updated=${result.updated} evicted=${result.evicted} embedded=${result.embedded} drained=${drainedEmbeddings}`);
|
|
165258
|
+
} catch (error48) {
|
|
165259
|
+
const elapsedMs = Date.now() - startedAt;
|
|
165260
|
+
log(`[git-commits] sweep failed for ${directory} after ${elapsedMs}ms: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
164263
165261
|
}
|
|
164264
|
-
const cleanup = () => {
|
|
164265
|
-
clearInterval(timer);
|
|
164266
|
-
activeTimer = null;
|
|
164267
|
-
activeCleanup = null;
|
|
164268
|
-
log("[dreamer] stopped dream schedule timer");
|
|
164269
|
-
};
|
|
164270
|
-
activeTimer = timer;
|
|
164271
|
-
activeCleanup = cleanup;
|
|
164272
|
-
log(`[dreamer] started independent schedule timer (every ${DREAM_TIMER_INTERVAL_MS / 60000}m)`);
|
|
164273
|
-
return cleanup;
|
|
164274
165262
|
}
|
|
164275
165263
|
|
|
164276
165264
|
// src/plugin/event.ts
|
|
@@ -164297,21 +165285,23 @@ function createCompactionHandler() {
|
|
|
164297
165285
|
};
|
|
164298
165286
|
}
|
|
164299
165287
|
// src/hooks/magic-context/event-resolvers.ts
|
|
165288
|
+
init_storage_meta_persisted();
|
|
164300
165289
|
init_logger();
|
|
164301
165290
|
init_models_dev_cache();
|
|
164302
165291
|
var DEFAULT_CONTEXT_LIMIT = 128000;
|
|
164303
165292
|
var MAX_EXECUTE_THRESHOLD = 80;
|
|
164304
|
-
function resolveContextLimit(providerID, modelID) {
|
|
164305
|
-
|
|
164306
|
-
|
|
164307
|
-
|
|
164308
|
-
|
|
164309
|
-
|
|
164310
|
-
|
|
164311
|
-
|
|
164312
|
-
|
|
165293
|
+
function resolveContextLimit(providerID, modelID, ctx) {
|
|
165294
|
+
const fromModelsDev = providerID && modelID ? getModelsDevContextLimit(providerID, modelID) : undefined;
|
|
165295
|
+
const baseline = fromModelsDev ?? DEFAULT_CONTEXT_LIMIT;
|
|
165296
|
+
if (ctx?.db && ctx.sessionID) {
|
|
165297
|
+
try {
|
|
165298
|
+
const overflow = getOverflowState(ctx.db, ctx.sessionID);
|
|
165299
|
+
if (overflow.detectedContextLimit > 0 && overflow.detectedContextLimit < baseline) {
|
|
165300
|
+
return overflow.detectedContextLimit;
|
|
165301
|
+
}
|
|
165302
|
+
} catch {}
|
|
164313
165303
|
}
|
|
164314
|
-
return
|
|
165304
|
+
return baseline;
|
|
164315
165305
|
}
|
|
164316
165306
|
function resolveCacheTtl(cacheTtl, modelKey) {
|
|
164317
165307
|
if (typeof cacheTtl === "string") {
|
|
@@ -165251,6 +166241,112 @@ ${snap.error}`;
|
|
|
165251
166241
|
// src/hooks/magic-context/hook.ts
|
|
165252
166242
|
init_derive_budgets();
|
|
165253
166243
|
|
|
166244
|
+
// src/features/magic-context/overflow-detection.ts
|
|
166245
|
+
var OVERFLOW_PATTERNS = [
|
|
166246
|
+
/prompt is too long/i,
|
|
166247
|
+
/input is too long for requested model/i,
|
|
166248
|
+
/exceeds the context window/i,
|
|
166249
|
+
/input token count.*exceeds the maximum/i,
|
|
166250
|
+
/maximum prompt length is \d+/i,
|
|
166251
|
+
/reduce the length of the messages/i,
|
|
166252
|
+
/maximum context length is \d+ tokens/i,
|
|
166253
|
+
/exceeds the limit of \d+/i,
|
|
166254
|
+
/exceeds the available context size/i,
|
|
166255
|
+
/greater than the context length/i,
|
|
166256
|
+
/context window exceeds limit/i,
|
|
166257
|
+
/exceeded model token limit/i,
|
|
166258
|
+
/context[_ ]length[_ ]exceeded/i,
|
|
166259
|
+
/request entity too large/i,
|
|
166260
|
+
/context length is only \d+ tokens/i,
|
|
166261
|
+
/input length.*exceeds.*context length/i,
|
|
166262
|
+
/prompt too long; exceeded (?:max )?context length/i,
|
|
166263
|
+
/too large for model with \d+ maximum context length/i,
|
|
166264
|
+
/model_context_window_exceeded/i,
|
|
166265
|
+
/context size has been exceeded/i
|
|
166266
|
+
];
|
|
166267
|
+
var LIMIT_EXTRACTION_PATTERNS = [
|
|
166268
|
+
/maximum prompt length is (\d+)/i,
|
|
166269
|
+
/maximum context length is (\d+) tokens?/i,
|
|
166270
|
+
/context length is only (\d+) tokens?/i,
|
|
166271
|
+
/exceeds the limit of (\d+)/i,
|
|
166272
|
+
/too large for model with (\d+) maximum context length/i,
|
|
166273
|
+
/context size.*(\d+) tokens?/i,
|
|
166274
|
+
/exceeds? the context length of (\d+)/i,
|
|
166275
|
+
/max(?:imum)?.*context.*?(\d+)/i
|
|
166276
|
+
];
|
|
166277
|
+
var MIN_PLAUSIBLE_LIMIT = 1024;
|
|
166278
|
+
var MAX_PLAUSIBLE_LIMIT = 1e7;
|
|
166279
|
+
function extractErrorMessage(error48) {
|
|
166280
|
+
if (!error48)
|
|
166281
|
+
return "";
|
|
166282
|
+
if (typeof error48 === "string")
|
|
166283
|
+
return error48;
|
|
166284
|
+
if (typeof error48 === "object") {
|
|
166285
|
+
const obj = error48;
|
|
166286
|
+
const nested = obj.error;
|
|
166287
|
+
if (nested && typeof nested.message === "string" && nested.message.length > 0) {
|
|
166288
|
+
return nested.message;
|
|
166289
|
+
}
|
|
166290
|
+
}
|
|
166291
|
+
if (error48 instanceof Error)
|
|
166292
|
+
return error48.message;
|
|
166293
|
+
if (typeof error48 === "object") {
|
|
166294
|
+
const obj = error48;
|
|
166295
|
+
if (typeof obj.message === "string")
|
|
166296
|
+
return obj.message;
|
|
166297
|
+
if (typeof obj.responseBody === "string")
|
|
166298
|
+
return obj.responseBody;
|
|
166299
|
+
try {
|
|
166300
|
+
return JSON.stringify(error48);
|
|
166301
|
+
} catch {
|
|
166302
|
+
return String(error48);
|
|
166303
|
+
}
|
|
166304
|
+
}
|
|
166305
|
+
return String(error48);
|
|
166306
|
+
}
|
|
166307
|
+
function detectOverflow(error48) {
|
|
166308
|
+
const message = extractErrorMessage(error48);
|
|
166309
|
+
if (!message) {
|
|
166310
|
+
return { isOverflow: false };
|
|
166311
|
+
}
|
|
166312
|
+
const hasStatus413 = /\b413\b/.test(message) && /(entity|payload|context|prompt)/i.test(message);
|
|
166313
|
+
let matched;
|
|
166314
|
+
for (const pattern of OVERFLOW_PATTERNS) {
|
|
166315
|
+
if (pattern.test(message)) {
|
|
166316
|
+
matched = pattern;
|
|
166317
|
+
break;
|
|
166318
|
+
}
|
|
166319
|
+
}
|
|
166320
|
+
if (!matched && !hasStatus413) {
|
|
166321
|
+
return { isOverflow: false };
|
|
166322
|
+
}
|
|
166323
|
+
const reportedLimit = parseReportedLimit(message);
|
|
166324
|
+
return {
|
|
166325
|
+
isOverflow: true,
|
|
166326
|
+
reportedLimit,
|
|
166327
|
+
matchedPattern: matched?.source
|
|
166328
|
+
};
|
|
166329
|
+
}
|
|
166330
|
+
function parseReportedLimit(message) {
|
|
166331
|
+
if (!message)
|
|
166332
|
+
return;
|
|
166333
|
+
for (const pattern of LIMIT_EXTRACTION_PATTERNS) {
|
|
166334
|
+
const match = message.match(pattern);
|
|
166335
|
+
if (!match)
|
|
166336
|
+
continue;
|
|
166337
|
+
const raw = match[1];
|
|
166338
|
+
if (!raw)
|
|
166339
|
+
continue;
|
|
166340
|
+
const value = Number.parseInt(raw, 10);
|
|
166341
|
+
if (!Number.isFinite(value))
|
|
166342
|
+
continue;
|
|
166343
|
+
if (value < MIN_PLAUSIBLE_LIMIT || value > MAX_PLAUSIBLE_LIMIT)
|
|
166344
|
+
continue;
|
|
166345
|
+
return value;
|
|
166346
|
+
}
|
|
166347
|
+
return;
|
|
166348
|
+
}
|
|
166349
|
+
|
|
165254
166350
|
// src/hooks/magic-context/event-handler.ts
|
|
165255
166351
|
init_storage();
|
|
165256
166352
|
init_storage_meta_persisted();
|
|
@@ -165309,9 +166405,18 @@ function getMessageUpdatedAssistantInfo(properties) {
|
|
|
165309
166405
|
read: typeof cache?.read === "number" ? cache.read : undefined,
|
|
165310
166406
|
write: typeof cache?.write === "number" ? cache.write : undefined
|
|
165311
166407
|
}
|
|
165312
|
-
}
|
|
166408
|
+
},
|
|
166409
|
+
error: info.error !== undefined ? info.error : undefined
|
|
165313
166410
|
};
|
|
165314
166411
|
}
|
|
166412
|
+
function getSessionErrorInfo(properties) {
|
|
166413
|
+
if (!isRecord(properties))
|
|
166414
|
+
return null;
|
|
166415
|
+
const sessionID = properties.sessionID;
|
|
166416
|
+
if (typeof sessionID !== "string" || sessionID.length === 0)
|
|
166417
|
+
return null;
|
|
166418
|
+
return { sessionID, error: properties.error };
|
|
166419
|
+
}
|
|
165315
166420
|
function getMessageRemovedInfo(properties) {
|
|
165316
166421
|
if (!isRecord(properties)) {
|
|
165317
166422
|
return null;
|
|
@@ -165490,7 +166595,60 @@ init_inject_compartments();
|
|
|
165490
166595
|
init_note_nudger();
|
|
165491
166596
|
init_read_session_chunk();
|
|
165492
166597
|
init_read_session_formatting();
|
|
166598
|
+
|
|
166599
|
+
// src/hooks/magic-context/reasoning-capability.ts
|
|
166600
|
+
init_models_dev_cache();
|
|
166601
|
+
function modelRequiresInterleavedReasoning(model) {
|
|
166602
|
+
if (!model?.providerID || !model?.modelID) {
|
|
166603
|
+
return false;
|
|
166604
|
+
}
|
|
166605
|
+
const field = getModelsDevInterleavedField(model.providerID, model.modelID);
|
|
166606
|
+
return typeof field === "string" && field.length > 0;
|
|
166607
|
+
}
|
|
166608
|
+
|
|
166609
|
+
// src/hooks/magic-context/transform.ts
|
|
165493
166610
|
init_send_session_notification();
|
|
166611
|
+
// src/hooks/magic-context/sentinel.ts
|
|
166612
|
+
function makeSentinel(originalPart) {
|
|
166613
|
+
const sentinel = {
|
|
166614
|
+
type: "text",
|
|
166615
|
+
text: ""
|
|
166616
|
+
};
|
|
166617
|
+
if (isRecord(originalPart)) {
|
|
166618
|
+
if (originalPart.cache_control !== undefined) {
|
|
166619
|
+
sentinel.cache_control = originalPart.cache_control;
|
|
166620
|
+
}
|
|
166621
|
+
if (originalPart.cacheControl !== undefined) {
|
|
166622
|
+
sentinel.cacheControl = originalPart.cacheControl;
|
|
166623
|
+
}
|
|
166624
|
+
}
|
|
166625
|
+
return sentinel;
|
|
166626
|
+
}
|
|
166627
|
+
function isSentinel(part) {
|
|
166628
|
+
return isRecord(part) && part.type === "text" && typeof part.text === "string" && part.text === "";
|
|
166629
|
+
}
|
|
166630
|
+
function replaySentinelByMessageIds(messages, ids) {
|
|
166631
|
+
if (ids.size === 0)
|
|
166632
|
+
return { replayed: 0, missingIds: [] };
|
|
166633
|
+
const seen = new Set;
|
|
166634
|
+
let replayed = 0;
|
|
166635
|
+
for (const msg of messages) {
|
|
166636
|
+
const id = msg.info.id;
|
|
166637
|
+
if (!id || !ids.has(id))
|
|
166638
|
+
continue;
|
|
166639
|
+
seen.add(id);
|
|
166640
|
+
if (msg.parts.length === 1 && isSentinel(msg.parts[0]))
|
|
166641
|
+
continue;
|
|
166642
|
+
msg.parts.length = 0;
|
|
166643
|
+
msg.parts.push(makeSentinel(undefined));
|
|
166644
|
+
replayed++;
|
|
166645
|
+
}
|
|
166646
|
+
const missingIds = [];
|
|
166647
|
+
for (const id of ids)
|
|
166648
|
+
if (!seen.has(id))
|
|
166649
|
+
missingIds.push(id);
|
|
166650
|
+
return { replayed, missingIds };
|
|
166651
|
+
}
|
|
165494
166652
|
|
|
165495
166653
|
// src/hooks/magic-context/strip-content.ts
|
|
165496
166654
|
var DROPPED_PLACEHOLDER_PATTERN = /^\[dropped \u00A7\d+\u00A7\]$/;
|
|
@@ -165512,12 +166670,15 @@ function isSystemInjectedText(text) {
|
|
|
165512
166670
|
}
|
|
165513
166671
|
function stripSystemInjectedMessages(messages, protectedTailStart) {
|
|
165514
166672
|
let stripped = 0;
|
|
165515
|
-
|
|
166673
|
+
const sentineledIds = [];
|
|
166674
|
+
for (let i = 0;i < messages.length; i++) {
|
|
165516
166675
|
if (i >= protectedTailStart)
|
|
165517
166676
|
continue;
|
|
165518
166677
|
const msg = messages[i];
|
|
165519
166678
|
if (msg.parts.length === 0)
|
|
165520
166679
|
continue;
|
|
166680
|
+
if (msg.parts.length === 1 && isSentinel(msg.parts[0]))
|
|
166681
|
+
continue;
|
|
165521
166682
|
let hasContentPart = false;
|
|
165522
166683
|
let allContentIsSystemInjection = true;
|
|
165523
166684
|
for (const part of msg.parts) {
|
|
@@ -165544,11 +166705,14 @@ function stripSystemInjectedMessages(messages, protectedTailStart) {
|
|
|
165544
166705
|
break;
|
|
165545
166706
|
}
|
|
165546
166707
|
if (hasContentPart && allContentIsSystemInjection) {
|
|
165547
|
-
|
|
166708
|
+
msg.parts.length = 0;
|
|
166709
|
+
msg.parts.push(makeSentinel(undefined));
|
|
165548
166710
|
stripped++;
|
|
166711
|
+
if (typeof msg.info.id === "string")
|
|
166712
|
+
sentineledIds.push(msg.info.id);
|
|
165549
166713
|
}
|
|
165550
166714
|
}
|
|
165551
|
-
return stripped;
|
|
166715
|
+
return { stripped, sentineledIds };
|
|
165552
166716
|
}
|
|
165553
166717
|
var METADATA_PART_TYPES = new Set([
|
|
165554
166718
|
"step-start",
|
|
@@ -165562,12 +166726,15 @@ var METADATA_PART_TYPES = new Set([
|
|
|
165562
166726
|
]);
|
|
165563
166727
|
function stripDroppedPlaceholderMessages(messages) {
|
|
165564
166728
|
let stripped = 0;
|
|
165565
|
-
|
|
166729
|
+
const sentineledIds = [];
|
|
166730
|
+
for (let i = 0;i < messages.length; i++) {
|
|
165566
166731
|
const msg = messages[i];
|
|
165567
166732
|
if (msg.parts.length === 0)
|
|
165568
166733
|
continue;
|
|
165569
166734
|
if (msg.info.role === "user")
|
|
165570
166735
|
continue;
|
|
166736
|
+
if (msg.parts.length === 1 && isSentinel(msg.parts[0]))
|
|
166737
|
+
continue;
|
|
165571
166738
|
let hasContentPart = false;
|
|
165572
166739
|
let hasNonDroppedContent = false;
|
|
165573
166740
|
for (const part of msg.parts) {
|
|
@@ -165608,13 +166775,18 @@ function stripDroppedPlaceholderMessages(messages) {
|
|
|
165608
166775
|
break;
|
|
165609
166776
|
}
|
|
165610
166777
|
if (hasContentPart && !hasNonDroppedContent) {
|
|
165611
|
-
|
|
166778
|
+
msg.parts.length = 0;
|
|
166779
|
+
msg.parts.push(makeSentinel(undefined));
|
|
165612
166780
|
stripped++;
|
|
166781
|
+
if (typeof msg.info.id === "string")
|
|
166782
|
+
sentineledIds.push(msg.info.id);
|
|
165613
166783
|
}
|
|
165614
166784
|
}
|
|
165615
|
-
return stripped;
|
|
166785
|
+
return { stripped, sentineledIds };
|
|
165616
166786
|
}
|
|
165617
|
-
function replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedWatermark) {
|
|
166787
|
+
function replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedWatermark, skipTypedReasoningCleanup = false) {
|
|
166788
|
+
if (skipTypedReasoningCleanup)
|
|
166789
|
+
return 0;
|
|
165618
166790
|
if (persistedWatermark <= 0)
|
|
165619
166791
|
return 0;
|
|
165620
166792
|
let cleared = 0;
|
|
@@ -165660,7 +166832,9 @@ function replayStrippedInlineThinking(messages, messageTagNumbers, persistedWate
|
|
|
165660
166832
|
}
|
|
165661
166833
|
return stripped;
|
|
165662
166834
|
}
|
|
165663
|
-
function clearOldReasoning(messages, reasoningByMessage, messageTagNumbers, clearReasoningAge) {
|
|
166835
|
+
function clearOldReasoning(messages, reasoningByMessage, messageTagNumbers, clearReasoningAge, skipTypedReasoningCleanup = false) {
|
|
166836
|
+
if (skipTypedReasoningCleanup)
|
|
166837
|
+
return 0;
|
|
165664
166838
|
const maxTag = findMaxTag(messageTagNumbers);
|
|
165665
166839
|
if (maxTag === 0)
|
|
165666
166840
|
return 0;
|
|
@@ -165695,28 +166869,29 @@ function findMaxTag(messageTagNumbers) {
|
|
|
165695
166869
|
return max;
|
|
165696
166870
|
}
|
|
165697
166871
|
var CLEARED_REASONING_TYPES = new Set(["thinking", "reasoning"]);
|
|
165698
|
-
function stripClearedReasoning(messages) {
|
|
166872
|
+
function stripClearedReasoning(messages, skipTypedReasoningCleanup = false) {
|
|
166873
|
+
if (skipTypedReasoningCleanup)
|
|
166874
|
+
return 0;
|
|
165699
166875
|
let stripped = 0;
|
|
165700
166876
|
for (const message of messages) {
|
|
165701
166877
|
if (message.info.role !== "assistant")
|
|
165702
166878
|
continue;
|
|
165703
|
-
|
|
165704
|
-
|
|
166879
|
+
for (let i = 0;i < message.parts.length; i++) {
|
|
166880
|
+
const part = message.parts[i];
|
|
165705
166881
|
if (!isRecord(part))
|
|
165706
|
-
|
|
166882
|
+
continue;
|
|
165707
166883
|
const partType = part.type;
|
|
165708
166884
|
if (!CLEARED_REASONING_TYPES.has(partType))
|
|
165709
|
-
|
|
166885
|
+
continue;
|
|
165710
166886
|
if (!("thinking" in part) && !("text" in part))
|
|
165711
|
-
|
|
166887
|
+
continue;
|
|
165712
166888
|
const thinking = "thinking" in part ? part.thinking : undefined;
|
|
165713
166889
|
const text = "text" in part ? part.text : undefined;
|
|
165714
|
-
|
|
165715
|
-
|
|
165716
|
-
|
|
165717
|
-
message.parts
|
|
165718
|
-
|
|
165719
|
-
stripped += originalLength - kept.length;
|
|
166890
|
+
const isCleared = (thinking === undefined || thinking === "[cleared]") && (text === undefined || text === "[cleared]");
|
|
166891
|
+
if (!isCleared)
|
|
166892
|
+
continue;
|
|
166893
|
+
message.parts[i] = makeSentinel(part);
|
|
166894
|
+
stripped++;
|
|
165720
166895
|
}
|
|
165721
166896
|
}
|
|
165722
166897
|
return stripped;
|
|
@@ -165804,13 +166979,15 @@ function stripReasoningFromMergedAssistants(messages) {
|
|
|
165804
166979
|
continue;
|
|
165805
166980
|
if (part.ignored === true)
|
|
165806
166981
|
continue;
|
|
166982
|
+
if (isSentinel(part))
|
|
166983
|
+
continue;
|
|
165807
166984
|
if (REASONING_PART_TYPES.has(partType)) {
|
|
165808
166985
|
keepIndex = i;
|
|
165809
166986
|
}
|
|
165810
166987
|
break;
|
|
165811
166988
|
}
|
|
165812
166989
|
}
|
|
165813
|
-
for (let i = message.parts.length
|
|
166990
|
+
for (let i = 0;i < message.parts.length; i++) {
|
|
165814
166991
|
const part = message.parts[i];
|
|
165815
166992
|
if (!isRecord(part))
|
|
165816
166993
|
continue;
|
|
@@ -165820,7 +166997,7 @@ function stripReasoningFromMergedAssistants(messages) {
|
|
|
165820
166997
|
keptReasoningInRun = true;
|
|
165821
166998
|
continue;
|
|
165822
166999
|
}
|
|
165823
|
-
message.parts
|
|
167000
|
+
message.parts[i] = makeSentinel(part);
|
|
165824
167001
|
stripped++;
|
|
165825
167002
|
}
|
|
165826
167003
|
prevRole = role;
|
|
@@ -165843,7 +167020,7 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
165843
167020
|
if (maxTag > watermark) {
|
|
165844
167021
|
continue;
|
|
165845
167022
|
}
|
|
165846
|
-
for (let j = msg.parts.length
|
|
167023
|
+
for (let j = 0;j < msg.parts.length; j++) {
|
|
165847
167024
|
const part = msg.parts[j];
|
|
165848
167025
|
if (!isRecord(part) || part.type !== "file") {
|
|
165849
167026
|
continue;
|
|
@@ -165852,7 +167029,7 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
165852
167029
|
continue;
|
|
165853
167030
|
}
|
|
165854
167031
|
if (typeof part.url === "string" && part.url.startsWith("data:") && part.url.length > 200) {
|
|
165855
|
-
msg.parts
|
|
167032
|
+
msg.parts[j] = makeSentinel(part);
|
|
165856
167033
|
stripped++;
|
|
165857
167034
|
}
|
|
165858
167035
|
}
|
|
@@ -165950,7 +167127,8 @@ async function runCompartmentPhase(args) {
|
|
|
165950
167127
|
experimentalUserMemories: args.experimentalUserMemories,
|
|
165951
167128
|
historianTwoPass: args.historianTwoPass,
|
|
165952
167129
|
compressorMinCompartmentRatio: args.compressorMinCompartmentRatio,
|
|
165953
|
-
compressorMaxMergeDepth: args.compressorMaxMergeDepth
|
|
167130
|
+
compressorMaxMergeDepth: args.compressorMaxMergeDepth,
|
|
167131
|
+
onInjectionCacheCleared: args.onInjectionCacheCleared
|
|
165954
167132
|
});
|
|
165955
167133
|
compartmentInProgress = true;
|
|
165956
167134
|
}
|
|
@@ -165974,7 +167152,8 @@ async function runCompartmentPhase(args) {
|
|
|
165974
167152
|
experimentalUserMemories: args.experimentalUserMemories,
|
|
165975
167153
|
historianTwoPass: args.historianTwoPass,
|
|
165976
167154
|
compressorMinCompartmentRatio: args.compressorMinCompartmentRatio,
|
|
165977
|
-
compressorMaxMergeDepth: args.compressorMaxMergeDepth
|
|
167155
|
+
compressorMaxMergeDepth: args.compressorMaxMergeDepth,
|
|
167156
|
+
onInjectionCacheCleared: args.onInjectionCacheCleared
|
|
165978
167157
|
});
|
|
165979
167158
|
activeRun = getActiveCompartmentRun(args.sessionId);
|
|
165980
167159
|
} else if (!activeRun && hasEligibleHistoryForCompartment()) {
|
|
@@ -166220,19 +167399,20 @@ function stripStructuralNoise(messages) {
|
|
|
166220
167399
|
if (!Array.isArray(message.parts)) {
|
|
166221
167400
|
continue;
|
|
166222
167401
|
}
|
|
166223
|
-
|
|
166224
|
-
|
|
166225
|
-
|
|
166226
|
-
|
|
166227
|
-
|
|
166228
|
-
|
|
167402
|
+
for (let i = 0;i < message.parts.length; i++) {
|
|
167403
|
+
const part = message.parts[i];
|
|
167404
|
+
if (isSentinel(part))
|
|
167405
|
+
continue;
|
|
167406
|
+
if (!isStructuralNoisePart(part))
|
|
167407
|
+
continue;
|
|
167408
|
+
message.parts[i] = makeSentinel(part);
|
|
167409
|
+
strippedParts++;
|
|
166229
167410
|
}
|
|
166230
167411
|
}
|
|
166231
167412
|
return strippedParts;
|
|
166232
167413
|
}
|
|
166233
167414
|
// src/hooks/magic-context/tag-messages.ts
|
|
166234
167415
|
init_storage();
|
|
166235
|
-
|
|
166236
167416
|
// src/hooks/magic-context/drop-stale-reduce-calls.ts
|
|
166237
167417
|
var STALE_TOOL_NAMES = new Set(["ctx_reduce"]);
|
|
166238
167418
|
function isReduceToolPart(part) {
|
|
@@ -166264,20 +167444,25 @@ function hasAnyMeaningfulPart(parts) {
|
|
|
166264
167444
|
function dropStaleReduceCalls(messages, protectedCount = 0) {
|
|
166265
167445
|
let didDrop = false;
|
|
166266
167446
|
const protectedStart = messages.length - protectedCount;
|
|
166267
|
-
for (let i =
|
|
167447
|
+
for (let i = 0;i < messages.length; i++) {
|
|
166268
167448
|
if (i >= protectedStart)
|
|
166269
|
-
|
|
167449
|
+
break;
|
|
166270
167450
|
const message = messages[i];
|
|
166271
|
-
|
|
166272
|
-
for (let j = message.parts.length
|
|
166273
|
-
|
|
166274
|
-
|
|
167451
|
+
let touched = false;
|
|
167452
|
+
for (let j = 0;j < message.parts.length; j++) {
|
|
167453
|
+
const part = message.parts[j];
|
|
167454
|
+
if (isSentinel(part))
|
|
167455
|
+
continue;
|
|
167456
|
+
if (isReduceToolPart(part)) {
|
|
167457
|
+
message.parts[j] = makeSentinel(part);
|
|
167458
|
+
touched = true;
|
|
166275
167459
|
}
|
|
166276
167460
|
}
|
|
166277
|
-
if (
|
|
167461
|
+
if (touched) {
|
|
166278
167462
|
didDrop = true;
|
|
166279
167463
|
if (!hasAnyMeaningfulPart(message.parts)) {
|
|
166280
|
-
|
|
167464
|
+
message.parts.length = 0;
|
|
167465
|
+
message.parts.push(makeSentinel(undefined));
|
|
166281
167466
|
}
|
|
166282
167467
|
}
|
|
166283
167468
|
}
|
|
@@ -166924,6 +168109,571 @@ function applyContextNudge(messages, nudge, nudgePlacements, sessionId) {
|
|
|
166924
168109
|
}
|
|
166925
168110
|
}
|
|
166926
168111
|
|
|
168112
|
+
// src/features/magic-context/search.ts
|
|
168113
|
+
init_read_session_chunk();
|
|
168114
|
+
init_logger();
|
|
168115
|
+
init_memory();
|
|
168116
|
+
init_embedding();
|
|
168117
|
+
init_storage_memory_fts();
|
|
168118
|
+
init_message_index();
|
|
168119
|
+
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
168120
|
+
var FTS_SEMANTIC_CANDIDATE_LIMIT = 50;
|
|
168121
|
+
var SEMANTIC_WEIGHT = 0.7;
|
|
168122
|
+
var FTS_WEIGHT = 0.3;
|
|
168123
|
+
var SINGLE_SOURCE_PENALTY = 0.8;
|
|
168124
|
+
var RESULT_PREVIEW_LIMIT = 220;
|
|
168125
|
+
var MEMORY_SOURCE_BOOST = 1.3;
|
|
168126
|
+
var MESSAGE_SOURCE_BOOST = 1.15;
|
|
168127
|
+
var GIT_COMMIT_SOURCE_BOOST = 1.2;
|
|
168128
|
+
var messageSearchStatements = new WeakMap;
|
|
168129
|
+
function normalizeLimit(limit) {
|
|
168130
|
+
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
168131
|
+
return DEFAULT_UNIFIED_SEARCH_LIMIT;
|
|
168132
|
+
}
|
|
168133
|
+
return Math.max(1, Math.floor(limit));
|
|
168134
|
+
}
|
|
168135
|
+
function normalizeCosineScore(score) {
|
|
168136
|
+
if (!Number.isFinite(score)) {
|
|
168137
|
+
return 0;
|
|
168138
|
+
}
|
|
168139
|
+
return Math.min(1, Math.max(0, score));
|
|
168140
|
+
}
|
|
168141
|
+
function previewText(text) {
|
|
168142
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
168143
|
+
if (normalized.length <= RESULT_PREVIEW_LIMIT) {
|
|
168144
|
+
return normalized;
|
|
168145
|
+
}
|
|
168146
|
+
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}\u2026`;
|
|
168147
|
+
}
|
|
168148
|
+
function getMessageSearchStatement(db) {
|
|
168149
|
+
let stmt = messageSearchStatements.get(db);
|
|
168150
|
+
if (!stmt) {
|
|
168151
|
+
stmt = db.prepare("SELECT message_ordinal AS messageOrdinal, message_id AS messageId, role, content FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ? ORDER BY bm25(message_history_fts), CAST(message_ordinal AS INTEGER) ASC LIMIT ?");
|
|
168152
|
+
messageSearchStatements.set(db, stmt);
|
|
168153
|
+
}
|
|
168154
|
+
return stmt;
|
|
168155
|
+
}
|
|
168156
|
+
function getMessageOrdinal(value) {
|
|
168157
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
168158
|
+
return value;
|
|
168159
|
+
}
|
|
168160
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
168161
|
+
const parsed = Number.parseInt(value, 10);
|
|
168162
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
168163
|
+
}
|
|
168164
|
+
return null;
|
|
168165
|
+
}
|
|
168166
|
+
async function getSemanticScores(args) {
|
|
168167
|
+
const semanticScores = new Map;
|
|
168168
|
+
if (!args.embeddingEnabled || !args.isEmbeddingRuntimeEnabled() || args.memories.length === 0) {
|
|
168169
|
+
return semanticScores;
|
|
168170
|
+
}
|
|
168171
|
+
const queryEmbedding = await args.embedQuery(args.query, args.signal);
|
|
168172
|
+
if (!queryEmbedding) {
|
|
168173
|
+
return semanticScores;
|
|
168174
|
+
}
|
|
168175
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
168176
|
+
const embeddings = await ensureMemoryEmbeddings({
|
|
168177
|
+
db: args.db,
|
|
168178
|
+
memories: args.memories,
|
|
168179
|
+
existingEmbeddings: cachedEmbeddings
|
|
168180
|
+
});
|
|
168181
|
+
for (const memory of args.memories) {
|
|
168182
|
+
const memoryEmbedding = embeddings.get(memory.id);
|
|
168183
|
+
if (!memoryEmbedding) {
|
|
168184
|
+
continue;
|
|
168185
|
+
}
|
|
168186
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(queryEmbedding, memoryEmbedding)));
|
|
168187
|
+
}
|
|
168188
|
+
return semanticScores;
|
|
168189
|
+
}
|
|
168190
|
+
function getFtsMatches(args) {
|
|
168191
|
+
try {
|
|
168192
|
+
return searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
168193
|
+
} catch (error48) {
|
|
168194
|
+
log(`[search] FTS query failed for "${args.query}": ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
168195
|
+
return [];
|
|
168196
|
+
}
|
|
168197
|
+
}
|
|
168198
|
+
function getFtsScores(matches) {
|
|
168199
|
+
return new Map(matches.map((memory, rank) => [memory.id, 1 / (rank + 1)]));
|
|
168200
|
+
}
|
|
168201
|
+
function selectSemanticCandidates(args) {
|
|
168202
|
+
if (args.ftsMatches.length === 0) {
|
|
168203
|
+
return args.memories;
|
|
168204
|
+
}
|
|
168205
|
+
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
168206
|
+
const cachedEmbeddings = peekProjectEmbeddings(args.projectPath);
|
|
168207
|
+
if (cachedEmbeddings) {
|
|
168208
|
+
for (const memoryId of cachedEmbeddings.keys()) {
|
|
168209
|
+
candidateIds.add(memoryId);
|
|
168210
|
+
}
|
|
168211
|
+
}
|
|
168212
|
+
return args.memories.filter((memory) => candidateIds.has(memory.id));
|
|
168213
|
+
}
|
|
168214
|
+
function mergeMemoryResults(args) {
|
|
168215
|
+
const memoryById = new Map(args.memories.map((memory) => [memory.id, memory]));
|
|
168216
|
+
const candidateIds = new Set([...args.semanticScores.keys(), ...args.ftsScores.keys()]);
|
|
168217
|
+
const results = [];
|
|
168218
|
+
for (const id of candidateIds) {
|
|
168219
|
+
if (args.visibleMemoryIds?.has(id)) {
|
|
168220
|
+
continue;
|
|
168221
|
+
}
|
|
168222
|
+
const memory = memoryById.get(id);
|
|
168223
|
+
if (!memory) {
|
|
168224
|
+
continue;
|
|
168225
|
+
}
|
|
168226
|
+
const semanticScore = args.semanticScores.get(id);
|
|
168227
|
+
const ftsScore = args.ftsScores.get(id);
|
|
168228
|
+
let score = 0;
|
|
168229
|
+
let matchType = "fts";
|
|
168230
|
+
if (semanticScore !== undefined && ftsScore !== undefined) {
|
|
168231
|
+
score = SEMANTIC_WEIGHT * semanticScore + FTS_WEIGHT * ftsScore;
|
|
168232
|
+
matchType = "hybrid";
|
|
168233
|
+
} else if (semanticScore !== undefined) {
|
|
168234
|
+
score = semanticScore * SINGLE_SOURCE_PENALTY;
|
|
168235
|
+
matchType = "semantic";
|
|
168236
|
+
} else if (ftsScore !== undefined) {
|
|
168237
|
+
score = ftsScore * SINGLE_SOURCE_PENALTY;
|
|
168238
|
+
matchType = "fts";
|
|
168239
|
+
}
|
|
168240
|
+
if (score <= 0) {
|
|
168241
|
+
continue;
|
|
168242
|
+
}
|
|
168243
|
+
results.push({
|
|
168244
|
+
source: "memory",
|
|
168245
|
+
content: previewText(memory.content),
|
|
168246
|
+
score,
|
|
168247
|
+
memoryId: memory.id,
|
|
168248
|
+
category: memory.category,
|
|
168249
|
+
matchType
|
|
168250
|
+
});
|
|
168251
|
+
}
|
|
168252
|
+
return results.sort((left, right) => {
|
|
168253
|
+
if (right.score !== left.score) {
|
|
168254
|
+
return right.score - left.score;
|
|
168255
|
+
}
|
|
168256
|
+
return left.memoryId - right.memoryId;
|
|
168257
|
+
}).slice(0, args.limit);
|
|
168258
|
+
}
|
|
168259
|
+
async function searchMemories(args) {
|
|
168260
|
+
if (!args.memoryEnabled) {
|
|
168261
|
+
return [];
|
|
168262
|
+
}
|
|
168263
|
+
const memories = getMemoriesByProject(args.db, args.projectPath);
|
|
168264
|
+
if (memories.length === 0) {
|
|
168265
|
+
return [];
|
|
168266
|
+
}
|
|
168267
|
+
const ftsMatches = getFtsMatches({
|
|
168268
|
+
db: args.db,
|
|
168269
|
+
projectPath: args.projectPath,
|
|
168270
|
+
query: args.query,
|
|
168271
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
168272
|
+
});
|
|
168273
|
+
const ftsScores = getFtsScores(ftsMatches);
|
|
168274
|
+
const semanticCandidates = selectSemanticCandidates({
|
|
168275
|
+
memories,
|
|
168276
|
+
projectPath: args.projectPath,
|
|
168277
|
+
ftsMatches
|
|
168278
|
+
});
|
|
168279
|
+
const semanticScores = await getSemanticScores({
|
|
168280
|
+
db: args.db,
|
|
168281
|
+
projectPath: args.projectPath,
|
|
168282
|
+
query: args.query,
|
|
168283
|
+
memories: semanticCandidates,
|
|
168284
|
+
embeddingEnabled: args.embeddingEnabled,
|
|
168285
|
+
embedQuery: args.embedQuery,
|
|
168286
|
+
isEmbeddingRuntimeEnabled: args.isEmbeddingRuntimeEnabled,
|
|
168287
|
+
signal: args.signal
|
|
168288
|
+
});
|
|
168289
|
+
return mergeMemoryResults({
|
|
168290
|
+
memories,
|
|
168291
|
+
semanticScores,
|
|
168292
|
+
ftsScores,
|
|
168293
|
+
limit: args.limit,
|
|
168294
|
+
visibleMemoryIds: args.visibleMemoryIds
|
|
168295
|
+
});
|
|
168296
|
+
}
|
|
168297
|
+
function linearDecayScore(rank, total) {
|
|
168298
|
+
if (total <= 0)
|
|
168299
|
+
return 0;
|
|
168300
|
+
return Math.max(0, 1 - rank / total);
|
|
168301
|
+
}
|
|
168302
|
+
function searchMessages(args) {
|
|
168303
|
+
ensureMessagesIndexed(args.db, args.sessionId, args.readMessages);
|
|
168304
|
+
const sanitizedQuery = sanitizeFtsQuery(args.query.trim());
|
|
168305
|
+
if (sanitizedQuery.length === 0) {
|
|
168306
|
+
return [];
|
|
168307
|
+
}
|
|
168308
|
+
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
168309
|
+
const rows = getMessageSearchStatement(args.db).all(args.sessionId, sanitizedQuery, fetchLimit).map((row) => row);
|
|
168310
|
+
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
168311
|
+
const filtered = rows.map((row) => {
|
|
168312
|
+
const messageOrdinal = getMessageOrdinal(row.messageOrdinal);
|
|
168313
|
+
if (messageOrdinal === null || typeof row.messageId !== "string" || typeof row.role !== "string" || typeof row.content !== "string") {
|
|
168314
|
+
return null;
|
|
168315
|
+
}
|
|
168316
|
+
if (cutoff !== null && messageOrdinal > cutoff) {
|
|
168317
|
+
return null;
|
|
168318
|
+
}
|
|
168319
|
+
return {
|
|
168320
|
+
messageOrdinal,
|
|
168321
|
+
messageId: row.messageId,
|
|
168322
|
+
role: row.role,
|
|
168323
|
+
content: row.content
|
|
168324
|
+
};
|
|
168325
|
+
}).filter((result) => result !== null).slice(0, args.limit);
|
|
168326
|
+
return filtered.map((row, rank) => ({
|
|
168327
|
+
source: "message",
|
|
168328
|
+
content: previewText(row.content),
|
|
168329
|
+
score: linearDecayScore(rank, filtered.length),
|
|
168330
|
+
messageOrdinal: row.messageOrdinal,
|
|
168331
|
+
messageId: row.messageId,
|
|
168332
|
+
role: row.role
|
|
168333
|
+
}));
|
|
168334
|
+
}
|
|
168335
|
+
function getSourceBoost(result) {
|
|
168336
|
+
switch (result.source) {
|
|
168337
|
+
case "memory":
|
|
168338
|
+
return MEMORY_SOURCE_BOOST;
|
|
168339
|
+
case "message":
|
|
168340
|
+
return MESSAGE_SOURCE_BOOST;
|
|
168341
|
+
case "git_commit":
|
|
168342
|
+
return GIT_COMMIT_SOURCE_BOOST;
|
|
168343
|
+
}
|
|
168344
|
+
}
|
|
168345
|
+
function compareUnifiedResults(left, right) {
|
|
168346
|
+
const leftEffective = left.score * getSourceBoost(left);
|
|
168347
|
+
const rightEffective = right.score * getSourceBoost(right);
|
|
168348
|
+
if (rightEffective !== leftEffective) {
|
|
168349
|
+
return rightEffective - leftEffective;
|
|
168350
|
+
}
|
|
168351
|
+
if (left.source === "memory" && right.source === "memory") {
|
|
168352
|
+
return left.memoryId - right.memoryId;
|
|
168353
|
+
}
|
|
168354
|
+
if (left.source === "message" && right.source === "message") {
|
|
168355
|
+
return left.messageOrdinal - right.messageOrdinal;
|
|
168356
|
+
}
|
|
168357
|
+
if (left.source === "git_commit" && right.source === "git_commit") {
|
|
168358
|
+
return right.committedAtMs - left.committedAtMs;
|
|
168359
|
+
}
|
|
168360
|
+
return 0;
|
|
168361
|
+
}
|
|
168362
|
+
function toGitCommitResult(hit) {
|
|
168363
|
+
return {
|
|
168364
|
+
source: "git_commit",
|
|
168365
|
+
content: previewText(hit.commit.message),
|
|
168366
|
+
score: hit.score,
|
|
168367
|
+
sha: hit.commit.sha,
|
|
168368
|
+
shortSha: hit.commit.shortSha,
|
|
168369
|
+
author: hit.commit.author,
|
|
168370
|
+
committedAtMs: hit.commit.committedAtMs,
|
|
168371
|
+
matchType: hit.matchType
|
|
168372
|
+
};
|
|
168373
|
+
}
|
|
168374
|
+
async function searchGitCommitsAsync(args) {
|
|
168375
|
+
if (args.limit <= 0)
|
|
168376
|
+
return [];
|
|
168377
|
+
let queryEmbedding = null;
|
|
168378
|
+
if (args.embeddingEnabled && args.isEmbeddingRuntimeEnabled()) {
|
|
168379
|
+
try {
|
|
168380
|
+
queryEmbedding = await args.embedQuery(args.query, args.signal);
|
|
168381
|
+
} catch (error48) {
|
|
168382
|
+
log(`[search] git commit query embedding failed: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
168383
|
+
}
|
|
168384
|
+
}
|
|
168385
|
+
const hits = searchGitCommitsSync(args.db, args.projectPath, args.query, {
|
|
168386
|
+
limit: args.limit,
|
|
168387
|
+
queryEmbedding
|
|
168388
|
+
});
|
|
168389
|
+
return hits.map(toGitCommitResult);
|
|
168390
|
+
}
|
|
168391
|
+
function resolveSources(sources) {
|
|
168392
|
+
if (sources === undefined) {
|
|
168393
|
+
return new Set(["memory", "message", "git_commit"]);
|
|
168394
|
+
}
|
|
168395
|
+
const set2 = new Set;
|
|
168396
|
+
for (const source of sources) {
|
|
168397
|
+
if (source === "memory" || source === "message" || source === "git_commit") {
|
|
168398
|
+
set2.add(source);
|
|
168399
|
+
}
|
|
168400
|
+
}
|
|
168401
|
+
return set2;
|
|
168402
|
+
}
|
|
168403
|
+
async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
168404
|
+
const trimmedQuery = query.trim();
|
|
168405
|
+
if (trimmedQuery.length === 0) {
|
|
168406
|
+
return [];
|
|
168407
|
+
}
|
|
168408
|
+
const limit = normalizeLimit(options.limit);
|
|
168409
|
+
const tierLimit = Math.max(limit * 3, DEFAULT_UNIFIED_SEARCH_LIMIT);
|
|
168410
|
+
const embeddingEnabled = options.embeddingEnabled ?? true;
|
|
168411
|
+
const embedQuery = options.embedQuery ?? embedText;
|
|
168412
|
+
const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
|
|
168413
|
+
const gitCommitsEnabled = options.gitCommitsEnabled ?? false;
|
|
168414
|
+
const activeSources = resolveSources(options.sources);
|
|
168415
|
+
const runMemory = activeSources.has("memory") && (options.memoryEnabled ?? true);
|
|
168416
|
+
const runMessages = activeSources.has("message");
|
|
168417
|
+
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
168418
|
+
const [memoryResults, messageResults, gitCommitResults] = await Promise.all([
|
|
168419
|
+
runMemory ? searchMemories({
|
|
168420
|
+
db,
|
|
168421
|
+
projectPath,
|
|
168422
|
+
query: trimmedQuery,
|
|
168423
|
+
limit: tierLimit,
|
|
168424
|
+
memoryEnabled: true,
|
|
168425
|
+
embeddingEnabled,
|
|
168426
|
+
embedQuery,
|
|
168427
|
+
isEmbeddingRuntimeEnabled,
|
|
168428
|
+
visibleMemoryIds: options.visibleMemoryIds,
|
|
168429
|
+
signal: options.signal
|
|
168430
|
+
}) : Promise.resolve([]),
|
|
168431
|
+
runMessages ? Promise.resolve(searchMessages({
|
|
168432
|
+
db,
|
|
168433
|
+
sessionId,
|
|
168434
|
+
query: trimmedQuery,
|
|
168435
|
+
limit: tierLimit,
|
|
168436
|
+
readMessages: options.readMessages ?? readRawSessionMessages,
|
|
168437
|
+
maxOrdinal: options.maxMessageOrdinal
|
|
168438
|
+
})) : Promise.resolve([]),
|
|
168439
|
+
runGitCommits ? searchGitCommitsAsync({
|
|
168440
|
+
db,
|
|
168441
|
+
projectPath,
|
|
168442
|
+
query: trimmedQuery,
|
|
168443
|
+
limit: tierLimit,
|
|
168444
|
+
embeddingEnabled,
|
|
168445
|
+
embedQuery,
|
|
168446
|
+
isEmbeddingRuntimeEnabled,
|
|
168447
|
+
signal: options.signal
|
|
168448
|
+
}) : Promise.resolve([])
|
|
168449
|
+
]);
|
|
168450
|
+
const results = [...memoryResults, ...messageResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
|
|
168451
|
+
const countRetrievals = options.countRetrievals ?? true;
|
|
168452
|
+
if (countRetrievals) {
|
|
168453
|
+
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
168454
|
+
if (memoryIds.length > 0) {
|
|
168455
|
+
db.transaction(() => {
|
|
168456
|
+
for (const memoryId of memoryIds) {
|
|
168457
|
+
updateMemoryRetrievalCount(db, memoryId);
|
|
168458
|
+
}
|
|
168459
|
+
})();
|
|
168460
|
+
}
|
|
168461
|
+
}
|
|
168462
|
+
return results;
|
|
168463
|
+
}
|
|
168464
|
+
|
|
168465
|
+
// src/hooks/magic-context/auto-search-runner.ts
|
|
168466
|
+
init_logger();
|
|
168467
|
+
|
|
168468
|
+
// src/hooks/magic-context/auto-search-hint.ts
|
|
168469
|
+
init_caveman();
|
|
168470
|
+
var MAX_FRAGMENTS = 3;
|
|
168471
|
+
var FRAGMENT_CHAR_CAP = 80;
|
|
168472
|
+
var MAX_HINT_CHARS = 800;
|
|
168473
|
+
var MS_PER_DAY2 = 24 * 60 * 60 * 1000;
|
|
168474
|
+
function truncate(text, limit) {
|
|
168475
|
+
const normalized = text.replace(/\s+/g, " ").trim();
|
|
168476
|
+
if (normalized.length <= limit)
|
|
168477
|
+
return normalized;
|
|
168478
|
+
return `${normalized.slice(0, Math.max(0, limit - 1)).trimEnd()}\u2026`;
|
|
168479
|
+
}
|
|
168480
|
+
function formatAge(committedAtMs) {
|
|
168481
|
+
const delta = Date.now() - committedAtMs;
|
|
168482
|
+
if (delta < 0)
|
|
168483
|
+
return "future";
|
|
168484
|
+
const days = Math.floor(delta / MS_PER_DAY2);
|
|
168485
|
+
if (days <= 0)
|
|
168486
|
+
return "today";
|
|
168487
|
+
if (days === 1)
|
|
168488
|
+
return "1d ago";
|
|
168489
|
+
if (days < 30)
|
|
168490
|
+
return `${days}d ago`;
|
|
168491
|
+
const months = Math.floor(days / 30);
|
|
168492
|
+
if (months === 1)
|
|
168493
|
+
return "1mo ago";
|
|
168494
|
+
if (months < 12)
|
|
168495
|
+
return `${months}mo ago`;
|
|
168496
|
+
const years = Math.floor(days / 365);
|
|
168497
|
+
return years === 1 ? "1y ago" : `${years}y ago`;
|
|
168498
|
+
}
|
|
168499
|
+
function renderFragment(result, charCap) {
|
|
168500
|
+
switch (result.source) {
|
|
168501
|
+
case "memory": {
|
|
168502
|
+
const compressed = cavemanCompress(result.content, "ultra");
|
|
168503
|
+
return truncate(compressed, charCap);
|
|
168504
|
+
}
|
|
168505
|
+
case "git_commit": {
|
|
168506
|
+
const subject = result.content.split(/\r?\n/)[0] ?? result.content;
|
|
168507
|
+
const body = truncate(subject, Math.max(10, charCap - 20));
|
|
168508
|
+
return `commit ${result.shortSha} ${formatAge(result.committedAtMs)}: ${body}`;
|
|
168509
|
+
}
|
|
168510
|
+
case "message": {
|
|
168511
|
+
const compressed = cavemanCompress(result.content, "ultra");
|
|
168512
|
+
return truncate(compressed, charCap);
|
|
168513
|
+
}
|
|
168514
|
+
}
|
|
168515
|
+
}
|
|
168516
|
+
function buildAutoSearchHint(results, options = {}) {
|
|
168517
|
+
const maxFragments = Math.max(1, options.maxFragments ?? MAX_FRAGMENTS);
|
|
168518
|
+
const fragmentCharCap = Math.max(20, options.fragmentCharCap ?? FRAGMENT_CHAR_CAP);
|
|
168519
|
+
const picks = results.slice(0, maxFragments);
|
|
168520
|
+
const lines = [];
|
|
168521
|
+
for (const result of picks) {
|
|
168522
|
+
const fragment = renderFragment(result, fragmentCharCap);
|
|
168523
|
+
if (fragment.length === 0)
|
|
168524
|
+
continue;
|
|
168525
|
+
lines.push(`- ${fragment}`);
|
|
168526
|
+
}
|
|
168527
|
+
if (lines.length === 0)
|
|
168528
|
+
return null;
|
|
168529
|
+
const header = lines.length === 1 ? "Your memory may contain 1 related fragment:" : `Your memory may contain ${lines.length} related fragments:`;
|
|
168530
|
+
const footer = "Run ctx_search to retrieve full context if relevant.";
|
|
168531
|
+
const body = [header, ...lines, footer].join(`
|
|
168532
|
+
`);
|
|
168533
|
+
const wrapped = `<ctx-search-hint>
|
|
168534
|
+
${body}
|
|
168535
|
+
</ctx-search-hint>`;
|
|
168536
|
+
if (wrapped.length > MAX_HINT_CHARS) {
|
|
168537
|
+
const overflow = wrapped.length - MAX_HINT_CHARS;
|
|
168538
|
+
const trimmedBody = body.slice(0, Math.max(0, body.length - overflow - 1)).trimEnd();
|
|
168539
|
+
return `<ctx-search-hint>
|
|
168540
|
+
${trimmedBody}\u2026
|
|
168541
|
+
</ctx-search-hint>`;
|
|
168542
|
+
}
|
|
168543
|
+
return wrapped;
|
|
168544
|
+
}
|
|
168545
|
+
|
|
168546
|
+
// src/hooks/magic-context/auto-search-runner.ts
|
|
168547
|
+
var autoSearchByTurn = new Map;
|
|
168548
|
+
var AUTO_SEARCH_TIMEOUT_MS = 3000;
|
|
168549
|
+
async function unifiedSearchWithTimeout(db, sessionId, projectPath, prompt, options, timeoutMs) {
|
|
168550
|
+
const controller = new AbortController;
|
|
168551
|
+
let timer;
|
|
168552
|
+
const timeoutPromise = new Promise((resolve3) => {
|
|
168553
|
+
timer = setTimeout(() => {
|
|
168554
|
+
controller.abort();
|
|
168555
|
+
resolve3(null);
|
|
168556
|
+
}, timeoutMs);
|
|
168557
|
+
});
|
|
168558
|
+
try {
|
|
168559
|
+
return await Promise.race([
|
|
168560
|
+
unifiedSearch(db, sessionId, projectPath, prompt, {
|
|
168561
|
+
...options,
|
|
168562
|
+
signal: controller.signal,
|
|
168563
|
+
countRetrievals: false
|
|
168564
|
+
}),
|
|
168565
|
+
timeoutPromise
|
|
168566
|
+
]);
|
|
168567
|
+
} finally {
|
|
168568
|
+
if (timer !== undefined)
|
|
168569
|
+
clearTimeout(timer);
|
|
168570
|
+
}
|
|
168571
|
+
}
|
|
168572
|
+
function collectUserPromptParts(message) {
|
|
168573
|
+
let collected = "";
|
|
168574
|
+
for (const part of message.parts) {
|
|
168575
|
+
const p = part;
|
|
168576
|
+
if (p.type === "text" && typeof p.text === "string") {
|
|
168577
|
+
collected += (collected.length > 0 ? `
|
|
168578
|
+
` : "") + p.text;
|
|
168579
|
+
}
|
|
168580
|
+
}
|
|
168581
|
+
return collected;
|
|
168582
|
+
}
|
|
168583
|
+
function hasStackedAugmentation(rawText) {
|
|
168584
|
+
return rawText.includes("<sidekick-augmentation>") || rawText.includes("<ctx-search-hint>") || rawText.includes("<ctx-search-auto>");
|
|
168585
|
+
}
|
|
168586
|
+
function extractUserPromptText(message) {
|
|
168587
|
+
return collectUserPromptParts(message).replace(/\u00A7\d+\u00A7\s*/g, "").replace(/<!--\s*\+[\d\s.hmdw]+\s*-->/g, "").replace(/<!--\s*OMO_INTERNAL_INITIATOR[\s\S]*?-->/g, "").replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "").replace(/<ctx-search-hint>[\s\S]*?<\/ctx-search-hint>/g, "").replace(/<ctx-search-auto>[\s\S]*?<\/ctx-search-auto>/g, "").replace(/<instruction[^>]*>[\s\S]*?<\/instruction>/g, "").replace(/<sidekick-augmentation>[\s\S]*?<\/sidekick-augmentation>/g, "").replace(/[ \t]+\n/g, `
|
|
168588
|
+
`).replace(/\n{3,}/g, `
|
|
168589
|
+
|
|
168590
|
+
`).trim();
|
|
168591
|
+
}
|
|
168592
|
+
function findLatestMeaningfulUserMessage(messages) {
|
|
168593
|
+
for (let i = messages.length - 1;i >= 0; i -= 1) {
|
|
168594
|
+
const msg = messages[i];
|
|
168595
|
+
if (msg.info.role !== "user")
|
|
168596
|
+
continue;
|
|
168597
|
+
if (typeof msg.info.id !== "string")
|
|
168598
|
+
continue;
|
|
168599
|
+
for (const part of msg.parts) {
|
|
168600
|
+
const p = part;
|
|
168601
|
+
if (p.type === "text" && typeof p.text === "string" && p.text.trim().length > 0) {
|
|
168602
|
+
return msg;
|
|
168603
|
+
}
|
|
168604
|
+
}
|
|
168605
|
+
}
|
|
168606
|
+
return null;
|
|
168607
|
+
}
|
|
168608
|
+
async function runAutoSearchHint(args) {
|
|
168609
|
+
const { sessionId, db, messages, options } = args;
|
|
168610
|
+
if (!options.enabled)
|
|
168611
|
+
return;
|
|
168612
|
+
const userMsg = findLatestMeaningfulUserMessage(messages);
|
|
168613
|
+
if (!userMsg || typeof userMsg.info.id !== "string")
|
|
168614
|
+
return;
|
|
168615
|
+
const userMsgId = userMsg.info.id;
|
|
168616
|
+
const cached2 = autoSearchByTurn.get(sessionId);
|
|
168617
|
+
if (cached2 && cached2.messageId === userMsgId) {
|
|
168618
|
+
appendReminderToUserMessageById(messages, userMsgId, cached2.hint);
|
|
168619
|
+
return;
|
|
168620
|
+
}
|
|
168621
|
+
const rawPartsText = collectUserPromptParts(userMsg);
|
|
168622
|
+
if (hasStackedAugmentation(rawPartsText)) {
|
|
168623
|
+
sessionLog(sessionId, "auto-search: skipping \u2014 user message already carries augmentation/hint");
|
|
168624
|
+
autoSearchByTurn.set(sessionId, { messageId: userMsgId, hint: "" });
|
|
168625
|
+
return;
|
|
168626
|
+
}
|
|
168627
|
+
const rawPrompt = extractUserPromptText(userMsg);
|
|
168628
|
+
if (rawPrompt.length < options.minPromptChars) {
|
|
168629
|
+
autoSearchByTurn.set(sessionId, { messageId: userMsgId, hint: "" });
|
|
168630
|
+
return;
|
|
168631
|
+
}
|
|
168632
|
+
let results;
|
|
168633
|
+
try {
|
|
168634
|
+
const searchOptions = {
|
|
168635
|
+
limit: 10,
|
|
168636
|
+
memoryEnabled: options.memoryEnabled,
|
|
168637
|
+
embeddingEnabled: options.embeddingEnabled,
|
|
168638
|
+
gitCommitsEnabled: options.gitCommitsEnabled,
|
|
168639
|
+
visibleMemoryIds: options.visibleMemoryIds ?? null
|
|
168640
|
+
};
|
|
168641
|
+
results = await unifiedSearchWithTimeout(db, sessionId, options.projectPath, rawPrompt, searchOptions, AUTO_SEARCH_TIMEOUT_MS);
|
|
168642
|
+
} catch (error48) {
|
|
168643
|
+
log(`[auto-search] unified search failed for session ${sessionId}: ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
168644
|
+
autoSearchByTurn.set(sessionId, { messageId: userMsgId, hint: "" });
|
|
168645
|
+
return;
|
|
168646
|
+
}
|
|
168647
|
+
if (results === null) {
|
|
168648
|
+
sessionLog(sessionId, `auto-search: timed out after ${AUTO_SEARCH_TIMEOUT_MS}ms, skipping hint for this turn`);
|
|
168649
|
+
autoSearchByTurn.set(sessionId, { messageId: userMsgId, hint: "" });
|
|
168650
|
+
return;
|
|
168651
|
+
}
|
|
168652
|
+
if (results.length === 0) {
|
|
168653
|
+
autoSearchByTurn.set(sessionId, { messageId: userMsgId, hint: "" });
|
|
168654
|
+
return;
|
|
168655
|
+
}
|
|
168656
|
+
if (results[0].score < options.scoreThreshold) {
|
|
168657
|
+
sessionLog(sessionId, `auto-search: top score ${results[0].score.toFixed(3)} below threshold ${options.scoreThreshold}`);
|
|
168658
|
+
autoSearchByTurn.set(sessionId, { messageId: userMsgId, hint: "" });
|
|
168659
|
+
return;
|
|
168660
|
+
}
|
|
168661
|
+
const hintText = buildAutoSearchHint(results);
|
|
168662
|
+
if (!hintText) {
|
|
168663
|
+
autoSearchByTurn.set(sessionId, { messageId: userMsgId, hint: "" });
|
|
168664
|
+
return;
|
|
168665
|
+
}
|
|
168666
|
+
const payload = `
|
|
168667
|
+
|
|
168668
|
+
${hintText}`;
|
|
168669
|
+
autoSearchByTurn.set(sessionId, { messageId: userMsgId, hint: payload });
|
|
168670
|
+
appendReminderToUserMessageById(messages, userMsgId, payload);
|
|
168671
|
+
sessionLog(sessionId, `auto-search: attached hint to ${userMsgId} (${results.length} fragments, top score ${results[0].score.toFixed(3)})`);
|
|
168672
|
+
}
|
|
168673
|
+
function clearAutoSearchForSession(sessionId) {
|
|
168674
|
+
autoSearchByTurn.delete(sessionId);
|
|
168675
|
+
}
|
|
168676
|
+
|
|
166927
168677
|
// src/hooks/magic-context/transform-postprocess-phase.ts
|
|
166928
168678
|
init_compartment_runner();
|
|
166929
168679
|
|
|
@@ -167151,7 +168901,7 @@ function logTransformTiming(sessionId, stage, startMs, extra) {
|
|
|
167151
168901
|
}
|
|
167152
168902
|
|
|
167153
168903
|
// src/hooks/magic-context/transform-postprocess-phase.ts
|
|
167154
|
-
function runPostTransformPhase(args) {
|
|
168904
|
+
async function runPostTransformPhase(args) {
|
|
167155
168905
|
let didMutateFromPendingOperations = false;
|
|
167156
168906
|
const isExplicitFlush = args.flushedSessions.has(args.sessionId);
|
|
167157
168907
|
const alreadyRanThisTurn = args.currentTurnId !== null && args.lastHeuristicsTurnId.get(args.sessionId) === args.currentTurnId;
|
|
@@ -167211,8 +168961,8 @@ function runPostTransformPhase(args) {
|
|
|
167211
168961
|
logTransformTiming(args.sessionId, "watermarkCleanup", t6);
|
|
167212
168962
|
}
|
|
167213
168963
|
const t7 = performance.now();
|
|
167214
|
-
const clearedReasoning = clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge);
|
|
167215
|
-
stripClearedReasoning(args.messages);
|
|
168964
|
+
const clearedReasoning = clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge, args.skipTypedReasoningCleanup);
|
|
168965
|
+
stripClearedReasoning(args.messages, args.skipTypedReasoningCleanup);
|
|
167216
168966
|
const strippedInline = stripInlineThinking(args.messages, args.messageTagNumbers, args.clearReasoningAge);
|
|
167217
168967
|
if (clearedReasoning > 0 || strippedInline > 0) {
|
|
167218
168968
|
let maxTag = 0;
|
|
@@ -167226,6 +168976,7 @@ function runPostTransformPhase(args) {
|
|
|
167226
168976
|
updateSessionMeta(args.db, args.sessionId, {
|
|
167227
168977
|
clearedReasoningThroughTag: newWatermark
|
|
167228
168978
|
});
|
|
168979
|
+
args.sessionMeta.clearedReasoningThroughTag = newWatermark;
|
|
167229
168980
|
sessionLog(args.sessionId, `reasoning cleanup: cleared=${clearedReasoning} inlineStripped=${strippedInline} watermark=${currentWatermark}\u2192${newWatermark}`);
|
|
167230
168981
|
} else {
|
|
167231
168982
|
sessionLog(args.sessionId, `reasoning cleanup: cleared=${clearedReasoning} inlineStripped=${strippedInline} watermark=${currentWatermark} (unchanged)`);
|
|
@@ -167276,55 +169027,31 @@ function runPostTransformPhase(args) {
|
|
|
167276
169027
|
{
|
|
167277
169028
|
const persistedIds = getStrippedPlaceholderIds(args.db, args.sessionId);
|
|
167278
169029
|
if (persistedIds.size > 0) {
|
|
167279
|
-
|
|
167280
|
-
for (let i = args.messages.length - 1;i >= 0; i--) {
|
|
167281
|
-
const msgId = args.messages[i].info.id;
|
|
167282
|
-
if (msgId && persistedIds.has(msgId)) {
|
|
167283
|
-
args.messages.splice(i, 1);
|
|
167284
|
-
replayed++;
|
|
167285
|
-
}
|
|
167286
|
-
}
|
|
169030
|
+
const { replayed, missingIds } = replaySentinelByMessageIds(args.messages, persistedIds);
|
|
167287
169031
|
if (replayed > 0) {
|
|
167288
|
-
sessionLog(args.sessionId, `
|
|
169032
|
+
sessionLog(args.sessionId, `sentinel replay: neutralized ${replayed} previously-stripped messages`);
|
|
169033
|
+
}
|
|
169034
|
+
if (missingIds.length > 0) {
|
|
169035
|
+
for (const id of missingIds)
|
|
169036
|
+
persistedIds.delete(id);
|
|
169037
|
+
setStrippedPlaceholderIds(args.db, args.sessionId, persistedIds);
|
|
167289
169038
|
}
|
|
167290
169039
|
}
|
|
167291
169040
|
if (isCacheBustingPass) {
|
|
167292
|
-
const
|
|
167293
|
-
|
|
167294
|
-
|
|
167295
|
-
|
|
167296
|
-
|
|
167297
|
-
|
|
167298
|
-
|
|
167299
|
-
const
|
|
167300
|
-
|
|
167301
|
-
if (msg.info.id)
|
|
167302
|
-
postStripIds.add(msg.info.id);
|
|
167303
|
-
}
|
|
167304
|
-
let newlyStrippedCount = 0;
|
|
167305
|
-
for (const id of preStripIds) {
|
|
167306
|
-
if (!postStripIds.has(id)) {
|
|
167307
|
-
persistedIds.add(id);
|
|
167308
|
-
newlyStrippedCount++;
|
|
167309
|
-
}
|
|
167310
|
-
}
|
|
167311
|
-
for (const id of persistedIds) {
|
|
167312
|
-
if (!preStripIds.has(id) && !postStripIds.has(id)) {
|
|
167313
|
-
persistedIds.delete(id);
|
|
167314
|
-
}
|
|
167315
|
-
}
|
|
169041
|
+
const droppedResult = stripDroppedPlaceholderMessages(args.messages);
|
|
169042
|
+
const protectedTailStart = Math.max(0, args.messages.length - args.protectedTags * 2);
|
|
169043
|
+
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart);
|
|
169044
|
+
const newlyNeutralized = droppedResult.sentineledIds.length + systemInjectedResult.sentineledIds.length;
|
|
169045
|
+
if (newlyNeutralized > 0) {
|
|
169046
|
+
for (const id of droppedResult.sentineledIds)
|
|
169047
|
+
persistedIds.add(id);
|
|
169048
|
+
for (const id of systemInjectedResult.sentineledIds)
|
|
169049
|
+
persistedIds.add(id);
|
|
167316
169050
|
setStrippedPlaceholderIds(args.db, args.sessionId, persistedIds);
|
|
167317
|
-
sessionLog(args.sessionId, `stripped ${
|
|
169051
|
+
sessionLog(args.sessionId, `neutralized ${droppedResult.stripped} dropped + ${systemInjectedResult.stripped} system-injected messages (${newlyNeutralized} new, ${persistedIds.size} total persisted)`);
|
|
167318
169052
|
}
|
|
167319
169053
|
}
|
|
167320
169054
|
}
|
|
167321
|
-
if (isCacheBustingPass) {
|
|
167322
|
-
const protectedTailStart = Math.max(0, args.messages.length - args.protectedTags * 2);
|
|
167323
|
-
const strippedSystemInjected = stripSystemInjectedMessages(args.messages, protectedTailStart);
|
|
167324
|
-
if (strippedSystemInjected > 0) {
|
|
167325
|
-
sessionLog(args.sessionId, `stripped ${strippedSystemInjected} system-injected messages (notifications/reminders)`);
|
|
167326
|
-
}
|
|
167327
|
-
}
|
|
167328
169055
|
const pendingUserTurnReminder = getPersistedStickyTurnReminder(args.db, args.sessionId);
|
|
167329
169056
|
if (pendingUserTurnReminder) {
|
|
167330
169057
|
if (args.hasRecentReduceCall && isCacheBustingPass) {
|
|
@@ -167392,6 +169119,28 @@ function runPostTransformPhase(args) {
|
|
|
167392
169119
|
const anchoredMessageId = appendReminderToLatestUserMessage(args.messages, noteInstruction);
|
|
167393
169120
|
markNoteNudgeDelivered(args.db, args.sessionId, noteInstruction, anchoredMessageId);
|
|
167394
169121
|
}
|
|
169122
|
+
if (args.fullFeatureMode && args.autoSearch?.enabled && args.projectPath) {
|
|
169123
|
+
const visibleMemoryIds = getVisibleMemoryIds(args.db, args.sessionId) ?? undefined;
|
|
169124
|
+
try {
|
|
169125
|
+
await runAutoSearchHint({
|
|
169126
|
+
sessionId: args.sessionId,
|
|
169127
|
+
db: args.db,
|
|
169128
|
+
messages: args.messages,
|
|
169129
|
+
options: {
|
|
169130
|
+
enabled: true,
|
|
169131
|
+
scoreThreshold: args.autoSearch.scoreThreshold,
|
|
169132
|
+
minPromptChars: args.autoSearch.minPromptChars,
|
|
169133
|
+
projectPath: args.projectPath,
|
|
169134
|
+
memoryEnabled: args.autoSearch.memoryEnabled,
|
|
169135
|
+
embeddingEnabled: args.autoSearch.embeddingEnabled,
|
|
169136
|
+
gitCommitsEnabled: args.autoSearch.gitCommitsEnabled,
|
|
169137
|
+
visibleMemoryIds
|
|
169138
|
+
}
|
|
169139
|
+
});
|
|
169140
|
+
} catch (error48) {
|
|
169141
|
+
sessionLog(args.sessionId, "auto-search runner failed:", error48);
|
|
169142
|
+
}
|
|
169143
|
+
}
|
|
167395
169144
|
}
|
|
167396
169145
|
|
|
167397
169146
|
// src/hooks/magic-context/nudge-placement-store.ts
|
|
@@ -167503,10 +169252,20 @@ function createTransform(deps) {
|
|
|
167503
169252
|
deps.liveModelBySession.set(sessionId, lastAssistantModel);
|
|
167504
169253
|
updateSessionMeta(db, sessionId, {
|
|
167505
169254
|
lastContextPercentage: 0,
|
|
167506
|
-
lastInputTokens: 0
|
|
169255
|
+
lastInputTokens: 0,
|
|
169256
|
+
clearedReasoningThroughTag: 0
|
|
167507
169257
|
});
|
|
167508
169258
|
clearHistorianFailureState(db, sessionId);
|
|
169259
|
+
clearPersistedReasoningWatermark(db, sessionId);
|
|
169260
|
+
clearDetectedContextLimit(db, sessionId);
|
|
169261
|
+
clearEmergencyRecovery(db, sessionId);
|
|
167509
169262
|
deps.contextUsageMap.delete(sessionId);
|
|
169263
|
+
sessionMeta = {
|
|
169264
|
+
...sessionMeta,
|
|
169265
|
+
lastContextPercentage: 0,
|
|
169266
|
+
lastInputTokens: 0,
|
|
169267
|
+
clearedReasoningThroughTag: 0
|
|
169268
|
+
};
|
|
167510
169269
|
}
|
|
167511
169270
|
}
|
|
167512
169271
|
}
|
|
@@ -167528,7 +169287,21 @@ function createTransform(deps) {
|
|
|
167528
169287
|
sessionMeta = { ...sessionMeta, lastContextPercentage: 0, lastInputTokens: 0 };
|
|
167529
169288
|
}
|
|
167530
169289
|
}
|
|
167531
|
-
|
|
169290
|
+
let contextUsageEarly = loadContextUsage(deps.contextUsageMap, db, sessionId);
|
|
169291
|
+
if (fullFeatureMode) {
|
|
169292
|
+
try {
|
|
169293
|
+
const overflowState = getOverflowState(db, sessionId);
|
|
169294
|
+
if (overflowState.needsEmergencyRecovery && contextUsageEarly.percentage < 95) {
|
|
169295
|
+
sessionLog(sessionId, `transform: bumping percentage to 95% due to overflow recovery flag (was ${contextUsageEarly.percentage.toFixed(1)}%, detectedLimit=${overflowState.detectedContextLimit || "unknown"})`);
|
|
169296
|
+
contextUsageEarly = {
|
|
169297
|
+
...contextUsageEarly,
|
|
169298
|
+
percentage: 95
|
|
169299
|
+
};
|
|
169300
|
+
}
|
|
169301
|
+
} catch (error48) {
|
|
169302
|
+
sessionLog(sessionId, "transform: overflow recovery state read failed:", getErrorMessage(error48));
|
|
169303
|
+
}
|
|
169304
|
+
}
|
|
167532
169305
|
const historyBudgetTokens = resolveHistoryBudgetTokens(deps.historyBudgetPercentage, contextUsageEarly, deps.executeThresholdPercentage, deps.getModelKey?.(sessionId), deps.executeThresholdTokens);
|
|
167533
169306
|
const schedulerDecisionEarly = resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId));
|
|
167534
169307
|
const isCacheBusting = deps.flushedSessions.has(sessionId);
|
|
@@ -167567,7 +169340,10 @@ function createTransform(deps) {
|
|
|
167567
169340
|
experimentalTemporalAwareness: deps.experimentalTemporalAwareness,
|
|
167568
169341
|
historianTwoPass: deps.historianTwoPass,
|
|
167569
169342
|
compressorMinCompartmentRatio: deps.compressorMinCompartmentRatio,
|
|
167570
|
-
compressorMaxMergeDepth: deps.compressorMaxMergeDepth
|
|
169343
|
+
compressorMaxMergeDepth: deps.compressorMaxMergeDepth,
|
|
169344
|
+
onInjectionCacheCleared: (sid) => {
|
|
169345
|
+
deps.flushedSessions.add(sid);
|
|
169346
|
+
}
|
|
167571
169347
|
});
|
|
167572
169348
|
skipCompartmentAwaitForThisPass = true;
|
|
167573
169349
|
return true;
|
|
@@ -167657,10 +169433,12 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
167657
169433
|
const t3 = performance.now();
|
|
167658
169434
|
const strippedStructuralNoise = stripStructuralNoise(messages);
|
|
167659
169435
|
logTransformTiming(sessionId, "stripStructuralNoise", t3, `strippedParts=${strippedStructuralNoise}`);
|
|
169436
|
+
const currentSessionModel = deps.liveModelBySession?.get(sessionId) ?? findLastAssistantModel(messages) ?? undefined;
|
|
169437
|
+
const skipTypedReasoningCleanup = modelRequiresInterleavedReasoning(currentSessionModel);
|
|
167660
169438
|
const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
|
|
167661
169439
|
if (persistedReasoningWatermark > 0) {
|
|
167662
169440
|
const tReplay = performance.now();
|
|
167663
|
-
const replayed = replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedReasoningWatermark);
|
|
169441
|
+
const replayed = replayClearedReasoning(messages, reasoningByMessage, messageTagNumbers, persistedReasoningWatermark, skipTypedReasoningCleanup);
|
|
167664
169442
|
const replayedInline = replayStrippedInlineThinking(messages, messageTagNumbers, persistedReasoningWatermark);
|
|
167665
169443
|
if (replayed > 0 || replayedInline > 0) {
|
|
167666
169444
|
sessionLog(sessionId, `reasoning replay: cleared=${replayed} inlineStripped=${replayedInline} (watermark=${persistedReasoningWatermark})`);
|
|
@@ -167668,10 +169446,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
167668
169446
|
logTransformTiming(sessionId, "replayReasoningClearing", tReplay);
|
|
167669
169447
|
}
|
|
167670
169448
|
const t4 = performance.now();
|
|
167671
|
-
const strippedClearedReasoning = stripClearedReasoning(messages);
|
|
169449
|
+
const strippedClearedReasoning = stripClearedReasoning(messages, skipTypedReasoningCleanup);
|
|
167672
169450
|
logTransformTiming(sessionId, "stripClearedReasoning", t4, `strippedParts=${strippedClearedReasoning}`);
|
|
167673
169451
|
const tMergeStrip = performance.now();
|
|
167674
|
-
const strippedMergedReasoning = stripReasoningFromMergedAssistants(messages);
|
|
169452
|
+
const strippedMergedReasoning = skipTypedReasoningCleanup ? 0 : stripReasoningFromMergedAssistants(messages);
|
|
167675
169453
|
if (strippedMergedReasoning > 0) {
|
|
167676
169454
|
sessionLog(sessionId, `stripped ${strippedMergedReasoning} reasoning parts from merged assistants (anthropic groupIntoBlocks workaround)`);
|
|
167677
169455
|
}
|
|
@@ -167713,7 +169491,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
167713
169491
|
historianTwoPass: deps.historianTwoPass,
|
|
167714
169492
|
compressorMinCompartmentRatio: deps.compressorMinCompartmentRatio,
|
|
167715
169493
|
compressorMaxMergeDepth: deps.compressorMaxMergeDepth,
|
|
167716
|
-
compressorCooldownMs: deps.compressorCooldownMs
|
|
169494
|
+
compressorCooldownMs: deps.compressorCooldownMs,
|
|
169495
|
+
onInjectionCacheCleared: (sid) => {
|
|
169496
|
+
deps.flushedSessions.add(sid);
|
|
169497
|
+
}
|
|
167717
169498
|
});
|
|
167718
169499
|
pendingCompartmentInjection = compartmentPhase.pendingCompartmentInjection;
|
|
167719
169500
|
const awaitedCompartmentRun = compartmentPhase.awaitedCompartmentRun;
|
|
@@ -167721,7 +169502,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
167721
169502
|
sessionMeta = { ...sessionMeta, compartmentInProgress };
|
|
167722
169503
|
logTransformTiming(sessionId, "compartmentPhase", tCompartmentPhase);
|
|
167723
169504
|
const tPostProcess = performance.now();
|
|
167724
|
-
runPostTransformPhase({
|
|
169505
|
+
await runPostTransformPhase({
|
|
167725
169506
|
sessionId,
|
|
167726
169507
|
db,
|
|
167727
169508
|
messages,
|
|
@@ -167751,7 +169532,9 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so ma
|
|
|
167751
169532
|
watermark,
|
|
167752
169533
|
forceMaterializationPercentage: FORCE_MATERIALIZE_PERCENTAGE,
|
|
167753
169534
|
hasRecentReduceCall,
|
|
167754
|
-
|
|
169535
|
+
skipTypedReasoningCleanup,
|
|
169536
|
+
projectPath: deps.projectPath,
|
|
169537
|
+
autoSearch: deps.autoSearch
|
|
167755
169538
|
});
|
|
167756
169539
|
logTransformTiming(sessionId, "postTransformPhase", tPostProcess);
|
|
167757
169540
|
const msgTokens = getMessageTokensCache(sessionId);
|
|
@@ -167971,6 +169754,25 @@ function createEventHandler2(deps) {
|
|
|
167971
169754
|
}
|
|
167972
169755
|
return;
|
|
167973
169756
|
}
|
|
169757
|
+
if (input.event.type === "session.error") {
|
|
169758
|
+
const errInfo = getSessionErrorInfo(input.event.properties);
|
|
169759
|
+
if (!errInfo) {
|
|
169760
|
+
return;
|
|
169761
|
+
}
|
|
169762
|
+
try {
|
|
169763
|
+
const detection = detectOverflow(errInfo.error);
|
|
169764
|
+
if (!detection.isOverflow) {
|
|
169765
|
+
return;
|
|
169766
|
+
}
|
|
169767
|
+
const existing = getOverflowState(deps.db, errInfo.sessionID);
|
|
169768
|
+
recordOverflowDetected(deps.db, errInfo.sessionID, detection.reportedLimit);
|
|
169769
|
+
sessionLog(errInfo.sessionID, `overflow detected via session.error: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"} (previousRecovery=${existing.needsEmergencyRecovery})`);
|
|
169770
|
+
deps.onSessionCacheInvalidated?.(errInfo.sessionID);
|
|
169771
|
+
} catch (error48) {
|
|
169772
|
+
sessionLog(errInfo.sessionID, "event session.error handling failed:", error48);
|
|
169773
|
+
}
|
|
169774
|
+
return;
|
|
169775
|
+
}
|
|
167974
169776
|
if (input.event.type === "message.updated") {
|
|
167975
169777
|
const info = getMessageUpdatedAssistantInfo(input.event.properties);
|
|
167976
169778
|
if (!info) {
|
|
@@ -167987,6 +169789,18 @@ function createEventHandler2(deps) {
|
|
|
167987
169789
|
} else {
|
|
167988
169790
|
clearMessageTokensCache(info.sessionID);
|
|
167989
169791
|
}
|
|
169792
|
+
if (info.error !== undefined && info.error !== null) {
|
|
169793
|
+
const detection = detectOverflow(info.error);
|
|
169794
|
+
if (detection.isOverflow) {
|
|
169795
|
+
try {
|
|
169796
|
+
recordOverflowDetected(deps.db, info.sessionID, detection.reportedLimit);
|
|
169797
|
+
sessionLog(info.sessionID, `overflow detected via message.updated: reportedLimit=${detection.reportedLimit ?? "unknown"} pattern=${detection.matchedPattern ?? "n/a"}`);
|
|
169798
|
+
deps.onSessionCacheInvalidated?.(info.sessionID);
|
|
169799
|
+
} catch (error48) {
|
|
169800
|
+
sessionLog(info.sessionID, "event message.updated overflow persistence failed:", error48);
|
|
169801
|
+
}
|
|
169802
|
+
}
|
|
169803
|
+
}
|
|
167990
169804
|
const now = Date.now();
|
|
167991
169805
|
const usageTokens = [
|
|
167992
169806
|
info.tokens?.input,
|
|
@@ -168012,7 +169826,10 @@ function createEventHandler2(deps) {
|
|
|
168012
169826
|
}
|
|
168013
169827
|
if (hasUsageTokens) {
|
|
168014
169828
|
const totalInputTokens = (info.tokens?.input ?? 0) + (info.tokens?.cache?.read ?? 0) + (info.tokens?.cache?.write ?? 0);
|
|
168015
|
-
const contextLimit = resolveContextLimit(info.providerID, info.modelID
|
|
169829
|
+
const contextLimit = resolveContextLimit(info.providerID, info.modelID, {
|
|
169830
|
+
db: deps.db,
|
|
169831
|
+
sessionID: info.sessionID
|
|
169832
|
+
});
|
|
168016
169833
|
const percentage = contextLimit > 0 ? totalInputTokens / contextLimit * 100 : 0;
|
|
168017
169834
|
sessionLog(info.sessionID, `event message.updated: totalInputTokens=${totalInputTokens} contextLimit=${contextLimit} percentage=${percentage.toFixed(1)}%`);
|
|
168018
169835
|
deps.contextUsageMap.set(info.sessionID, {
|
|
@@ -168286,29 +170103,6 @@ function estimateProjectedPercentage(db, sessionId, contextUsage, preloadedTags)
|
|
|
168286
170103
|
const dropRatio = pendingDropBytes / totalActiveBytes;
|
|
168287
170104
|
return contextUsage.percentage * (1 - dropRatio);
|
|
168288
170105
|
}
|
|
168289
|
-
function generateEmergencyNudgeText(db, sessionId, contextUsage, config2) {
|
|
168290
|
-
const largest = formatLargestTags(getTopNBySize(db, sessionId, 3));
|
|
168291
|
-
const protectedCount = config2.protected_tags;
|
|
168292
|
-
const activeTags = getTagsBySession(db, sessionId).filter((t) => t.status === "active");
|
|
168293
|
-
const highestProtected = activeTags.map((t) => t.tagNumber).sort((a, b) => b - a).slice(0, protectedCount)[0];
|
|
168294
|
-
const protectedHint = highestProtected ? ` Tags \xA7${highestProtected}\xA7 and above are protected (last ${protectedCount}) \u2014 You MUST NOT try to reduce those.` : "";
|
|
168295
|
-
const oldToolHint = formatOldToolTags(activeTags, protectedCount, 5);
|
|
168296
|
-
return [
|
|
168297
|
-
`<instruction name="context_emergency">`,
|
|
168298
|
-
`CONTEXT EMERGENCY \u2014 ~${Math.round(contextUsage.percentage)}%. STOP all current work immediately.`,
|
|
168299
|
-
``,
|
|
168300
|
-
`You MUST use \`ctx_reduce\` RIGHT NOW to free space. If context overflows, you lose all work.`,
|
|
168301
|
-
``,
|
|
168302
|
-
`Steps:`,
|
|
168303
|
-
`1. Find OLD tool outputs (grep results, file reads, build logs) you already processed \u2014 look at \xA7N\xA7 tags`,
|
|
168304
|
-
`2. Drop those specifically: e.g. drop="3,7,12" \u2014 NEVER drop large ranges like "1-50"`,
|
|
168305
|
-
`3. KEEP anything related to current task, recent errors, or decisions`,
|
|
168306
|
-
``,
|
|
168307
|
-
`Largest tags: ${largest}.${oldToolHint}${protectedHint}`,
|
|
168308
|
-
`</instruction>`
|
|
168309
|
-
].join(`
|
|
168310
|
-
`);
|
|
168311
|
-
}
|
|
168312
170106
|
|
|
168313
170107
|
// src/hooks/magic-context/hook.ts
|
|
168314
170108
|
init_read_session_db();
|
|
@@ -168322,6 +170116,7 @@ function createTextCompleteHandler() {
|
|
|
168322
170116
|
}
|
|
168323
170117
|
|
|
168324
170118
|
// src/hooks/magic-context/hook.ts
|
|
170119
|
+
init_compaction_marker_manager();
|
|
168325
170120
|
init_compartment_runner();
|
|
168326
170121
|
|
|
168327
170122
|
// src/hooks/magic-context/hook-handlers.ts
|
|
@@ -168349,6 +170144,12 @@ function createChatMessageHook(args) {
|
|
|
168349
170144
|
const sessionId = input.sessionID;
|
|
168350
170145
|
if (!sessionId)
|
|
168351
170146
|
return;
|
|
170147
|
+
if (input.model?.providerID && input.model.modelID) {
|
|
170148
|
+
args.liveModelBySession.set(sessionId, {
|
|
170149
|
+
providerID: input.model.providerID,
|
|
170150
|
+
modelID: input.model.modelID
|
|
170151
|
+
});
|
|
170152
|
+
}
|
|
168352
170153
|
if (args.ctxReduceEnabled !== false) {
|
|
168353
170154
|
const sessionMeta = getOrCreateSessionMeta(args.db, sessionId);
|
|
168354
170155
|
const turnUsage = args.toolUsageSinceUserTurn.get(sessionId);
|
|
@@ -168382,8 +170183,12 @@ function createEventHook(args) {
|
|
|
168382
170183
|
modelID: assistantInfo.modelID
|
|
168383
170184
|
});
|
|
168384
170185
|
if (previous && (previous.providerID !== assistantInfo.providerID || previous.modelID !== assistantInfo.modelID)) {
|
|
168385
|
-
sessionLog(assistantInfo.sessionID, `model changed (${previous.providerID}/${previous.modelID} -> ${assistantInfo.providerID}/${assistantInfo.modelID}), clearing historian failure state`);
|
|
170186
|
+
sessionLog(assistantInfo.sessionID, `model changed (${previous.providerID}/${previous.modelID} -> ${assistantInfo.providerID}/${assistantInfo.modelID}), clearing historian failure state and reasoning watermark`);
|
|
168386
170187
|
clearHistorianFailureState(args.db, assistantInfo.sessionID);
|
|
170188
|
+
clearPersistedReasoningWatermark(args.db, assistantInfo.sessionID);
|
|
170189
|
+
updateSessionMeta(args.db, assistantInfo.sessionID, {
|
|
170190
|
+
clearedReasoningThroughTag: 0
|
|
170191
|
+
});
|
|
168387
170192
|
}
|
|
168388
170193
|
}
|
|
168389
170194
|
}
|
|
@@ -168397,57 +170202,11 @@ function createEventHook(args) {
|
|
|
168397
170202
|
args.agentBySession.delete(sessionId);
|
|
168398
170203
|
args.recentReduceBySession.delete(sessionId);
|
|
168399
170204
|
args.toolUsageSinceUserTurn.delete(sessionId);
|
|
168400
|
-
args.emergencyNudgeFired.delete(sessionId);
|
|
168401
170205
|
args.flushedSessions.delete(sessionId);
|
|
168402
170206
|
args.lastHeuristicsTurnId.delete(sessionId);
|
|
168403
170207
|
args.commitSeenLastPass?.delete(sessionId);
|
|
168404
170208
|
clearNoteNudgeState(args.db, sessionId);
|
|
168405
|
-
|
|
168406
|
-
if (input.event.type === "message.removed") {
|
|
168407
|
-
return;
|
|
168408
|
-
}
|
|
168409
|
-
const entry = args.contextUsageMap.get(sessionId);
|
|
168410
|
-
if (!entry)
|
|
168411
|
-
return;
|
|
168412
|
-
if (entry.usage.percentage < FORCE_COMPARTMENT_PERCENTAGE) {
|
|
168413
|
-
args.emergencyNudgeFired.delete(sessionId);
|
|
168414
|
-
return;
|
|
168415
|
-
}
|
|
168416
|
-
if (args.ctxReduceEnabled === false)
|
|
168417
|
-
return;
|
|
168418
|
-
if (args.emergencyNudgeFired.has(sessionId))
|
|
168419
|
-
return;
|
|
168420
|
-
const meta3 = getOrCreateSessionMeta(args.db, sessionId);
|
|
168421
|
-
if (meta3.isSubagent)
|
|
168422
|
-
return;
|
|
168423
|
-
args.emergencyNudgeFired.add(sessionId);
|
|
168424
|
-
updateSessionMeta(args.db, sessionId, { lastNudgeTokens: entry.usage.inputTokens });
|
|
168425
|
-
const nudgeText = generateEmergencyNudgeText(args.db, sessionId, entry.usage, {
|
|
168426
|
-
protected_tags: args.protectedTags
|
|
168427
|
-
});
|
|
168428
|
-
sessionLog(sessionId, "firing 80% emergency nudge as ignored notification");
|
|
168429
|
-
try {
|
|
168430
|
-
const model = args.liveModelBySession.get(sessionId);
|
|
168431
|
-
const variant = args.variantBySession.get(sessionId);
|
|
168432
|
-
const agent = args.agentBySession.get(sessionId);
|
|
168433
|
-
const c = args.client;
|
|
168434
|
-
if (typeof c.session?.promptAsync !== "function") {
|
|
168435
|
-
sessionLog(sessionId, "emergency nudge: promptAsync unavailable");
|
|
168436
|
-
args.emergencyNudgeFired.delete(sessionId);
|
|
168437
|
-
return;
|
|
168438
|
-
}
|
|
168439
|
-
await c.session.promptAsync({
|
|
168440
|
-
path: { id: sessionId },
|
|
168441
|
-
body: {
|
|
168442
|
-
...agent ? { agent } : {},
|
|
168443
|
-
...model ? { model } : {},
|
|
168444
|
-
...variant ? { variant } : {},
|
|
168445
|
-
parts: [{ type: "text", text: nudgeText }]
|
|
168446
|
-
}
|
|
168447
|
-
});
|
|
168448
|
-
} catch (error48) {
|
|
168449
|
-
sessionLog(sessionId, "emergency nudge promptAsync failed:", error48);
|
|
168450
|
-
args.emergencyNudgeFired.delete(sessionId);
|
|
170209
|
+
clearAutoSearchForSession(sessionId);
|
|
168451
170210
|
}
|
|
168452
170211
|
};
|
|
168453
170212
|
}
|
|
@@ -168492,7 +170251,7 @@ init_send_session_notification();
|
|
|
168492
170251
|
|
|
168493
170252
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
168494
170253
|
import { existsSync as existsSync7, readFileSync as readFileSync6, realpathSync } from "fs";
|
|
168495
|
-
import { join as
|
|
170254
|
+
import { join as join15, resolve as resolve3, sep } from "path";
|
|
168496
170255
|
|
|
168497
170256
|
// src/agents/magic-context-prompt.ts
|
|
168498
170257
|
function getToolHistoryGuidance(dropToolStructure) {
|
|
@@ -168711,11 +170470,17 @@ var USER_PROFILE_MARKER = "<user-profile>";
|
|
|
168711
170470
|
var KEY_FILES_MARKER = "<key-files>";
|
|
168712
170471
|
var cachedUserProfileBySession = new Map;
|
|
168713
170472
|
var cachedKeyFilesBySession = new Map;
|
|
170473
|
+
function clearSystemPromptHashSession(sessionId, handleMaps) {
|
|
170474
|
+
cachedUserProfileBySession.delete(sessionId);
|
|
170475
|
+
cachedKeyFilesBySession.delete(sessionId);
|
|
170476
|
+
handleMaps.stickyDateBySession.delete(sessionId);
|
|
170477
|
+
handleMaps.cachedDocsBySession.delete(sessionId);
|
|
170478
|
+
}
|
|
168714
170479
|
var DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
|
|
168715
170480
|
function readProjectDocs(directory) {
|
|
168716
170481
|
const sections = [];
|
|
168717
170482
|
for (const filename of DOC_FILES) {
|
|
168718
|
-
const filePath =
|
|
170483
|
+
const filePath = join15(directory, filename);
|
|
168719
170484
|
try {
|
|
168720
170485
|
if (existsSync7(filePath)) {
|
|
168721
170486
|
const content = readFileSync6(filePath, "utf-8").trim();
|
|
@@ -168741,7 +170506,7 @@ function createSystemPromptHashHandler(deps) {
|
|
|
168741
170506
|
const stickyDateBySession = new Map;
|
|
168742
170507
|
const cachedDocsBySession = new Map;
|
|
168743
170508
|
const shouldInjectDocs = deps.dreamerEnabled && deps.injectDocs;
|
|
168744
|
-
|
|
170509
|
+
const handler = async (input, output) => {
|
|
168745
170510
|
const sessionId = input.sessionID;
|
|
168746
170511
|
if (!sessionId)
|
|
168747
170512
|
return;
|
|
@@ -168908,6 +170673,15 @@ ${sections.join(`
|
|
|
168908
170673
|
updateSessionMeta(deps.db, sessionId, { systemPromptTokens });
|
|
168909
170674
|
}
|
|
168910
170675
|
};
|
|
170676
|
+
return {
|
|
170677
|
+
handler,
|
|
170678
|
+
clearSession: (sessionId) => {
|
|
170679
|
+
clearSystemPromptHashSession(sessionId, {
|
|
170680
|
+
stickyDateBySession,
|
|
170681
|
+
cachedDocsBySession
|
|
170682
|
+
});
|
|
170683
|
+
}
|
|
170684
|
+
};
|
|
168911
170685
|
}
|
|
168912
170686
|
|
|
168913
170687
|
// src/hooks/magic-context/hook.ts
|
|
@@ -168946,6 +170720,13 @@ function createMagicContextHook(deps) {
|
|
|
168946
170720
|
}
|
|
168947
170721
|
const projectPath = resolveProjectIdentity(deps.directory);
|
|
168948
170722
|
registerDreamProjectDirectory(projectPath, deps.directory);
|
|
170723
|
+
if (deps.config.compaction_markers !== false) {
|
|
170724
|
+
try {
|
|
170725
|
+
checkCompactionMarkerConsistency(db);
|
|
170726
|
+
} catch (error48) {
|
|
170727
|
+
log("[magic-context] startup compaction-marker consistency check failed:", error48);
|
|
170728
|
+
}
|
|
170729
|
+
}
|
|
168949
170730
|
let lastScheduleCheckMs = 0;
|
|
168950
170731
|
const getHistorianChunkTokens = () => deriveHistorianChunkTokens(resolveHistorianContextLimit(deps.config.historian?.model));
|
|
168951
170732
|
const nudgePlacements = createNudgePlacementStore(db);
|
|
@@ -169012,13 +170793,21 @@ function createMagicContextHook(deps) {
|
|
|
169012
170793
|
},
|
|
169013
170794
|
projectPath,
|
|
169014
170795
|
experimentalCompactionMarkers: deps.config.compaction_markers,
|
|
169015
|
-
experimentalUserMemories: deps.config.
|
|
170796
|
+
experimentalUserMemories: deps.config.dreamer?.user_memories?.enabled,
|
|
169016
170797
|
experimentalTemporalAwareness: deps.config.experimental?.temporal_awareness === true,
|
|
169017
170798
|
historianTwoPass: deps.config.historian?.two_pass === true,
|
|
169018
170799
|
compressorMinCompartmentRatio: deps.config.compressor?.enabled === false ? undefined : deps.config.compressor?.min_compartment_ratio,
|
|
169019
170800
|
compressorMaxMergeDepth: deps.config.compressor?.enabled === false ? undefined : deps.config.compressor?.max_merge_depth,
|
|
169020
170801
|
compressorCooldownMs: deps.config.compressor?.enabled === false ? undefined : deps.config.compressor?.cooldown_ms,
|
|
169021
|
-
liveModelBySession
|
|
170802
|
+
liveModelBySession,
|
|
170803
|
+
autoSearch: deps.config.experimental?.auto_search?.enabled ? {
|
|
170804
|
+
enabled: true,
|
|
170805
|
+
scoreThreshold: deps.config.experimental.auto_search.score_threshold,
|
|
170806
|
+
minPromptChars: deps.config.experimental.auto_search.min_prompt_chars,
|
|
170807
|
+
memoryEnabled: deps.config.memory?.enabled !== false,
|
|
170808
|
+
embeddingEnabled: deps.config.embedding?.provider !== "off",
|
|
170809
|
+
gitCommitsEnabled: deps.config.experimental?.git_commit_indexing?.enabled === true
|
|
170810
|
+
} : undefined
|
|
169022
170811
|
});
|
|
169023
170812
|
const eventHandler = createEventHandler2({
|
|
169024
170813
|
contextUsageMap,
|
|
@@ -169030,6 +170819,9 @@ function createMagicContextHook(deps) {
|
|
|
169030
170819
|
onSessionCacheInvalidated: (sessionId) => {
|
|
169031
170820
|
clearInjectionCache(sessionId);
|
|
169032
170821
|
deps.onSessionCacheInvalidated?.(sessionId);
|
|
170822
|
+
},
|
|
170823
|
+
onSessionDeleted: (sessionId) => {
|
|
170824
|
+
systemPromptHash.clearSession(sessionId);
|
|
169033
170825
|
}
|
|
169034
170826
|
});
|
|
169035
170827
|
const runDreamQueueInBackground = () => {
|
|
@@ -169054,14 +170846,14 @@ function createMagicContextHook(deps) {
|
|
|
169054
170846
|
tasks: dreaming.tasks,
|
|
169055
170847
|
taskTimeoutMinutes: dreaming.task_timeout_minutes,
|
|
169056
170848
|
maxRuntimeMinutes: dreaming.max_runtime_minutes,
|
|
169057
|
-
experimentalUserMemories: deps.config.
|
|
170849
|
+
experimentalUserMemories: deps.config.dreamer?.user_memories?.enabled ? {
|
|
169058
170850
|
enabled: true,
|
|
169059
|
-
promotionThreshold: deps.config.
|
|
170851
|
+
promotionThreshold: deps.config.dreamer.user_memories.promotion_threshold
|
|
169060
170852
|
} : undefined,
|
|
169061
|
-
experimentalPinKeyFiles: deps.config.
|
|
170853
|
+
experimentalPinKeyFiles: deps.config.dreamer?.pin_key_files?.enabled ? {
|
|
169062
170854
|
enabled: true,
|
|
169063
|
-
token_budget: deps.config.
|
|
169064
|
-
min_reads: deps.config.
|
|
170855
|
+
token_budget: deps.config.dreamer.pin_key_files.token_budget,
|
|
170856
|
+
min_reads: deps.config.dreamer.pin_key_files.min_reads
|
|
169065
170857
|
} : undefined
|
|
169066
170858
|
}).catch((error48) => {
|
|
169067
170859
|
log("[dreamer] scheduled queue processing failed:", error48);
|
|
@@ -169098,7 +170890,10 @@ function createMagicContextHook(deps) {
|
|
|
169098
170890
|
return model ? `${model.providerID}/${model.modelID}` : undefined;
|
|
169099
170891
|
})(),
|
|
169100
170892
|
getNotificationParams: () => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
|
|
169101
|
-
historianTwoPass: deps.config.historian?.two_pass === true
|
|
170893
|
+
historianTwoPass: deps.config.historian?.two_pass === true,
|
|
170894
|
+
onInjectionCacheCleared: (sid) => {
|
|
170895
|
+
flushedSessions.add(sid);
|
|
170896
|
+
}
|
|
169102
170897
|
}, options),
|
|
169103
170898
|
sendNotification: async (sessionId, text, params) => {
|
|
169104
170899
|
await sendIgnoredMessage(deps.client, sessionId, text, {
|
|
@@ -169117,19 +170912,18 @@ function createMagicContextHook(deps) {
|
|
|
169117
170912
|
projectPath,
|
|
169118
170913
|
client: deps.client,
|
|
169119
170914
|
directory: deps.directory,
|
|
169120
|
-
experimentalUserMemories: deps.config.
|
|
170915
|
+
experimentalUserMemories: deps.config.dreamer?.user_memories?.enabled ? {
|
|
169121
170916
|
enabled: true,
|
|
169122
|
-
promotionThreshold: deps.config.
|
|
170917
|
+
promotionThreshold: deps.config.dreamer.user_memories.promotion_threshold
|
|
169123
170918
|
} : undefined,
|
|
169124
|
-
experimentalPinKeyFiles: deps.config.
|
|
170919
|
+
experimentalPinKeyFiles: deps.config.dreamer?.pin_key_files?.enabled ? {
|
|
169125
170920
|
enabled: true,
|
|
169126
|
-
token_budget: deps.config.
|
|
169127
|
-
min_reads: deps.config.
|
|
170921
|
+
token_budget: deps.config.dreamer.pin_key_files.token_budget,
|
|
170922
|
+
min_reads: deps.config.dreamer.pin_key_files.min_reads
|
|
169128
170923
|
} : undefined
|
|
169129
170924
|
} : undefined
|
|
169130
170925
|
});
|
|
169131
|
-
const
|
|
169132
|
-
const systemPromptHashHandler = createSystemPromptHashHandler({
|
|
170926
|
+
const systemPromptHash = createSystemPromptHashHandler({
|
|
169133
170927
|
db,
|
|
169134
170928
|
protectedTags: deps.config.protected_tags,
|
|
169135
170929
|
ctxReduceEnabled,
|
|
@@ -169139,11 +170933,12 @@ function createMagicContextHook(deps) {
|
|
|
169139
170933
|
directory: deps.directory,
|
|
169140
170934
|
flushedSessions,
|
|
169141
170935
|
lastHeuristicsTurnId,
|
|
169142
|
-
experimentalUserMemories: deps.config.
|
|
169143
|
-
experimentalPinKeyFiles: deps.config.
|
|
169144
|
-
experimentalPinKeyFilesTokenBudget: deps.config.
|
|
170936
|
+
experimentalUserMemories: deps.config.dreamer?.user_memories?.enabled,
|
|
170937
|
+
experimentalPinKeyFiles: deps.config.dreamer?.pin_key_files?.enabled ?? false,
|
|
170938
|
+
experimentalPinKeyFilesTokenBudget: deps.config.dreamer?.pin_key_files?.token_budget,
|
|
169145
170939
|
experimentalTemporalAwareness: deps.config.experimental?.temporal_awareness === true
|
|
169146
170940
|
});
|
|
170941
|
+
const systemPromptHashHandler = systemPromptHash.handler;
|
|
169147
170942
|
const eventHook = createEventHook({
|
|
169148
170943
|
eventHandler,
|
|
169149
170944
|
contextUsageMap,
|
|
@@ -169153,7 +170948,6 @@ function createMagicContextHook(deps) {
|
|
|
169153
170948
|
agentBySession,
|
|
169154
170949
|
recentReduceBySession,
|
|
169155
170950
|
toolUsageSinceUserTurn,
|
|
169156
|
-
emergencyNudgeFired,
|
|
169157
170951
|
flushedSessions,
|
|
169158
170952
|
lastHeuristicsTurnId,
|
|
169159
170953
|
commitSeenLastPass,
|
|
@@ -169169,6 +170963,7 @@ function createMagicContextHook(deps) {
|
|
|
169169
170963
|
db,
|
|
169170
170964
|
toolUsageSinceUserTurn,
|
|
169171
170965
|
recentReduceBySession,
|
|
170966
|
+
liveModelBySession,
|
|
169172
170967
|
variantBySession,
|
|
169173
170968
|
agentBySession,
|
|
169174
170969
|
flushedSessions,
|
|
@@ -169226,6 +171021,8 @@ function createSessionHooks(args) {
|
|
|
169226
171021
|
memory: pluginConfig.memory,
|
|
169227
171022
|
sidekick: pluginConfig.sidekick,
|
|
169228
171023
|
dreamer: pluginConfig.dreamer,
|
|
171024
|
+
commit_cluster_trigger: pluginConfig.commit_cluster_trigger,
|
|
171025
|
+
compaction_markers: pluginConfig.compaction_markers,
|
|
169229
171026
|
compressor: pluginConfig.compressor,
|
|
169230
171027
|
experimental: pluginConfig.experimental
|
|
169231
171028
|
}
|
|
@@ -169720,7 +171517,7 @@ var MEMORY_CATEGORIES = new Set(CATEGORY_PRIORITY);
|
|
|
169720
171517
|
function isMemoryCategory2(value) {
|
|
169721
171518
|
return MEMORY_CATEGORIES.has(value);
|
|
169722
171519
|
}
|
|
169723
|
-
function
|
|
171520
|
+
function normalizeLimit2(limit) {
|
|
169724
171521
|
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
169725
171522
|
return DEFAULT_SEARCH_LIMIT2;
|
|
169726
171523
|
}
|
|
@@ -169895,7 +171692,7 @@ function createCtxMemoryTool(deps) {
|
|
|
169895
171692
|
return `Archived memory [ID: ${args.id}].`;
|
|
169896
171693
|
}
|
|
169897
171694
|
if (args.action === "list") {
|
|
169898
|
-
const limit =
|
|
171695
|
+
const limit = normalizeLimit2(args.limit);
|
|
169899
171696
|
const category = normalizeCategory(args.category);
|
|
169900
171697
|
const memories = filterByCategory(getMemoriesByProject(deps.db, deps.projectPath), category).slice(0, limit);
|
|
169901
171698
|
return formatMemoryList(memories);
|
|
@@ -170184,6 +171981,9 @@ ${parts.join(`
|
|
|
170184
171981
|
projectIdentity: deps.projectIdentity,
|
|
170185
171982
|
sessionId
|
|
170186
171983
|
});
|
|
171984
|
+
try {
|
|
171985
|
+
setNoteLastReadAt(deps.db, sessionId);
|
|
171986
|
+
} catch {}
|
|
170187
171987
|
if (sections.length === 0) {
|
|
170188
171988
|
return `## Notes
|
|
170189
171989
|
|
|
@@ -170342,336 +172142,73 @@ function createCtxReduceTools(deps) {
|
|
|
170342
172142
|
}
|
|
170343
172143
|
// src/tools/ctx-search/constants.ts
|
|
170344
172144
|
var CTX_SEARCH_TOOL_NAME = "ctx_search";
|
|
170345
|
-
var CTX_SEARCH_DESCRIPTION =
|
|
172145
|
+
var CTX_SEARCH_DESCRIPTION = [
|
|
172146
|
+
"Search across project memories, indexed git commits, and raw conversation history.",
|
|
172147
|
+
"",
|
|
172148
|
+
"Sources:",
|
|
172149
|
+
"- memory: curated cross-session knowledge (highest-signal; already-visible ones are filtered out)",
|
|
172150
|
+
"- message: raw user/assistant messages from older compartmentalized history",
|
|
172151
|
+
"- git_commit: HEAD git commits (enabled when experimental.git_commit_indexing is on)",
|
|
172152
|
+
"",
|
|
172153
|
+
"Narrow via the `sources` param when the question maps to a specific channel:",
|
|
172154
|
+
'- "was this working before / when did this break" \u2192 ["git_commit", "message"]',
|
|
172155
|
+
'- "when did we change this" \u2192 ["git_commit"]',
|
|
172156
|
+
'- "what is our naming convention" \u2192 ["memory"]',
|
|
172157
|
+
'- "did we discuss this earlier" \u2192 ["message"]',
|
|
172158
|
+
"Omit sources for a broad search across all enabled channels.",
|
|
172159
|
+
"",
|
|
172160
|
+
"Memories already rendered in <session-history> are hard-filtered from results \u2014 the agent already sees them in context.",
|
|
172161
|
+
"Session facts are NOT a search source; they're always visible in <session-history>.",
|
|
172162
|
+
"Message results include ordinals the agent can pass to ctx_expand for full context."
|
|
172163
|
+
].join(`
|
|
172164
|
+
`);
|
|
170346
172165
|
var DEFAULT_CTX_SEARCH_LIMIT = 10;
|
|
170347
172166
|
// src/tools/ctx-search/tools.ts
|
|
170348
172167
|
init_compartment_storage();
|
|
170349
172168
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
170350
|
-
|
|
170351
|
-
|
|
170352
|
-
init_read_session_chunk();
|
|
170353
|
-
init_logger();
|
|
170354
|
-
init_memory();
|
|
170355
|
-
init_embedding();
|
|
170356
|
-
init_storage_memory_fts();
|
|
170357
|
-
init_message_index();
|
|
170358
|
-
init_storage();
|
|
170359
|
-
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
170360
|
-
var FTS_SEMANTIC_CANDIDATE_LIMIT = 50;
|
|
170361
|
-
var SEMANTIC_WEIGHT = 0.7;
|
|
170362
|
-
var FTS_WEIGHT = 0.3;
|
|
170363
|
-
var SINGLE_SOURCE_PENALTY = 0.8;
|
|
170364
|
-
var RESULT_PREVIEW_LIMIT = 220;
|
|
170365
|
-
var MEMORY_SOURCE_BOOST = 1.3;
|
|
170366
|
-
var FACT_SOURCE_BOOST = 1.15;
|
|
170367
|
-
var MESSAGE_SOURCE_BOOST = 1;
|
|
170368
|
-
var messageSearchStatements = new WeakMap;
|
|
170369
|
-
function normalizeLimit2(limit) {
|
|
170370
|
-
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
170371
|
-
return DEFAULT_UNIFIED_SEARCH_LIMIT;
|
|
170372
|
-
}
|
|
170373
|
-
return Math.max(1, Math.floor(limit));
|
|
170374
|
-
}
|
|
170375
|
-
function normalizeCosineScore(score) {
|
|
170376
|
-
if (!Number.isFinite(score)) {
|
|
170377
|
-
return 0;
|
|
170378
|
-
}
|
|
170379
|
-
return Math.min(1, Math.max(0, score));
|
|
170380
|
-
}
|
|
170381
|
-
function previewText(text) {
|
|
170382
|
-
const normalized = text.replace(/\s+/g, " ").trim();
|
|
170383
|
-
if (normalized.length <= RESULT_PREVIEW_LIMIT) {
|
|
170384
|
-
return normalized;
|
|
170385
|
-
}
|
|
170386
|
-
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}\u2026`;
|
|
170387
|
-
}
|
|
170388
|
-
function tokenizeQuery(query) {
|
|
170389
|
-
return Array.from(new Set(query.toLowerCase().split(/\s+/).map((token) => token.trim()).filter((token) => token.length > 0)));
|
|
170390
|
-
}
|
|
170391
|
-
function scoreTextMatch(content, query, extraText = "") {
|
|
170392
|
-
const tokens = tokenizeQuery(query);
|
|
170393
|
-
if (tokens.length === 0) {
|
|
170394
|
-
return 0;
|
|
170395
|
-
}
|
|
170396
|
-
const haystack = `${content} ${extraText}`.toLowerCase();
|
|
170397
|
-
const queryLower = query.trim().toLowerCase();
|
|
170398
|
-
let matchedTokens = 0;
|
|
170399
|
-
for (const token of tokens) {
|
|
170400
|
-
if (haystack.includes(token)) {
|
|
170401
|
-
matchedTokens++;
|
|
170402
|
-
}
|
|
170403
|
-
}
|
|
170404
|
-
if (matchedTokens === 0) {
|
|
170405
|
-
return 0;
|
|
170406
|
-
}
|
|
170407
|
-
let score = matchedTokens / tokens.length;
|
|
170408
|
-
if (queryLower.length > 0 && haystack.includes(queryLower)) {
|
|
170409
|
-
score += 0.35;
|
|
170410
|
-
}
|
|
170411
|
-
return Math.min(1, score);
|
|
170412
|
-
}
|
|
170413
|
-
function getMessageSearchStatement(db) {
|
|
170414
|
-
let stmt = messageSearchStatements.get(db);
|
|
170415
|
-
if (!stmt) {
|
|
170416
|
-
stmt = db.prepare("SELECT message_ordinal AS messageOrdinal, message_id AS messageId, role, content FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ? ORDER BY bm25(message_history_fts), CAST(message_ordinal AS INTEGER) ASC LIMIT ?");
|
|
170417
|
-
messageSearchStatements.set(db, stmt);
|
|
170418
|
-
}
|
|
170419
|
-
return stmt;
|
|
170420
|
-
}
|
|
170421
|
-
function getMessageOrdinal(value) {
|
|
170422
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
170423
|
-
return value;
|
|
170424
|
-
}
|
|
170425
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
170426
|
-
const parsed = Number.parseInt(value, 10);
|
|
170427
|
-
return Number.isFinite(parsed) ? parsed : null;
|
|
170428
|
-
}
|
|
170429
|
-
return null;
|
|
170430
|
-
}
|
|
170431
|
-
async function getSemanticScores(args) {
|
|
170432
|
-
const semanticScores = new Map;
|
|
170433
|
-
if (!args.embeddingEnabled || !args.isEmbeddingRuntimeEnabled() || args.memories.length === 0) {
|
|
170434
|
-
return semanticScores;
|
|
170435
|
-
}
|
|
170436
|
-
const queryEmbedding = await args.embedQuery(args.query);
|
|
170437
|
-
if (!queryEmbedding) {
|
|
170438
|
-
return semanticScores;
|
|
170439
|
-
}
|
|
170440
|
-
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
170441
|
-
const embeddings = await ensureMemoryEmbeddings({
|
|
170442
|
-
db: args.db,
|
|
170443
|
-
memories: args.memories,
|
|
170444
|
-
existingEmbeddings: cachedEmbeddings
|
|
170445
|
-
});
|
|
170446
|
-
for (const memory of args.memories) {
|
|
170447
|
-
const memoryEmbedding = embeddings.get(memory.id);
|
|
170448
|
-
if (!memoryEmbedding) {
|
|
170449
|
-
continue;
|
|
170450
|
-
}
|
|
170451
|
-
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(queryEmbedding, memoryEmbedding)));
|
|
170452
|
-
}
|
|
170453
|
-
return semanticScores;
|
|
170454
|
-
}
|
|
170455
|
-
function getFtsMatches(args) {
|
|
170456
|
-
try {
|
|
170457
|
-
return searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
170458
|
-
} catch (error48) {
|
|
170459
|
-
log(`[search] FTS query failed for "${args.query}": ${error48 instanceof Error ? error48.message : String(error48)}`);
|
|
170460
|
-
return [];
|
|
170461
|
-
}
|
|
170462
|
-
}
|
|
170463
|
-
function getFtsScores(matches) {
|
|
170464
|
-
return new Map(matches.map((memory, rank) => [memory.id, 1 / (rank + 1)]));
|
|
170465
|
-
}
|
|
170466
|
-
function selectSemanticCandidates(args) {
|
|
170467
|
-
if (args.ftsMatches.length === 0) {
|
|
170468
|
-
return args.memories;
|
|
170469
|
-
}
|
|
170470
|
-
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
170471
|
-
const cachedEmbeddings = peekProjectEmbeddings(args.projectPath);
|
|
170472
|
-
if (cachedEmbeddings) {
|
|
170473
|
-
for (const memoryId of cachedEmbeddings.keys()) {
|
|
170474
|
-
candidateIds.add(memoryId);
|
|
170475
|
-
}
|
|
170476
|
-
}
|
|
170477
|
-
return args.memories.filter((memory) => candidateIds.has(memory.id));
|
|
170478
|
-
}
|
|
170479
|
-
function mergeMemoryResults(args) {
|
|
170480
|
-
const memoryById = new Map(args.memories.map((memory) => [memory.id, memory]));
|
|
170481
|
-
const candidateIds = new Set([...args.semanticScores.keys(), ...args.ftsScores.keys()]);
|
|
170482
|
-
const results = [];
|
|
170483
|
-
for (const id of candidateIds) {
|
|
170484
|
-
const memory = memoryById.get(id);
|
|
170485
|
-
if (!memory) {
|
|
170486
|
-
continue;
|
|
170487
|
-
}
|
|
170488
|
-
const semanticScore = args.semanticScores.get(id);
|
|
170489
|
-
const ftsScore = args.ftsScores.get(id);
|
|
170490
|
-
let score = 0;
|
|
170491
|
-
let matchType = "fts";
|
|
170492
|
-
if (semanticScore !== undefined && ftsScore !== undefined) {
|
|
170493
|
-
score = SEMANTIC_WEIGHT * semanticScore + FTS_WEIGHT * ftsScore;
|
|
170494
|
-
matchType = "hybrid";
|
|
170495
|
-
} else if (semanticScore !== undefined) {
|
|
170496
|
-
score = semanticScore * SINGLE_SOURCE_PENALTY;
|
|
170497
|
-
matchType = "semantic";
|
|
170498
|
-
} else if (ftsScore !== undefined) {
|
|
170499
|
-
score = ftsScore * SINGLE_SOURCE_PENALTY;
|
|
170500
|
-
matchType = "fts";
|
|
170501
|
-
}
|
|
170502
|
-
if (score <= 0) {
|
|
170503
|
-
continue;
|
|
170504
|
-
}
|
|
170505
|
-
results.push({
|
|
170506
|
-
source: "memory",
|
|
170507
|
-
content: previewText(memory.content),
|
|
170508
|
-
score,
|
|
170509
|
-
memoryId: memory.id,
|
|
170510
|
-
category: memory.category,
|
|
170511
|
-
matchType
|
|
170512
|
-
});
|
|
170513
|
-
}
|
|
170514
|
-
return results.sort((left, right) => {
|
|
170515
|
-
if (right.score !== left.score) {
|
|
170516
|
-
return right.score - left.score;
|
|
170517
|
-
}
|
|
170518
|
-
return left.memoryId - right.memoryId;
|
|
170519
|
-
}).slice(0, args.limit);
|
|
170520
|
-
}
|
|
170521
|
-
async function searchMemories(args) {
|
|
170522
|
-
if (!args.memoryEnabled) {
|
|
170523
|
-
return [];
|
|
170524
|
-
}
|
|
170525
|
-
const memories = getMemoriesByProject(args.db, args.projectPath);
|
|
170526
|
-
if (memories.length === 0) {
|
|
170527
|
-
return [];
|
|
170528
|
-
}
|
|
170529
|
-
const ftsMatches = getFtsMatches({
|
|
170530
|
-
db: args.db,
|
|
170531
|
-
projectPath: args.projectPath,
|
|
170532
|
-
query: args.query,
|
|
170533
|
-
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
170534
|
-
});
|
|
170535
|
-
const ftsScores = getFtsScores(ftsMatches);
|
|
170536
|
-
const semanticCandidates = selectSemanticCandidates({
|
|
170537
|
-
memories,
|
|
170538
|
-
projectPath: args.projectPath,
|
|
170539
|
-
ftsMatches
|
|
170540
|
-
});
|
|
170541
|
-
const semanticScores = await getSemanticScores({
|
|
170542
|
-
db: args.db,
|
|
170543
|
-
projectPath: args.projectPath,
|
|
170544
|
-
query: args.query,
|
|
170545
|
-
memories: semanticCandidates,
|
|
170546
|
-
embeddingEnabled: args.embeddingEnabled,
|
|
170547
|
-
embedQuery: args.embedQuery,
|
|
170548
|
-
isEmbeddingRuntimeEnabled: args.isEmbeddingRuntimeEnabled
|
|
170549
|
-
});
|
|
170550
|
-
return mergeMemoryResults({
|
|
170551
|
-
memories,
|
|
170552
|
-
semanticScores,
|
|
170553
|
-
ftsScores,
|
|
170554
|
-
limit: args.limit
|
|
170555
|
-
});
|
|
170556
|
-
}
|
|
170557
|
-
function searchFacts(args) {
|
|
170558
|
-
return getSessionFacts(args.db, args.sessionId).map((fact) => ({
|
|
170559
|
-
fact,
|
|
170560
|
-
score: scoreTextMatch(fact.content, args.query, fact.category)
|
|
170561
|
-
})).filter((candidate) => candidate.score > 0).sort((left, right) => {
|
|
170562
|
-
if (right.score !== left.score) {
|
|
170563
|
-
return right.score - left.score;
|
|
170564
|
-
}
|
|
170565
|
-
return left.fact.id - right.fact.id;
|
|
170566
|
-
}).slice(0, args.limit).map(({ fact, score }) => ({
|
|
170567
|
-
source: "fact",
|
|
170568
|
-
content: previewText(fact.content),
|
|
170569
|
-
score,
|
|
170570
|
-
factId: fact.id,
|
|
170571
|
-
factCategory: fact.category
|
|
170572
|
-
}));
|
|
170573
|
-
}
|
|
170574
|
-
function searchMessages(args) {
|
|
170575
|
-
ensureMessagesIndexed(args.db, args.sessionId, args.readMessages);
|
|
170576
|
-
const sanitizedQuery = sanitizeFtsQuery(args.query.trim());
|
|
170577
|
-
if (sanitizedQuery.length === 0) {
|
|
170578
|
-
return [];
|
|
170579
|
-
}
|
|
170580
|
-
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
170581
|
-
const rows = getMessageSearchStatement(args.db).all(args.sessionId, sanitizedQuery, fetchLimit).map((row) => row);
|
|
170582
|
-
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
170583
|
-
return rows.map((row, rank) => {
|
|
170584
|
-
const messageOrdinal = getMessageOrdinal(row.messageOrdinal);
|
|
170585
|
-
if (messageOrdinal === null || typeof row.messageId !== "string" || typeof row.role !== "string" || typeof row.content !== "string") {
|
|
170586
|
-
return null;
|
|
170587
|
-
}
|
|
170588
|
-
if (cutoff !== null && messageOrdinal > cutoff) {
|
|
170589
|
-
return null;
|
|
170590
|
-
}
|
|
170591
|
-
return {
|
|
170592
|
-
source: "message",
|
|
170593
|
-
content: previewText(row.content),
|
|
170594
|
-
score: 1 / (rank + 1),
|
|
170595
|
-
messageOrdinal,
|
|
170596
|
-
messageId: row.messageId,
|
|
170597
|
-
role: row.role
|
|
170598
|
-
};
|
|
170599
|
-
}).filter((result) => result !== null).slice(0, args.limit);
|
|
170600
|
-
}
|
|
170601
|
-
function getSourceBoost(result) {
|
|
170602
|
-
switch (result.source) {
|
|
170603
|
-
case "memory":
|
|
170604
|
-
return MEMORY_SOURCE_BOOST;
|
|
170605
|
-
case "fact":
|
|
170606
|
-
return FACT_SOURCE_BOOST;
|
|
170607
|
-
case "message":
|
|
170608
|
-
return MESSAGE_SOURCE_BOOST;
|
|
170609
|
-
}
|
|
170610
|
-
}
|
|
170611
|
-
function compareUnifiedResults(left, right) {
|
|
170612
|
-
const leftEffective = left.score * getSourceBoost(left);
|
|
170613
|
-
const rightEffective = right.score * getSourceBoost(right);
|
|
170614
|
-
if (rightEffective !== leftEffective) {
|
|
170615
|
-
return rightEffective - leftEffective;
|
|
170616
|
-
}
|
|
170617
|
-
if (left.source === "memory" && right.source === "memory") {
|
|
170618
|
-
return left.memoryId - right.memoryId;
|
|
170619
|
-
}
|
|
170620
|
-
if (left.source === "fact" && right.source === "fact") {
|
|
170621
|
-
return left.factId - right.factId;
|
|
170622
|
-
}
|
|
170623
|
-
if (left.source === "message" && right.source === "message") {
|
|
170624
|
-
return left.messageOrdinal - right.messageOrdinal;
|
|
170625
|
-
}
|
|
170626
|
-
return 0;
|
|
170627
|
-
}
|
|
170628
|
-
async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
170629
|
-
const trimmedQuery = query.trim();
|
|
170630
|
-
if (trimmedQuery.length === 0) {
|
|
170631
|
-
return [];
|
|
170632
|
-
}
|
|
170633
|
-
const limit = normalizeLimit2(options.limit);
|
|
170634
|
-
const tierLimit = Math.max(limit * 3, DEFAULT_UNIFIED_SEARCH_LIMIT);
|
|
170635
|
-
const [memoryResults, factResults, messageResults] = await Promise.all([
|
|
170636
|
-
searchMemories({
|
|
170637
|
-
db,
|
|
170638
|
-
projectPath,
|
|
170639
|
-
query: trimmedQuery,
|
|
170640
|
-
limit: tierLimit,
|
|
170641
|
-
memoryEnabled: options.memoryEnabled ?? true,
|
|
170642
|
-
embeddingEnabled: options.embeddingEnabled ?? true,
|
|
170643
|
-
embedQuery: options.embedQuery ?? embedText,
|
|
170644
|
-
isEmbeddingRuntimeEnabled: options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled
|
|
170645
|
-
}),
|
|
170646
|
-
Promise.resolve(searchFacts({ db, sessionId, query: trimmedQuery, limit: tierLimit })),
|
|
170647
|
-
Promise.resolve(searchMessages({
|
|
170648
|
-
db,
|
|
170649
|
-
sessionId,
|
|
170650
|
-
query: trimmedQuery,
|
|
170651
|
-
limit: tierLimit,
|
|
170652
|
-
readMessages: options.readMessages ?? readRawSessionMessages,
|
|
170653
|
-
maxOrdinal: options.maxMessageOrdinal
|
|
170654
|
-
}))
|
|
170655
|
-
]);
|
|
170656
|
-
const results = [...memoryResults, ...factResults, ...messageResults].sort(compareUnifiedResults).slice(0, limit);
|
|
170657
|
-
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
170658
|
-
if (memoryIds.length > 0) {
|
|
170659
|
-
db.transaction(() => {
|
|
170660
|
-
for (const memoryId of memoryIds) {
|
|
170661
|
-
updateMemoryRetrievalCount(db, memoryId);
|
|
170662
|
-
}
|
|
170663
|
-
})();
|
|
170664
|
-
}
|
|
170665
|
-
return results;
|
|
170666
|
-
}
|
|
170667
|
-
|
|
170668
|
-
// src/tools/ctx-search/tools.ts
|
|
172169
|
+
init_inject_compartments();
|
|
172170
|
+
var VALID_SOURCES = new Set(["memory", "message", "git_commit"]);
|
|
170669
172171
|
function normalizeLimit3(limit) {
|
|
170670
172172
|
if (typeof limit !== "number" || !Number.isFinite(limit)) {
|
|
170671
172173
|
return DEFAULT_CTX_SEARCH_LIMIT;
|
|
170672
172174
|
}
|
|
170673
172175
|
return Math.max(1, Math.floor(limit));
|
|
170674
172176
|
}
|
|
172177
|
+
function normalizeSources(sources) {
|
|
172178
|
+
if (!sources || sources.length === 0)
|
|
172179
|
+
return;
|
|
172180
|
+
const result = [];
|
|
172181
|
+
const seen = new Set;
|
|
172182
|
+
for (const source of sources) {
|
|
172183
|
+
if (VALID_SOURCES.has(source)) {
|
|
172184
|
+
const typed = source;
|
|
172185
|
+
if (!seen.has(typed)) {
|
|
172186
|
+
seen.add(typed);
|
|
172187
|
+
result.push(typed);
|
|
172188
|
+
}
|
|
172189
|
+
}
|
|
172190
|
+
}
|
|
172191
|
+
return result.length > 0 ? result : undefined;
|
|
172192
|
+
}
|
|
172193
|
+
function formatAge2(committedAtMs) {
|
|
172194
|
+
const ageMs = Date.now() - committedAtMs;
|
|
172195
|
+
if (ageMs < 0)
|
|
172196
|
+
return "future";
|
|
172197
|
+
const days = Math.floor(ageMs / (24 * 60 * 60 * 1000));
|
|
172198
|
+
if (days <= 0)
|
|
172199
|
+
return "today";
|
|
172200
|
+
if (days === 1)
|
|
172201
|
+
return "1d ago";
|
|
172202
|
+
if (days < 30)
|
|
172203
|
+
return `${days}d ago`;
|
|
172204
|
+
const months = Math.floor(days / 30);
|
|
172205
|
+
if (months === 1)
|
|
172206
|
+
return "1mo ago";
|
|
172207
|
+
if (months < 12)
|
|
172208
|
+
return `${months}mo ago`;
|
|
172209
|
+
const years = Math.floor(days / 365);
|
|
172210
|
+
return years === 1 ? "1y ago" : `${years}y ago`;
|
|
172211
|
+
}
|
|
170675
172212
|
function formatResult(result, index) {
|
|
170676
172213
|
if (result.source === "memory") {
|
|
170677
172214
|
return [
|
|
@@ -170680,9 +172217,9 @@ function formatResult(result, index) {
|
|
|
170680
172217
|
].join(`
|
|
170681
172218
|
`);
|
|
170682
172219
|
}
|
|
170683
|
-
if (result.source === "
|
|
172220
|
+
if (result.source === "git_commit") {
|
|
170684
172221
|
return [
|
|
170685
|
-
`[${index}] [
|
|
172222
|
+
`[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge2(result.committedAtMs)} match=${result.matchType}`,
|
|
170686
172223
|
result.content
|
|
170687
172224
|
].join(`
|
|
170688
172225
|
`);
|
|
@@ -170698,7 +172235,7 @@ function formatResult(result, index) {
|
|
|
170698
172235
|
}
|
|
170699
172236
|
function formatSearchResults(query, results) {
|
|
170700
172237
|
if (results.length === 0) {
|
|
170701
|
-
return `No results found for "${query}" across memories,
|
|
172238
|
+
return `No results found for "${query}" across memories, git commits, or message history.`;
|
|
170702
172239
|
}
|
|
170703
172240
|
const body = results.map((result, index) => formatResult(result, index + 1)).join(`
|
|
170704
172241
|
|
|
@@ -170711,8 +172248,9 @@ function createCtxSearchTool(deps) {
|
|
|
170711
172248
|
return tool5({
|
|
170712
172249
|
description: CTX_SEARCH_DESCRIPTION,
|
|
170713
172250
|
args: {
|
|
170714
|
-
query: tool5.schema.string().describe("Search query
|
|
170715
|
-
limit: tool5.schema.number().optional().describe("Maximum results to return (default: 10)")
|
|
172251
|
+
query: tool5.schema.string().describe("Search query. Matches against memory content, git commit messages, and raw user/assistant message text."),
|
|
172252
|
+
limit: tool5.schema.number().optional().describe("Maximum results to return (default: 10)"),
|
|
172253
|
+
sources: tool5.schema.array(tool5.schema.enum(["memory", "message", "git_commit"])).optional().describe('Optional. Restrict to specific sources. Examples: ["git_commit"] for "when did we change X", ["memory"] for naming conventions, ["message"] for "did we discuss this earlier", ["git_commit","message"] for regression hunts. Omit for a broad search across all enabled sources.')
|
|
170716
172254
|
},
|
|
170717
172255
|
async execute(args, toolContext) {
|
|
170718
172256
|
const query = args.query?.trim();
|
|
@@ -170720,12 +172258,16 @@ function createCtxSearchTool(deps) {
|
|
|
170720
172258
|
return "Error: 'query' is required.";
|
|
170721
172259
|
}
|
|
170722
172260
|
const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, toolContext.sessionID);
|
|
172261
|
+
const visibleMemoryIds = getVisibleMemoryIds(deps.db, toolContext.sessionID);
|
|
170723
172262
|
const results = await unifiedSearch(deps.db, toolContext.sessionID, deps.projectPath, query, {
|
|
170724
172263
|
limit: normalizeLimit3(args.limit),
|
|
170725
172264
|
memoryEnabled: deps.memoryEnabled,
|
|
170726
172265
|
embeddingEnabled: deps.embeddingEnabled,
|
|
170727
172266
|
readMessages: deps.readMessages,
|
|
170728
|
-
maxMessageOrdinal: lastCompartmentEnd >= 0 ? lastCompartmentEnd : undefined
|
|
172267
|
+
maxMessageOrdinal: lastCompartmentEnd >= 0 ? lastCompartmentEnd : undefined,
|
|
172268
|
+
gitCommitsEnabled: deps.gitCommitsEnabled ?? false,
|
|
172269
|
+
sources: normalizeSources(args.sources),
|
|
172270
|
+
visibleMemoryIds
|
|
170729
172271
|
});
|
|
170730
172272
|
return formatSearchResults(query, results);
|
|
170731
172273
|
}
|
|
@@ -170807,7 +172349,8 @@ function createToolRegistry(args) {
|
|
|
170807
172349
|
db,
|
|
170808
172350
|
projectPath,
|
|
170809
172351
|
memoryEnabled,
|
|
170810
|
-
embeddingEnabled: embeddingConfig2.provider !== "off"
|
|
172352
|
+
embeddingEnabled: embeddingConfig2.provider !== "off",
|
|
172353
|
+
gitCommitsEnabled: pluginConfig.experimental?.git_commit_indexing?.enabled === true
|
|
170811
172354
|
}),
|
|
170812
172355
|
...memoryEnabled ? {
|
|
170813
172356
|
...createCtxMemoryTools({
|
|
@@ -170840,13 +172383,13 @@ import { dirname as dirname2 } from "path";
|
|
|
170840
172383
|
|
|
170841
172384
|
// src/shared/rpc-utils.ts
|
|
170842
172385
|
import { createHash as createHash2 } from "crypto";
|
|
170843
|
-
import { join as
|
|
172386
|
+
import { join as join16 } from "path";
|
|
170844
172387
|
function projectHash(directory) {
|
|
170845
172388
|
const normalized = directory.replace(/\/+$/, "");
|
|
170846
172389
|
return createHash2("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
170847
172390
|
}
|
|
170848
172391
|
function rpcPortFilePath(storageDir, directory) {
|
|
170849
|
-
return
|
|
172392
|
+
return join16(storageDir, "rpc", projectHash(directory), "port");
|
|
170850
172393
|
}
|
|
170851
172394
|
|
|
170852
172395
|
// src/shared/rpc-server.ts
|
|
@@ -170972,8 +172515,10 @@ var plugin = async (ctx) => {
|
|
|
170972
172515
|
setTimeout(async () => {
|
|
170973
172516
|
try {
|
|
170974
172517
|
const { sendIgnoredMessage: sendIgnoredMessage2 } = await Promise.resolve().then(() => (init_send_session_notification(), exports_send_session_notification));
|
|
170975
|
-
const
|
|
170976
|
-
const
|
|
172518
|
+
const clientWithSessions = ctx.client;
|
|
172519
|
+
const sessions = await Promise.resolve(clientWithSessions.session?.list?.()).catch(() => null);
|
|
172520
|
+
const sessionList = Array.isArray(sessions) ? sessions : sessions?.data;
|
|
172521
|
+
const sessionId = sessionList?.[0]?.id;
|
|
170977
172522
|
if (sessionId) {
|
|
170978
172523
|
await sendIgnoredMessage2(ctx.client, sessionId, warningText, {});
|
|
170979
172524
|
}
|
|
@@ -171007,14 +172552,19 @@ var plugin = async (ctx) => {
|
|
|
171007
172552
|
dreamerConfig: pluginConfig.dreamer,
|
|
171008
172553
|
embeddingConfig: pluginConfig.embedding,
|
|
171009
172554
|
memoryEnabled: pluginConfig.memory?.enabled === true,
|
|
171010
|
-
experimentalUserMemories: pluginConfig.
|
|
172555
|
+
experimentalUserMemories: pluginConfig.dreamer?.user_memories?.enabled ? {
|
|
172556
|
+
enabled: true,
|
|
172557
|
+
promotionThreshold: pluginConfig.dreamer.user_memories.promotion_threshold
|
|
172558
|
+
} : undefined,
|
|
172559
|
+
experimentalPinKeyFiles: pluginConfig.dreamer?.pin_key_files?.enabled ? {
|
|
171011
172560
|
enabled: true,
|
|
171012
|
-
|
|
172561
|
+
token_budget: pluginConfig.dreamer.pin_key_files.token_budget,
|
|
172562
|
+
min_reads: pluginConfig.dreamer.pin_key_files.min_reads
|
|
171013
172563
|
} : undefined,
|
|
171014
|
-
|
|
172564
|
+
gitCommitIndexing: pluginConfig.experimental?.git_commit_indexing?.enabled ? {
|
|
171015
172565
|
enabled: true,
|
|
171016
|
-
|
|
171017
|
-
|
|
172566
|
+
since_days: pluginConfig.experimental.git_commit_indexing.since_days,
|
|
172567
|
+
max_commits: pluginConfig.experimental.git_commit_indexing.max_commits
|
|
171018
172568
|
} : undefined
|
|
171019
172569
|
});
|
|
171020
172570
|
const storageDir = `${getOpenCodeStorageDir()}/plugin/magic-context`;
|
|
@@ -171114,7 +172664,7 @@ var plugin = async (ctx) => {
|
|
|
171114
172664
|
config2.agent = {
|
|
171115
172665
|
...config2.agent ?? {},
|
|
171116
172666
|
[DREAMER_AGENT]: buildHiddenAgentConfig(DREAMER_AGENT, DREAMER_SYSTEM_PROMPT, dreamerAgentOverrides),
|
|
171117
|
-
[HISTORIAN_AGENT]: buildHiddenAgentConfig(HISTORIAN_AGENT, pluginConfig.
|
|
172667
|
+
[HISTORIAN_AGENT]: buildHiddenAgentConfig(HISTORIAN_AGENT, pluginConfig.dreamer?.user_memories?.enabled ? COMPARTMENT_AGENT_SYSTEM_PROMPT + USER_OBSERVATIONS_APPENDIX : COMPARTMENT_AGENT_SYSTEM_PROMPT, historianAgentOverrides),
|
|
171118
172668
|
[HISTORIAN_EDITOR_AGENT]: buildHiddenAgentConfig(HISTORIAN_EDITOR_AGENT, HISTORIAN_EDITOR_SYSTEM_PROMPT, historianAgentOverrides),
|
|
171119
172669
|
[SIDEKICK_AGENT]: buildHiddenAgentConfig(SIDEKICK_AGENT, SIDEKICK_SYSTEM_PROMPT, sidekickAgentOverrides)
|
|
171120
172670
|
};
|