@cortexkit/opencode-magic-context 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -6
- package/dist/cli/config-paths.d.ts +9 -0
- package/dist/cli/config-paths.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/opencode-helpers.d.ts +19 -0
- package/dist/cli/opencode-helpers.d.ts.map +1 -0
- package/dist/cli/prompts.d.ts +12 -0
- package/dist/cli/prompts.d.ts.map +1 -0
- package/dist/cli/setup.d.ts +2 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli.js +442 -0
- package/dist/config/schema/magic-context.d.ts +0 -14
- 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/dreamer/queue.d.ts +0 -2
- package/dist/features/magic-context/dreamer/queue.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-cache.d.ts +8 -0
- package/dist/features/magic-context/memory/embedding-cache.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/index.d.ts +1 -0
- package/dist/features/magic-context/memory/index.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-fts.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
- package/dist/features/magic-context/message-index.d.ts +1 -0
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/scheduler.d.ts +1 -1
- package/dist/features/magic-context/scheduler.d.ts.map +1 -1
- 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-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-ops.d.ts +0 -1
- package/dist/features/magic-context/storage-ops.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.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/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-trigger.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-chunk.d.ts +1 -0
- package/dist/hooks/magic-context/read-session-chunk.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-id-fallback.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-context-state.d.ts +1 -1
- package/dist/hooks/magic-context/transform-context-state.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +1 -0
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.js +1206 -1052
- package/dist/plugin/dream-timer.d.ts +1 -1
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/shared/jsonc-parser.d.ts +0 -9
- package/dist/shared/jsonc-parser.d.ts.map +1 -1
- package/package.json +6 -2
- package/scripts/install.sh +35 -0
- package/dist/plugin/hooks/create-tag-content-resolver.d.ts +0 -7
- package/dist/plugin/hooks/create-tag-content-resolver.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -31,13 +31,6 @@ import { join } from "path";
|
|
|
31
31
|
|
|
32
32
|
// src/shared/jsonc-parser.ts
|
|
33
33
|
import { existsSync, readFileSync } from "fs";
|
|
34
|
-
|
|
35
|
-
// src/shared/error-message.ts
|
|
36
|
-
function getErrorMessage(error) {
|
|
37
|
-
return error instanceof Error ? error.message : String(error);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// src/shared/jsonc-parser.ts
|
|
41
34
|
function stripJsonComments(content) {
|
|
42
35
|
let result = "";
|
|
43
36
|
let inString = false;
|
|
@@ -13733,19 +13726,6 @@ var DEFAULT_DREAMER_TASKS = [
|
|
|
13733
13726
|
"archive-stale",
|
|
13734
13727
|
"improve"
|
|
13735
13728
|
];
|
|
13736
|
-
var DreamingConfigSchema = exports_external.object({
|
|
13737
|
-
enabled: exports_external.boolean().default(false),
|
|
13738
|
-
schedule: exports_external.string().default("02:00-06:00"),
|
|
13739
|
-
max_runtime_minutes: exports_external.number().min(10).default(120),
|
|
13740
|
-
tasks: exports_external.array(DreamingTaskSchema).default(DEFAULT_DREAMER_TASKS),
|
|
13741
|
-
task_timeout_minutes: exports_external.number().min(5).default(20)
|
|
13742
|
-
}).default({
|
|
13743
|
-
enabled: false,
|
|
13744
|
-
schedule: "02:00-06:00",
|
|
13745
|
-
max_runtime_minutes: 120,
|
|
13746
|
-
tasks: DEFAULT_DREAMER_TASKS,
|
|
13747
|
-
task_timeout_minutes: 20
|
|
13748
|
-
});
|
|
13749
13729
|
var DreamerConfigSchema = AgentOverrideConfigSchema.merge(exports_external.object({
|
|
13750
13730
|
enabled: exports_external.boolean().default(false),
|
|
13751
13731
|
schedule: exports_external.string().default("02:00-06:00"),
|
|
@@ -14618,6 +14598,24 @@ async function runSidekick(deps) {
|
|
|
14618
14598
|
}
|
|
14619
14599
|
|
|
14620
14600
|
// src/features/magic-context/compartment-storage.ts
|
|
14601
|
+
var insertCompartmentStatements = new WeakMap;
|
|
14602
|
+
var insertFactStatements = new WeakMap;
|
|
14603
|
+
function getInsertCompartmentStatement(db) {
|
|
14604
|
+
let stmt = insertCompartmentStatements.get(db);
|
|
14605
|
+
if (!stmt) {
|
|
14606
|
+
stmt = db.prepare("INSERT INTO compartments (session_id, sequence, start_message, end_message, start_message_id, end_message_id, title, content, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
|
|
14607
|
+
insertCompartmentStatements.set(db, stmt);
|
|
14608
|
+
}
|
|
14609
|
+
return stmt;
|
|
14610
|
+
}
|
|
14611
|
+
function getInsertFactStatement(db) {
|
|
14612
|
+
let stmt = insertFactStatements.get(db);
|
|
14613
|
+
if (!stmt) {
|
|
14614
|
+
stmt = db.prepare("INSERT INTO session_facts (session_id, category, content, created_at, updated_at) VALUES (?, ?, ?, ?, ?)");
|
|
14615
|
+
insertFactStatements.set(db, stmt);
|
|
14616
|
+
}
|
|
14617
|
+
return stmt;
|
|
14618
|
+
}
|
|
14621
14619
|
function isCompartmentRow(row) {
|
|
14622
14620
|
if (row === null || typeof row !== "object")
|
|
14623
14621
|
return false;
|
|
@@ -14630,6 +14628,18 @@ function isSessionFactRow(row) {
|
|
|
14630
14628
|
const candidate = row;
|
|
14631
14629
|
return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.category === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number" && typeof candidate.updated_at === "number";
|
|
14632
14630
|
}
|
|
14631
|
+
function insertCompartmentRows(db, sessionId, compartments, now) {
|
|
14632
|
+
const stmt = getInsertCompartmentStatement(db);
|
|
14633
|
+
for (const compartment of compartments) {
|
|
14634
|
+
stmt.run(sessionId, compartment.sequence, compartment.startMessage, compartment.endMessage, compartment.startMessageId, compartment.endMessageId, compartment.title, compartment.content, now);
|
|
14635
|
+
}
|
|
14636
|
+
}
|
|
14637
|
+
function insertFactRows(db, sessionId, facts, now) {
|
|
14638
|
+
const stmt = getInsertFactStatement(db);
|
|
14639
|
+
for (const fact of facts) {
|
|
14640
|
+
stmt.run(sessionId, fact.category, fact.content, now, now);
|
|
14641
|
+
}
|
|
14642
|
+
}
|
|
14633
14643
|
function toCompartment(row) {
|
|
14634
14644
|
return {
|
|
14635
14645
|
id: row.id,
|
|
@@ -14667,20 +14677,14 @@ function appendCompartments(db, sessionId, compartments) {
|
|
|
14667
14677
|
return;
|
|
14668
14678
|
const now = Date.now();
|
|
14669
14679
|
db.transaction(() => {
|
|
14670
|
-
|
|
14671
|
-
for (const c of compartments) {
|
|
14672
|
-
stmt.run(sessionId, c.sequence, c.startMessage, c.endMessage, c.startMessageId, c.endMessageId, c.title, c.content, now);
|
|
14673
|
-
}
|
|
14680
|
+
insertCompartmentRows(db, sessionId, compartments, now);
|
|
14674
14681
|
})();
|
|
14675
14682
|
}
|
|
14676
14683
|
function replaceSessionFacts(db, sessionId, facts) {
|
|
14677
14684
|
const now = Date.now();
|
|
14678
14685
|
db.transaction(() => {
|
|
14679
14686
|
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
14680
|
-
|
|
14681
|
-
for (const f of facts) {
|
|
14682
|
-
stmt.run(sessionId, f.category, f.content, now, now);
|
|
14683
|
-
}
|
|
14687
|
+
insertFactRows(db, sessionId, facts, now);
|
|
14684
14688
|
db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_count = 0 WHERE session_id = ?").run(sessionId);
|
|
14685
14689
|
})();
|
|
14686
14690
|
}
|
|
@@ -14693,14 +14697,8 @@ function replaceAllCompartmentState(db, sessionId, compartments, facts) {
|
|
|
14693
14697
|
db.transaction(() => {
|
|
14694
14698
|
db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
|
|
14695
14699
|
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
compartmentStmt.run(sessionId, c.sequence, c.startMessage, c.endMessage, c.startMessageId, c.endMessageId, c.title, c.content, now);
|
|
14699
|
-
}
|
|
14700
|
-
const factStmt = db.prepare("INSERT INTO session_facts (session_id, category, content, created_at, updated_at) VALUES (?, ?, ?, ?, ?)");
|
|
14701
|
-
for (const f of facts) {
|
|
14702
|
-
factStmt.run(sessionId, f.category, f.content, now, now);
|
|
14703
|
-
}
|
|
14700
|
+
insertCompartmentRows(db, sessionId, compartments, now);
|
|
14701
|
+
insertFactRows(db, sessionId, facts, now);
|
|
14704
14702
|
db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_count = 0 WHERE session_id = ?").run(sessionId);
|
|
14705
14703
|
})();
|
|
14706
14704
|
}
|
|
@@ -14777,14 +14775,8 @@ function promoteRecompStaging(db, sessionId) {
|
|
|
14777
14775
|
return null;
|
|
14778
14776
|
db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
|
|
14779
14777
|
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
compartmentStmt.run(sessionId, c.sequence, c.startMessage, c.endMessage, c.startMessageId, c.endMessageId, c.title, c.content, now);
|
|
14783
|
-
}
|
|
14784
|
-
const factStmt = db.prepare("INSERT INTO session_facts (session_id, category, content, created_at, updated_at) VALUES (?, ?, ?, ?, ?)");
|
|
14785
|
-
for (const f of staging.facts) {
|
|
14786
|
-
factStmt.run(sessionId, f.category, f.content, now, now);
|
|
14787
|
-
}
|
|
14778
|
+
insertCompartmentRows(db, sessionId, staging.compartments, now);
|
|
14779
|
+
insertFactRows(db, sessionId, staging.facts, now);
|
|
14788
14780
|
db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
|
|
14789
14781
|
db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
|
|
14790
14782
|
db.prepare("UPDATE session_meta SET memory_block_cache = '', memory_block_count = 0 WHERE session_id = ?").run(sessionId);
|
|
@@ -15100,6 +15092,13 @@ function clearStaleEntries(db, maxAgeMs) {
|
|
|
15100
15092
|
// src/features/magic-context/dreamer/runner.ts
|
|
15101
15093
|
import { existsSync as existsSync3 } from "fs";
|
|
15102
15094
|
import { join as join3 } from "path";
|
|
15095
|
+
|
|
15096
|
+
// src/shared/error-message.ts
|
|
15097
|
+
function getErrorMessage(error48) {
|
|
15098
|
+
return error48 instanceof Error ? error48.message : String(error48);
|
|
15099
|
+
}
|
|
15100
|
+
|
|
15101
|
+
// src/features/magic-context/dreamer/runner.ts
|
|
15103
15102
|
var dreamProjectDirectories = new Map;
|
|
15104
15103
|
function registerDreamProjectDirectory(projectIdentity, directory) {
|
|
15105
15104
|
dreamProjectDirectories.set(projectIdentity, directory);
|
|
@@ -15494,6 +15493,7 @@ function initializeDatabase(db) {
|
|
|
15494
15493
|
retry_count INTEGER DEFAULT 0
|
|
15495
15494
|
);
|
|
15496
15495
|
CREATE INDEX IF NOT EXISTS idx_dream_queue_project ON dream_queue(project_path);
|
|
15496
|
+
CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, enqueued_at);
|
|
15497
15497
|
|
|
15498
15498
|
CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts USING fts5(
|
|
15499
15499
|
content,
|
|
@@ -15805,892 +15805,1061 @@ function setPersistedStickyTurnReminder(db, sessionId, text, messageId = "") {
|
|
|
15805
15805
|
function clearPersistedStickyTurnReminder(db, sessionId) {
|
|
15806
15806
|
db.prepare("UPDATE session_meta SET sticky_turn_reminder_text = '', sticky_turn_reminder_message_id = '' WHERE session_id = ?").run(sessionId);
|
|
15807
15807
|
}
|
|
15808
|
-
// src/
|
|
15809
|
-
|
|
15810
|
-
|
|
15811
|
-
|
|
15812
|
-
|
|
15813
|
-
|
|
15814
|
-
|
|
15815
|
-
ensureSessionMetaRow(db, sessionId);
|
|
15816
|
-
return defaults;
|
|
15808
|
+
// src/shared/internal-initiator-marker.ts
|
|
15809
|
+
var OMO_INTERNAL_INITIATOR_MARKER = "<!-- OMO_INTERNAL_INITIATOR -->";
|
|
15810
|
+
|
|
15811
|
+
// src/shared/system-directive.ts
|
|
15812
|
+
var SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: MAGIC-CONTEXT";
|
|
15813
|
+
function isSystemDirective(text) {
|
|
15814
|
+
return text.trimStart().startsWith(SYSTEM_DIRECTIVE_PREFIX);
|
|
15817
15815
|
}
|
|
15818
|
-
function
|
|
15819
|
-
|
|
15820
|
-
|
|
15821
|
-
|
|
15822
|
-
|
|
15823
|
-
|
|
15824
|
-
|
|
15825
|
-
|
|
15826
|
-
|
|
15827
|
-
|
|
15828
|
-
|
|
15829
|
-
|
|
15830
|
-
|
|
15831
|
-
} else if (typeof value === "string" || typeof value === "number") {
|
|
15832
|
-
setClauses.push(`${column} = ?`);
|
|
15833
|
-
values.push(value);
|
|
15834
|
-
}
|
|
15835
|
-
}
|
|
15836
|
-
if (setClauses.length === 0) {
|
|
15816
|
+
function removeSystemReminders(text) {
|
|
15817
|
+
return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, "").trim();
|
|
15818
|
+
}
|
|
15819
|
+
|
|
15820
|
+
// src/hooks/magic-context/read-session-db.ts
|
|
15821
|
+
import { Database as Database2 } from "bun:sqlite";
|
|
15822
|
+
import { join as join6 } from "path";
|
|
15823
|
+
function getOpenCodeDbPath() {
|
|
15824
|
+
return join6(getDataDir(), "opencode", "opencode.db");
|
|
15825
|
+
}
|
|
15826
|
+
var cachedReadOnlyDb = null;
|
|
15827
|
+
function closeCachedReadOnlyDb() {
|
|
15828
|
+
if (!cachedReadOnlyDb) {
|
|
15837
15829
|
return;
|
|
15838
15830
|
}
|
|
15839
|
-
|
|
15840
|
-
|
|
15841
|
-
|
|
15842
|
-
|
|
15831
|
+
try {
|
|
15832
|
+
cachedReadOnlyDb.db.close(false);
|
|
15833
|
+
} catch (error48) {
|
|
15834
|
+
log("[magic-context] failed to close cached OpenCode read-only DB:", error48);
|
|
15835
|
+
} finally {
|
|
15836
|
+
cachedReadOnlyDb = null;
|
|
15837
|
+
}
|
|
15843
15838
|
}
|
|
15844
|
-
function
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
|
|
15849
|
-
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
|
|
15853
|
-
db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
|
|
15854
|
-
db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
|
|
15855
|
-
})();
|
|
15839
|
+
function getReadOnlySessionDb() {
|
|
15840
|
+
const dbPath = getOpenCodeDbPath();
|
|
15841
|
+
if (cachedReadOnlyDb?.path === dbPath) {
|
|
15842
|
+
return cachedReadOnlyDb.db;
|
|
15843
|
+
}
|
|
15844
|
+
closeCachedReadOnlyDb();
|
|
15845
|
+
const db = new Database2(dbPath, { readonly: true });
|
|
15846
|
+
cachedReadOnlyDb = { path: dbPath, db };
|
|
15847
|
+
return db;
|
|
15856
15848
|
}
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
if (row === null || typeof row !== "object")
|
|
15860
|
-
return false;
|
|
15861
|
-
const candidate = row;
|
|
15862
|
-
return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number";
|
|
15849
|
+
function withReadOnlySessionDb(fn) {
|
|
15850
|
+
return fn(getReadOnlySessionDb());
|
|
15863
15851
|
}
|
|
15864
|
-
function
|
|
15865
|
-
|
|
15866
|
-
|
|
15867
|
-
sessionId: row.session_id,
|
|
15868
|
-
content: row.content,
|
|
15869
|
-
createdAt: row.created_at
|
|
15870
|
-
};
|
|
15852
|
+
function getRawSessionMessageCountFromDb(db, sessionId) {
|
|
15853
|
+
const row = db.prepare("SELECT COUNT(*) as count FROM message WHERE session_id = ?").get(sessionId);
|
|
15854
|
+
return typeof row?.count === "number" ? row.count : 0;
|
|
15871
15855
|
}
|
|
15872
|
-
|
|
15873
|
-
|
|
15874
|
-
|
|
15856
|
+
|
|
15857
|
+
// src/hooks/magic-context/read-session-formatting.ts
|
|
15858
|
+
var COMMIT_HASH_PATTERN = /`?\b([0-9a-f]{6,12})\b`?/gi;
|
|
15859
|
+
var COMMIT_HINT_PATTERN = /\b(commit(?:ted)?|cherry-?pick(?:ed)?|hash(?:es)?|sha)\b/i;
|
|
15860
|
+
var MAX_COMMITS_PER_BLOCK = 5;
|
|
15861
|
+
function hasMeaningfulUserText(parts) {
|
|
15862
|
+
for (const part of parts) {
|
|
15863
|
+
if (part === null || typeof part !== "object")
|
|
15864
|
+
continue;
|
|
15865
|
+
const candidate = part;
|
|
15866
|
+
if (candidate.type !== "text" || typeof candidate.text !== "string")
|
|
15867
|
+
continue;
|
|
15868
|
+
if (candidate.ignored === true)
|
|
15869
|
+
continue;
|
|
15870
|
+
const cleaned = removeSystemReminders(candidate.text).replace(OMO_INTERNAL_INITIATOR_MARKER, "").trim();
|
|
15871
|
+
if (!cleaned)
|
|
15872
|
+
continue;
|
|
15873
|
+
if (isSystemDirective(cleaned))
|
|
15874
|
+
continue;
|
|
15875
|
+
return true;
|
|
15876
|
+
}
|
|
15877
|
+
return false;
|
|
15875
15878
|
}
|
|
15876
|
-
function
|
|
15877
|
-
|
|
15879
|
+
function extractTexts(parts) {
|
|
15880
|
+
const texts = [];
|
|
15881
|
+
for (const part of parts) {
|
|
15882
|
+
if (part === null || typeof part !== "object")
|
|
15883
|
+
continue;
|
|
15884
|
+
const p = part;
|
|
15885
|
+
if (p.type === "text" && typeof p.text === "string" && p.text.trim().length > 0) {
|
|
15886
|
+
texts.push(p.text.trim());
|
|
15887
|
+
}
|
|
15888
|
+
}
|
|
15889
|
+
return texts;
|
|
15878
15890
|
}
|
|
15879
|
-
function
|
|
15880
|
-
|
|
15891
|
+
function estimateTokens(text) {
|
|
15892
|
+
return Math.ceil(text.length / 3.5);
|
|
15881
15893
|
}
|
|
15882
|
-
|
|
15883
|
-
|
|
15884
|
-
if (row === null || typeof row !== "object")
|
|
15885
|
-
return false;
|
|
15886
|
-
const r = row;
|
|
15887
|
-
return typeof r.id === "number" && typeof r.session_id === "string" && typeof r.tag_id === "number" && typeof r.operation === "string" && typeof r.queued_at === "number";
|
|
15894
|
+
function normalizeText(text) {
|
|
15895
|
+
return text.replace(/\s+/g, " ").trim();
|
|
15888
15896
|
}
|
|
15889
|
-
function
|
|
15890
|
-
if (
|
|
15891
|
-
|
|
15892
|
-
|
|
15897
|
+
function compactRole(role) {
|
|
15898
|
+
if (role === "assistant")
|
|
15899
|
+
return "A";
|
|
15900
|
+
if (role === "user")
|
|
15901
|
+
return "U";
|
|
15902
|
+
return role.slice(0, 1).toUpperCase() || "M";
|
|
15903
|
+
}
|
|
15904
|
+
function formatBlock(block) {
|
|
15905
|
+
const range = block.startOrdinal === block.endOrdinal ? `[${block.startOrdinal}]` : `[${block.startOrdinal}-${block.endOrdinal}]`;
|
|
15906
|
+
const commitSuffix = block.commitHashes.length > 0 ? ` commits: ${block.commitHashes.join(", ")}` : "";
|
|
15907
|
+
return `${range} ${block.role}:${commitSuffix} ${block.parts.join(" / ")}`;
|
|
15908
|
+
}
|
|
15909
|
+
function extractCommitHashes(text) {
|
|
15910
|
+
const hashes = [];
|
|
15911
|
+
const seen = new Set;
|
|
15912
|
+
for (const match of text.matchAll(COMMIT_HASH_PATTERN)) {
|
|
15913
|
+
const hash2 = match[1]?.toLowerCase();
|
|
15914
|
+
if (!hash2 || seen.has(hash2))
|
|
15915
|
+
continue;
|
|
15916
|
+
seen.add(hash2);
|
|
15917
|
+
hashes.push(hash2);
|
|
15918
|
+
if (hashes.length >= MAX_COMMITS_PER_BLOCK)
|
|
15919
|
+
break;
|
|
15920
|
+
}
|
|
15921
|
+
return hashes;
|
|
15922
|
+
}
|
|
15923
|
+
function compactTextForSummary(text, role) {
|
|
15924
|
+
const commitHashes = role === "assistant" ? extractCommitHashes(text) : [];
|
|
15925
|
+
if (commitHashes.length === 0 || !COMMIT_HINT_PATTERN.test(text)) {
|
|
15926
|
+
return { text, commitHashes };
|
|
15893
15927
|
}
|
|
15928
|
+
const withoutHashes = text.replace(COMMIT_HASH_PATTERN, "").replace(/\(\s*\)/g, "").replace(/\s+,/g, ",").replace(/,\s*,+/g, ", ").replace(/\s{2,}/g, " ").replace(/\s+([,.;:])/g, "$1").trim();
|
|
15894
15929
|
return {
|
|
15895
|
-
|
|
15896
|
-
|
|
15897
|
-
tagId: row.tag_id,
|
|
15898
|
-
operation: row.operation,
|
|
15899
|
-
queuedAt: row.queued_at
|
|
15930
|
+
text: withoutHashes.length > 0 ? withoutHashes : text,
|
|
15931
|
+
commitHashes
|
|
15900
15932
|
};
|
|
15901
15933
|
}
|
|
15902
|
-
function
|
|
15903
|
-
|
|
15904
|
-
|
|
15905
|
-
|
|
15906
|
-
|
|
15907
|
-
|
|
15908
|
-
|
|
15909
|
-
|
|
15910
|
-
|
|
15934
|
+
function mergeCommitHashes(existing, next) {
|
|
15935
|
+
if (next.length === 0)
|
|
15936
|
+
return existing;
|
|
15937
|
+
const merged = [...existing];
|
|
15938
|
+
for (const hash2 of next) {
|
|
15939
|
+
if (merged.includes(hash2))
|
|
15940
|
+
continue;
|
|
15941
|
+
merged.push(hash2);
|
|
15942
|
+
if (merged.length >= MAX_COMMITS_PER_BLOCK)
|
|
15943
|
+
break;
|
|
15944
|
+
}
|
|
15945
|
+
return merged;
|
|
15911
15946
|
}
|
|
15912
|
-
|
|
15913
|
-
|
|
15947
|
+
|
|
15948
|
+
// src/hooks/magic-context/read-session-raw.ts
|
|
15949
|
+
function isRawMessageRow(row) {
|
|
15914
15950
|
if (row === null || typeof row !== "object")
|
|
15915
15951
|
return false;
|
|
15916
|
-
const
|
|
15917
|
-
return typeof
|
|
15952
|
+
const candidate = row;
|
|
15953
|
+
return typeof candidate.id === "string" && typeof candidate.data === "string";
|
|
15918
15954
|
}
|
|
15919
|
-
function
|
|
15920
|
-
db.prepare("INSERT OR IGNORE INTO source_contents (tag_id, session_id, content, created_at) VALUES (?, ?, ?, ?)").run(tagId, sessionId, content, Date.now());
|
|
15921
|
-
}
|
|
15922
|
-
function replaceSourceContent(db, sessionId, tagId, content) {
|
|
15923
|
-
db.prepare(`INSERT INTO source_contents (tag_id, session_id, content, created_at)
|
|
15924
|
-
VALUES (?, ?, ?, ?)
|
|
15925
|
-
ON CONFLICT(session_id, tag_id)
|
|
15926
|
-
DO UPDATE SET content = excluded.content, created_at = excluded.created_at`).run(tagId, sessionId, content, Date.now());
|
|
15927
|
-
}
|
|
15928
|
-
function getSourceContents(db, sessionId, tagIds) {
|
|
15929
|
-
if (tagIds.length === 0) {
|
|
15930
|
-
return new Map;
|
|
15931
|
-
}
|
|
15932
|
-
const placeholders = tagIds.map(() => "?").join(", ");
|
|
15933
|
-
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${placeholders})`).all(sessionId, ...tagIds).filter(isSourceContentRow);
|
|
15934
|
-
const sources = new Map;
|
|
15935
|
-
for (const row of rows) {
|
|
15936
|
-
sources.set(row.tag_id, row.content);
|
|
15937
|
-
}
|
|
15938
|
-
return sources;
|
|
15939
|
-
}
|
|
15940
|
-
// src/features/magic-context/storage-tags.ts
|
|
15941
|
-
var insertTagStatements = new WeakMap;
|
|
15942
|
-
function getInsertTagStatement(db) {
|
|
15943
|
-
let stmt = insertTagStatements.get(db);
|
|
15944
|
-
if (!stmt) {
|
|
15945
|
-
stmt = db.prepare("INSERT INTO tags (session_id, message_id, type, byte_size, tag_number) VALUES (?, ?, ?, ?, ?)");
|
|
15946
|
-
insertTagStatements.set(db, stmt);
|
|
15947
|
-
}
|
|
15948
|
-
return stmt;
|
|
15949
|
-
}
|
|
15950
|
-
function isTagRow(row) {
|
|
15955
|
+
function isRawPartRow(row) {
|
|
15951
15956
|
if (row === null || typeof row !== "object")
|
|
15952
15957
|
return false;
|
|
15953
|
-
const
|
|
15954
|
-
return typeof
|
|
15958
|
+
const candidate = row;
|
|
15959
|
+
return typeof candidate.message_id === "string" && typeof candidate.data === "string";
|
|
15955
15960
|
}
|
|
15956
|
-
function
|
|
15957
|
-
const
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
type,
|
|
15963
|
-
status,
|
|
15964
|
-
byteSize: row.byte_size,
|
|
15965
|
-
sessionId: row.session_id
|
|
15966
|
-
};
|
|
15961
|
+
function parseJsonRecord(value) {
|
|
15962
|
+
const parsed = JSON.parse(value);
|
|
15963
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
15964
|
+
throw new Error("Expected JSON object");
|
|
15965
|
+
}
|
|
15966
|
+
return parsed;
|
|
15967
15967
|
}
|
|
15968
|
-
function
|
|
15969
|
-
|
|
15970
|
-
return tagNumber;
|
|
15968
|
+
function parseJsonUnknown(value) {
|
|
15969
|
+
return JSON.parse(value);
|
|
15971
15970
|
}
|
|
15972
|
-
function
|
|
15973
|
-
db.prepare("
|
|
15971
|
+
function readRawSessionMessagesFromDb(db, sessionId) {
|
|
15972
|
+
const messageRows = db.prepare("SELECT id, data FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawMessageRow);
|
|
15973
|
+
const partRows = db.prepare("SELECT message_id, data FROM part WHERE session_id = ? ORDER BY time_created ASC, id ASC").all(sessionId).filter(isRawPartRow);
|
|
15974
|
+
const partsByMessageId = new Map;
|
|
15975
|
+
for (const part of partRows) {
|
|
15976
|
+
const list = partsByMessageId.get(part.message_id) ?? [];
|
|
15977
|
+
list.push(parseJsonUnknown(part.data));
|
|
15978
|
+
partsByMessageId.set(part.message_id, list);
|
|
15979
|
+
}
|
|
15980
|
+
return messageRows.map((row, index) => {
|
|
15981
|
+
const info = parseJsonRecord(row.data);
|
|
15982
|
+
const role = typeof info.role === "string" ? info.role : "unknown";
|
|
15983
|
+
return {
|
|
15984
|
+
ordinal: index + 1,
|
|
15985
|
+
id: row.id,
|
|
15986
|
+
role,
|
|
15987
|
+
parts: partsByMessageId.get(row.id) ?? []
|
|
15988
|
+
};
|
|
15989
|
+
});
|
|
15974
15990
|
}
|
|
15975
|
-
|
|
15976
|
-
|
|
15991
|
+
|
|
15992
|
+
// src/hooks/magic-context/tag-content-primitives.ts
|
|
15993
|
+
var encoder = new TextEncoder;
|
|
15994
|
+
var TAG_PREFIX_REGEX = /^\u00A7\d+\u00A7\s*/;
|
|
15995
|
+
function byteSize(value) {
|
|
15996
|
+
return encoder.encode(value).length;
|
|
15977
15997
|
}
|
|
15978
|
-
function
|
|
15979
|
-
|
|
15980
|
-
return rows.map(toTagEntry);
|
|
15998
|
+
function stripTagPrefix(value) {
|
|
15999
|
+
return value.replace(TAG_PREFIX_REGEX, "");
|
|
15981
16000
|
}
|
|
15982
|
-
function
|
|
15983
|
-
|
|
15984
|
-
|
|
15985
|
-
}
|
|
15986
|
-
const rows = db.prepare("SELECT id, message_id, type, status, byte_size, session_id, tag_number FROM tags WHERE session_id = ? AND status = 'active' ORDER BY byte_size DESC, tag_number ASC LIMIT ?").all(sessionId, n).filter(isTagRow);
|
|
15987
|
-
return rows.map(toTagEntry);
|
|
16001
|
+
function prependTag(tagId, value) {
|
|
16002
|
+
const stripped = stripTagPrefix(value);
|
|
16003
|
+
return `\xA7${tagId}\xA7 ${stripped}`;
|
|
15988
16004
|
}
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
const
|
|
15993
|
-
|
|
15994
|
-
return;
|
|
15995
|
-
}
|
|
15996
|
-
const timer = setInterval(() => {
|
|
15997
|
-
try {
|
|
15998
|
-
const db = openDatabase();
|
|
15999
|
-
checkScheduleAndEnqueue(db, dreamerConfig.schedule);
|
|
16000
|
-
processDreamQueue({
|
|
16001
|
-
db,
|
|
16002
|
-
client,
|
|
16003
|
-
tasks: dreamerConfig.tasks,
|
|
16004
|
-
taskTimeoutMinutes: dreamerConfig.task_timeout_minutes,
|
|
16005
|
-
maxRuntimeMinutes: dreamerConfig.max_runtime_minutes
|
|
16006
|
-
}).catch((error48) => {
|
|
16007
|
-
log("[dreamer] timer-triggered queue processing failed:", error48);
|
|
16008
|
-
});
|
|
16009
|
-
} catch (error48) {
|
|
16010
|
-
log("[dreamer] timer-triggered schedule check failed:", error48);
|
|
16011
|
-
}
|
|
16012
|
-
}, DREAM_TIMER_INTERVAL_MS);
|
|
16013
|
-
if (typeof timer === "object" && "unref" in timer) {
|
|
16014
|
-
timer.unref();
|
|
16015
|
-
}
|
|
16016
|
-
log(`[dreamer] started independent schedule timer (every ${DREAM_TIMER_INTERVAL_MS / 60000}m)`);
|
|
16005
|
+
function isThinkingPart(part) {
|
|
16006
|
+
if (part === null || typeof part !== "object")
|
|
16007
|
+
return false;
|
|
16008
|
+
const candidate = part;
|
|
16009
|
+
return candidate.type === "thinking" || candidate.type === "reasoning";
|
|
16017
16010
|
}
|
|
16018
16011
|
|
|
16019
|
-
// src/
|
|
16020
|
-
function
|
|
16021
|
-
|
|
16022
|
-
|
|
16023
|
-
|
|
16012
|
+
// src/hooks/magic-context/tag-part-guards.ts
|
|
16013
|
+
function isTextPart(part) {
|
|
16014
|
+
if (part === null || typeof part !== "object")
|
|
16015
|
+
return false;
|
|
16016
|
+
const p = part;
|
|
16017
|
+
return p.type === "text" && typeof p.text === "string";
|
|
16024
16018
|
}
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16029
|
-
|
|
16030
|
-
|
|
16031
|
-
|
|
16032
|
-
|
|
16033
|
-
|
|
16034
|
-
updateSessionMeta(db, sessionId, { lastNudgeBand: null });
|
|
16035
|
-
}
|
|
16036
|
-
};
|
|
16019
|
+
function isToolPartWithOutput(part) {
|
|
16020
|
+
if (part === null || typeof part !== "object")
|
|
16021
|
+
return false;
|
|
16022
|
+
const p = part;
|
|
16023
|
+
if (p.type !== "tool" || typeof p.callID !== "string")
|
|
16024
|
+
return false;
|
|
16025
|
+
if (p.state === null || typeof p.state !== "object")
|
|
16026
|
+
return false;
|
|
16027
|
+
return typeof p.state.output === "string";
|
|
16037
16028
|
}
|
|
16038
|
-
|
|
16039
|
-
|
|
16040
|
-
|
|
16041
|
-
|
|
16029
|
+
function isFilePart(part) {
|
|
16030
|
+
if (part === null || typeof part !== "object")
|
|
16031
|
+
return false;
|
|
16032
|
+
const p = part;
|
|
16033
|
+
return p.type === "file" && typeof p.url === "string";
|
|
16034
|
+
}
|
|
16035
|
+
function buildFileSourceContent(parts) {
|
|
16036
|
+
const content = parts.filter(isTextPart).map((part) => stripTagPrefix(part.text)).join(`
|
|
16037
|
+
`).trim();
|
|
16038
|
+
return content.length > 0 ? content : null;
|
|
16042
16039
|
}
|
|
16043
16040
|
|
|
16044
|
-
// src/hooks/magic-context/
|
|
16045
|
-
var
|
|
16046
|
-
function
|
|
16047
|
-
|
|
16048
|
-
return DEFAULT_CONTEXT_LIMIT;
|
|
16049
|
-
}
|
|
16050
|
-
if (modelID) {
|
|
16051
|
-
const modelSpecific = config2.modelContextLimitsCache?.get(`${providerID}/${modelID}`);
|
|
16052
|
-
if (typeof modelSpecific === "number" && modelSpecific > 0) {
|
|
16053
|
-
return modelSpecific;
|
|
16054
|
-
}
|
|
16055
|
-
}
|
|
16056
|
-
if (isAnthropicProvider(providerID)) {
|
|
16057
|
-
return 1e6;
|
|
16058
|
-
}
|
|
16059
|
-
return DEFAULT_CONTEXT_LIMIT;
|
|
16041
|
+
// src/hooks/magic-context/read-session-chunk.ts
|
|
16042
|
+
var activeRawMessageCache = null;
|
|
16043
|
+
function cleanUserText(text) {
|
|
16044
|
+
return removeSystemReminders(text).replace(OMO_INTERNAL_INITIATOR_MARKER, "").trim();
|
|
16060
16045
|
}
|
|
16061
|
-
function
|
|
16062
|
-
|
|
16063
|
-
|
|
16064
|
-
|
|
16065
|
-
if (modelKey && typeof cacheTtl[modelKey] === "string") {
|
|
16066
|
-
return cacheTtl[modelKey];
|
|
16046
|
+
function withRawSessionMessageCache(fn) {
|
|
16047
|
+
const outerCache = activeRawMessageCache;
|
|
16048
|
+
if (!outerCache) {
|
|
16049
|
+
activeRawMessageCache = new Map;
|
|
16067
16050
|
}
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16071
|
-
|
|
16051
|
+
try {
|
|
16052
|
+
return fn();
|
|
16053
|
+
} finally {
|
|
16054
|
+
if (!outerCache) {
|
|
16055
|
+
activeRawMessageCache = null;
|
|
16072
16056
|
}
|
|
16073
16057
|
}
|
|
16074
|
-
return cacheTtl.default ?? "5m";
|
|
16075
16058
|
}
|
|
16076
|
-
function
|
|
16077
|
-
if (
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
return config2[modelKey];
|
|
16082
|
-
}
|
|
16083
|
-
if (modelKey) {
|
|
16084
|
-
const bareModelId = modelKey.split("/").slice(1).join("/");
|
|
16085
|
-
if (bareModelId && typeof config2[bareModelId] === "number") {
|
|
16086
|
-
return config2[bareModelId];
|
|
16059
|
+
function readRawSessionMessages(sessionId) {
|
|
16060
|
+
if (activeRawMessageCache) {
|
|
16061
|
+
const cached2 = activeRawMessageCache.get(sessionId);
|
|
16062
|
+
if (cached2) {
|
|
16063
|
+
return cached2;
|
|
16087
16064
|
}
|
|
16065
|
+
const messages = withReadOnlySessionDb((db) => readRawSessionMessagesFromDb(db, sessionId));
|
|
16066
|
+
activeRawMessageCache.set(sessionId, messages);
|
|
16067
|
+
return messages;
|
|
16088
16068
|
}
|
|
16089
|
-
return
|
|
16069
|
+
return withReadOnlySessionDb((db) => readRawSessionMessagesFromDb(db, sessionId));
|
|
16090
16070
|
}
|
|
16091
|
-
function
|
|
16092
|
-
|
|
16093
|
-
return;
|
|
16094
|
-
}
|
|
16095
|
-
return `${providerID}/${modelID}`;
|
|
16071
|
+
function getRawSessionMessageCount(sessionId) {
|
|
16072
|
+
return withReadOnlySessionDb((db) => getRawSessionMessageCountFromDb(db, sessionId));
|
|
16096
16073
|
}
|
|
16097
|
-
function
|
|
16098
|
-
|
|
16099
|
-
|
|
16100
|
-
|
|
16101
|
-
|
|
16102
|
-
|
|
16103
|
-
|
|
16104
|
-
|
|
16105
|
-
|
|
16106
|
-
|
|
16107
|
-
|
|
16074
|
+
function getRawSessionTagKeysThrough(sessionId, upToMessageIndex) {
|
|
16075
|
+
const messages = readRawSessionMessages(sessionId);
|
|
16076
|
+
const keys = [];
|
|
16077
|
+
for (const message of messages) {
|
|
16078
|
+
if (message.ordinal > upToMessageIndex)
|
|
16079
|
+
break;
|
|
16080
|
+
for (const [partIndex, part] of message.parts.entries()) {
|
|
16081
|
+
if (isTextPart(part)) {
|
|
16082
|
+
keys.push(`${message.id}:p${partIndex}`);
|
|
16083
|
+
}
|
|
16084
|
+
if (isFilePart(part)) {
|
|
16085
|
+
keys.push(`${message.id}:file${partIndex}`);
|
|
16086
|
+
}
|
|
16087
|
+
if (isToolPartWithOutput(part)) {
|
|
16088
|
+
keys.push(part.callID);
|
|
16089
|
+
}
|
|
16090
|
+
}
|
|
16108
16091
|
}
|
|
16109
|
-
|
|
16110
|
-
|
|
16092
|
+
return keys;
|
|
16093
|
+
}
|
|
16094
|
+
var PROTECTED_TAIL_USER_TURNS = 5;
|
|
16095
|
+
function getProtectedTailStartOrdinal(sessionId) {
|
|
16096
|
+
const messages = readRawSessionMessages(sessionId);
|
|
16097
|
+
const userOrdinals = messages.filter((m) => m.role === "user" && hasMeaningfulUserText(m.parts)).map((m) => m.ordinal);
|
|
16098
|
+
if (userOrdinals.length < PROTECTED_TAIL_USER_TURNS) {
|
|
16099
|
+
return 1;
|
|
16111
16100
|
}
|
|
16112
|
-
return;
|
|
16101
|
+
return userOrdinals[userOrdinals.length - PROTECTED_TAIL_USER_TURNS];
|
|
16113
16102
|
}
|
|
16114
|
-
|
|
16115
|
-
|
|
16116
|
-
|
|
16117
|
-
|
|
16118
|
-
|
|
16119
|
-
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
|
|
16123
|
-
|
|
16124
|
-
|
|
16125
|
-
|
|
16126
|
-
|
|
16103
|
+
function readSessionChunk(sessionId, tokenBudget, offset = 1, eligibleEndOrdinal) {
|
|
16104
|
+
const messages = readRawSessionMessages(sessionId);
|
|
16105
|
+
const startOrdinal = Math.max(1, offset);
|
|
16106
|
+
const lines = [];
|
|
16107
|
+
const lineMeta = [];
|
|
16108
|
+
let totalTokens = 0;
|
|
16109
|
+
let messagesProcessed = 0;
|
|
16110
|
+
let lastOrdinal = startOrdinal - 1;
|
|
16111
|
+
let lastMessageId = "";
|
|
16112
|
+
let firstMessageId = "";
|
|
16113
|
+
let currentBlock = null;
|
|
16114
|
+
let pendingNoiseMeta = [];
|
|
16115
|
+
let commitClusters = 0;
|
|
16116
|
+
let lastFlushedRole = "";
|
|
16117
|
+
function flushCurrentBlock() {
|
|
16118
|
+
if (!currentBlock)
|
|
16119
|
+
return true;
|
|
16120
|
+
const blockText = formatBlock(currentBlock);
|
|
16121
|
+
const blockTokens = estimateTokens(blockText);
|
|
16122
|
+
if (totalTokens + blockTokens > tokenBudget && totalTokens > 0) {
|
|
16123
|
+
return false;
|
|
16124
|
+
}
|
|
16125
|
+
if (currentBlock.role === "A" && currentBlock.commitHashes.length > 0 && lastFlushedRole !== "A") {
|
|
16126
|
+
commitClusters++;
|
|
16127
|
+
}
|
|
16128
|
+
lastFlushedRole = currentBlock.role;
|
|
16129
|
+
if (!firstMessageId)
|
|
16130
|
+
firstMessageId = currentBlock.meta[0]?.messageId ?? "";
|
|
16131
|
+
lastOrdinal = currentBlock.meta[currentBlock.meta.length - 1]?.ordinal ?? currentBlock.endOrdinal;
|
|
16132
|
+
lastMessageId = currentBlock.meta[currentBlock.meta.length - 1]?.messageId ?? "";
|
|
16133
|
+
messagesProcessed += currentBlock.meta.length;
|
|
16134
|
+
lines.push(blockText);
|
|
16135
|
+
lineMeta.push(...currentBlock.meta);
|
|
16136
|
+
totalTokens += blockTokens;
|
|
16137
|
+
currentBlock = null;
|
|
16138
|
+
return true;
|
|
16127
16139
|
}
|
|
16128
|
-
const
|
|
16129
|
-
|
|
16130
|
-
|
|
16140
|
+
for (const msg of messages) {
|
|
16141
|
+
if (eligibleEndOrdinal !== undefined && msg.ordinal >= eligibleEndOrdinal)
|
|
16142
|
+
break;
|
|
16143
|
+
if (msg.ordinal < startOrdinal)
|
|
16144
|
+
continue;
|
|
16145
|
+
const meta3 = { ordinal: msg.ordinal, messageId: msg.id };
|
|
16146
|
+
if (msg.role === "user" && !hasMeaningfulUserText(msg.parts)) {
|
|
16147
|
+
pendingNoiseMeta.push(meta3);
|
|
16148
|
+
continue;
|
|
16149
|
+
}
|
|
16150
|
+
const role = compactRole(msg.role);
|
|
16151
|
+
const compacted = compactTextForSummary(extractTexts(msg.parts).map((t) => msg.role === "user" ? cleanUserText(t) : t).map(normalizeText).filter((value) => value.length > 0).join(" / "), msg.role);
|
|
16152
|
+
const text = compacted.text;
|
|
16153
|
+
if (!text) {
|
|
16154
|
+
pendingNoiseMeta.push(meta3);
|
|
16155
|
+
continue;
|
|
16156
|
+
}
|
|
16157
|
+
if (currentBlock && currentBlock.role === role) {
|
|
16158
|
+
currentBlock.endOrdinal = msg.ordinal;
|
|
16159
|
+
currentBlock.parts.push(text);
|
|
16160
|
+
currentBlock.meta.push(...pendingNoiseMeta, meta3);
|
|
16161
|
+
currentBlock.commitHashes = mergeCommitHashes(currentBlock.commitHashes, compacted.commitHashes);
|
|
16162
|
+
pendingNoiseMeta = [];
|
|
16163
|
+
continue;
|
|
16164
|
+
}
|
|
16165
|
+
if (!flushCurrentBlock())
|
|
16166
|
+
break;
|
|
16167
|
+
currentBlock = {
|
|
16168
|
+
role,
|
|
16169
|
+
startOrdinal: pendingNoiseMeta[0]?.ordinal ?? msg.ordinal,
|
|
16170
|
+
endOrdinal: msg.ordinal,
|
|
16171
|
+
parts: [text],
|
|
16172
|
+
meta: [...pendingNoiseMeta, meta3],
|
|
16173
|
+
commitHashes: [...compacted.commitHashes]
|
|
16174
|
+
};
|
|
16175
|
+
pendingNoiseMeta = [];
|
|
16131
16176
|
}
|
|
16132
|
-
|
|
16133
|
-
const unit = match[2];
|
|
16134
|
-
return value * UNIT_TO_MS[unit];
|
|
16135
|
-
}
|
|
16136
|
-
function createScheduler(config2) {
|
|
16177
|
+
flushCurrentBlock();
|
|
16137
16178
|
return {
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
|
|
16145
|
-
|
|
16146
|
-
|
|
16147
|
-
|
|
16148
|
-
|
|
16149
|
-
} else {
|
|
16150
|
-
log(`[magic-context] invalid cache_ttl "${sessionMeta.cacheTtl}"; falling back to default 5m`, error48);
|
|
16151
|
-
}
|
|
16152
|
-
ttlMs = parseCacheTtl("5m");
|
|
16153
|
-
}
|
|
16154
|
-
const elapsedTime = currentTime - sessionMeta.lastResponseTime;
|
|
16155
|
-
if (elapsedTime > ttlMs) {
|
|
16156
|
-
return "execute";
|
|
16157
|
-
}
|
|
16158
|
-
return "defer";
|
|
16159
|
-
}
|
|
16179
|
+
startIndex: startOrdinal,
|
|
16180
|
+
endIndex: lastOrdinal,
|
|
16181
|
+
startMessageId: firstMessageId,
|
|
16182
|
+
endMessageId: lastMessageId,
|
|
16183
|
+
messageCount: messagesProcessed,
|
|
16184
|
+
tokenEstimate: totalTokens,
|
|
16185
|
+
hasMore: lastOrdinal < (eligibleEndOrdinal !== undefined ? Math.min(eligibleEndOrdinal - 1, messages.length) : messages.length),
|
|
16186
|
+
text: lines.join(`
|
|
16187
|
+
`),
|
|
16188
|
+
lines: lineMeta,
|
|
16189
|
+
commitClusterCount: commitClusters
|
|
16160
16190
|
};
|
|
16161
16191
|
}
|
|
16162
16192
|
|
|
16163
|
-
// src/features/magic-context/
|
|
16164
|
-
var
|
|
16165
|
-
var
|
|
16166
|
-
|
|
16167
|
-
|
|
16168
|
-
|
|
16193
|
+
// src/features/magic-context/message-index.ts
|
|
16194
|
+
var lastIndexedStatements = new WeakMap;
|
|
16195
|
+
var insertMessageStatements = new WeakMap;
|
|
16196
|
+
var upsertIndexStatements = new WeakMap;
|
|
16197
|
+
var deleteFtsStatements = new WeakMap;
|
|
16198
|
+
var deleteIndexStatements = new WeakMap;
|
|
16199
|
+
function normalizeIndexText(text) {
|
|
16200
|
+
return text.replace(/\s+/g, " ").trim();
|
|
16201
|
+
}
|
|
16202
|
+
function getLastIndexedStatement(db) {
|
|
16203
|
+
let stmt = lastIndexedStatements.get(db);
|
|
16204
|
+
if (!stmt) {
|
|
16205
|
+
stmt = db.prepare("SELECT last_indexed_ordinal FROM message_history_index WHERE session_id = ?");
|
|
16206
|
+
lastIndexedStatements.set(db, stmt);
|
|
16169
16207
|
}
|
|
16170
|
-
|
|
16171
|
-
return typeof candidate.message_id === "string" && typeof candidate.tag_number === "number";
|
|
16208
|
+
return stmt;
|
|
16172
16209
|
}
|
|
16173
|
-
|
|
16174
|
-
|
|
16175
|
-
VALUES (?, ?)
|
|
16176
|
-
ON CONFLICT(session_id) DO UPDATE SET counter = excluded.counter
|
|
16177
|
-
`;
|
|
16178
|
-
var upsertCounterStatements = new WeakMap;
|
|
16179
|
-
function getUpsertCounterStatement(db) {
|
|
16180
|
-
let stmt = upsertCounterStatements.get(db);
|
|
16210
|
+
function getInsertMessageStatement(db) {
|
|
16211
|
+
let stmt = insertMessageStatements.get(db);
|
|
16181
16212
|
if (!stmt) {
|
|
16182
|
-
stmt = db.prepare(
|
|
16183
|
-
|
|
16213
|
+
stmt = db.prepare("INSERT INTO message_history_fts (session_id, message_ordinal, message_id, role, content) VALUES (?, ?, ?, ?, ?)");
|
|
16214
|
+
insertMessageStatements.set(db, stmt);
|
|
16184
16215
|
}
|
|
16185
16216
|
return stmt;
|
|
16186
16217
|
}
|
|
16187
|
-
function
|
|
16188
|
-
|
|
16189
|
-
|
|
16190
|
-
|
|
16191
|
-
|
|
16192
|
-
if (!map2) {
|
|
16193
|
-
map2 = new Map;
|
|
16194
|
-
assignments.set(sessionId, map2);
|
|
16195
|
-
}
|
|
16196
|
-
return map2;
|
|
16218
|
+
function getUpsertIndexStatement(db) {
|
|
16219
|
+
let stmt = upsertIndexStatements.get(db);
|
|
16220
|
+
if (!stmt) {
|
|
16221
|
+
stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, updated_at) VALUES (?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = excluded.last_indexed_ordinal, updated_at = excluded.updated_at");
|
|
16222
|
+
upsertIndexStatements.set(db, stmt);
|
|
16197
16223
|
}
|
|
16198
|
-
|
|
16199
|
-
|
|
16200
|
-
|
|
16201
|
-
|
|
16202
|
-
|
|
16203
|
-
|
|
16204
|
-
|
|
16205
|
-
const next = current + 1;
|
|
16206
|
-
db.transaction(() => {
|
|
16207
|
-
insertTag(db, sessionId, messageId, type, byteSize, next);
|
|
16208
|
-
getUpsertCounterStatement(db).run(sessionId, next);
|
|
16209
|
-
})();
|
|
16210
|
-
counters.set(sessionId, next);
|
|
16211
|
-
sessionAssignments.set(messageId, next);
|
|
16212
|
-
return next;
|
|
16224
|
+
return stmt;
|
|
16225
|
+
}
|
|
16226
|
+
function getDeleteFtsStatement(db) {
|
|
16227
|
+
let stmt = deleteFtsStatements.get(db);
|
|
16228
|
+
if (!stmt) {
|
|
16229
|
+
stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ?");
|
|
16230
|
+
deleteFtsStatements.set(db, stmt);
|
|
16213
16231
|
}
|
|
16214
|
-
|
|
16215
|
-
|
|
16232
|
+
return stmt;
|
|
16233
|
+
}
|
|
16234
|
+
function getDeleteIndexStatement(db) {
|
|
16235
|
+
let stmt = deleteIndexStatements.get(db);
|
|
16236
|
+
if (!stmt) {
|
|
16237
|
+
stmt = db.prepare("DELETE FROM message_history_index WHERE session_id = ?");
|
|
16238
|
+
deleteIndexStatements.set(db, stmt);
|
|
16216
16239
|
}
|
|
16217
|
-
|
|
16218
|
-
|
|
16240
|
+
return stmt;
|
|
16241
|
+
}
|
|
16242
|
+
function getLastIndexedOrdinal(db, sessionId) {
|
|
16243
|
+
const row = getLastIndexedStatement(db).get(sessionId);
|
|
16244
|
+
return typeof row?.last_indexed_ordinal === "number" ? row.last_indexed_ordinal : 0;
|
|
16245
|
+
}
|
|
16246
|
+
function clearIndexedMessages(db, sessionId) {
|
|
16247
|
+
getDeleteFtsStatement(db).run(sessionId);
|
|
16248
|
+
getDeleteIndexStatement(db).run(sessionId);
|
|
16249
|
+
}
|
|
16250
|
+
function getIndexableContent(role, parts) {
|
|
16251
|
+
if (role === "user") {
|
|
16252
|
+
if (!hasMeaningfulUserText(parts)) {
|
|
16253
|
+
return "";
|
|
16254
|
+
}
|
|
16255
|
+
return extractTexts(parts).map(cleanUserText).map(normalizeIndexText).filter((text) => text.length > 0).join(" / ");
|
|
16219
16256
|
}
|
|
16220
|
-
|
|
16221
|
-
return
|
|
16257
|
+
if (role === "assistant") {
|
|
16258
|
+
return extractTexts(parts).map(removeSystemReminders).map(normalizeIndexText).filter((text) => text.length > 0).join(" / ");
|
|
16222
16259
|
}
|
|
16223
|
-
|
|
16224
|
-
|
|
16225
|
-
|
|
16226
|
-
|
|
16260
|
+
return "";
|
|
16261
|
+
}
|
|
16262
|
+
function ensureMessagesIndexed(db, sessionId, readMessages) {
|
|
16263
|
+
const messages = readMessages(sessionId);
|
|
16264
|
+
if (messages.length === 0) {
|
|
16265
|
+
db.transaction(() => clearIndexedMessages(db, sessionId))();
|
|
16266
|
+
return;
|
|
16227
16267
|
}
|
|
16228
|
-
|
|
16229
|
-
|
|
16268
|
+
let lastIndexedOrdinal = getLastIndexedOrdinal(db, sessionId);
|
|
16269
|
+
if (lastIndexedOrdinal > messages.length) {
|
|
16270
|
+
db.transaction(() => clearIndexedMessages(db, sessionId))();
|
|
16271
|
+
lastIndexedOrdinal = 0;
|
|
16230
16272
|
}
|
|
16231
|
-
|
|
16232
|
-
|
|
16233
|
-
return;
|
|
16234
|
-
}
|
|
16235
|
-
const row = db.prepare(GET_COUNTER_SQL).get(sessionId);
|
|
16236
|
-
const assignmentRows = db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId).filter(isAssignmentRow);
|
|
16237
|
-
const sessionAssignments = getSessionAssignments(sessionId);
|
|
16238
|
-
sessionAssignments.clear();
|
|
16239
|
-
let maxTagNumber = 0;
|
|
16240
|
-
for (const assignment of assignmentRows) {
|
|
16241
|
-
sessionAssignments.set(assignment.message_id, assignment.tag_number);
|
|
16242
|
-
if (assignment.tag_number > maxTagNumber) {
|
|
16243
|
-
maxTagNumber = assignment.tag_number;
|
|
16244
|
-
}
|
|
16245
|
-
}
|
|
16246
|
-
const counter = Math.max(row?.counter ?? 0, maxTagNumber);
|
|
16247
|
-
counters.set(sessionId, counter);
|
|
16248
|
-
}
|
|
16249
|
-
function cleanup(sessionId) {
|
|
16250
|
-
counters.delete(sessionId);
|
|
16251
|
-
assignments.delete(sessionId);
|
|
16273
|
+
if (lastIndexedOrdinal >= messages.length) {
|
|
16274
|
+
return;
|
|
16252
16275
|
}
|
|
16253
|
-
|
|
16254
|
-
|
|
16255
|
-
|
|
16256
|
-
|
|
16257
|
-
|
|
16258
|
-
|
|
16259
|
-
|
|
16260
|
-
|
|
16261
|
-
|
|
16262
|
-
|
|
16276
|
+
const messagesToInsert = messages.filter((message) => message.ordinal > lastIndexedOrdinal).filter((message) => message.role === "user" || message.role === "assistant").map((message) => ({
|
|
16277
|
+
ordinal: message.ordinal,
|
|
16278
|
+
id: message.id,
|
|
16279
|
+
role: message.role,
|
|
16280
|
+
content: getIndexableContent(message.role, message.parts)
|
|
16281
|
+
})).filter((message) => message.content.length > 0);
|
|
16282
|
+
const now = Date.now();
|
|
16283
|
+
db.transaction(() => {
|
|
16284
|
+
const insertMessage = getInsertMessageStatement(db);
|
|
16285
|
+
for (const message of messagesToInsert) {
|
|
16286
|
+
insertMessage.run(sessionId, message.ordinal, message.id, message.role, message.content);
|
|
16287
|
+
}
|
|
16288
|
+
getUpsertIndexStatement(db).run(sessionId, messages.length, now);
|
|
16289
|
+
})();
|
|
16263
16290
|
}
|
|
16264
16291
|
|
|
16265
|
-
// src/features/magic-context/
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
|
|
16275
|
-
|
|
16276
|
-
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
16280
|
-
|
|
16281
|
-
|
|
16292
|
+
// src/features/magic-context/storage-meta-session.ts
|
|
16293
|
+
function getOrCreateSessionMeta(db, sessionId) {
|
|
16294
|
+
const result = db.prepare("SELECT session_id, last_response_time, cache_ttl, counter, last_nudge_tokens, last_nudge_band, last_transform_error, is_subagent, last_context_percentage, last_input_tokens, times_execute_threshold_reached, compartment_in_progress, system_prompt_hash FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
16295
|
+
if (isSessionMetaRow(result)) {
|
|
16296
|
+
return toSessionMeta(result);
|
|
16297
|
+
}
|
|
16298
|
+
const defaults = getDefaultSessionMeta(sessionId);
|
|
16299
|
+
ensureSessionMetaRow(db, sessionId);
|
|
16300
|
+
return defaults;
|
|
16301
|
+
}
|
|
16302
|
+
function updateSessionMeta(db, sessionId, updates) {
|
|
16303
|
+
const setClauses = [];
|
|
16304
|
+
const values = [];
|
|
16305
|
+
for (const [key, column] of Object.entries(META_COLUMNS)) {
|
|
16306
|
+
const value = updates[key];
|
|
16307
|
+
if (value === undefined)
|
|
16308
|
+
continue;
|
|
16309
|
+
if (value === null) {
|
|
16310
|
+
setClauses.push(`${column} = ?`);
|
|
16311
|
+
values.push("");
|
|
16312
|
+
} else if (BOOLEAN_META_KEYS.has(key)) {
|
|
16313
|
+
setClauses.push(`${column} = ?`);
|
|
16314
|
+
values.push(value ? 1 : 0);
|
|
16315
|
+
} else if (typeof value === "string" || typeof value === "number") {
|
|
16316
|
+
setClauses.push(`${column} = ?`);
|
|
16317
|
+
values.push(value);
|
|
16318
|
+
}
|
|
16319
|
+
}
|
|
16320
|
+
if (setClauses.length === 0) {
|
|
16282
16321
|
return;
|
|
16283
16322
|
}
|
|
16323
|
+
db.transaction(() => {
|
|
16324
|
+
ensureSessionMetaRow(db, sessionId);
|
|
16325
|
+
db.prepare(`UPDATE session_meta SET ${setClauses.join(", ")} WHERE session_id = ?`).run(...values, sessionId);
|
|
16326
|
+
})();
|
|
16284
16327
|
}
|
|
16285
|
-
function
|
|
16286
|
-
|
|
16287
|
-
|
|
16288
|
-
|
|
16328
|
+
function clearSession(db, sessionId) {
|
|
16329
|
+
db.transaction(() => {
|
|
16330
|
+
db.prepare("DELETE FROM pending_ops WHERE session_id = ?").run(sessionId);
|
|
16331
|
+
db.prepare("DELETE FROM source_contents WHERE session_id = ?").run(sessionId);
|
|
16332
|
+
db.prepare("DELETE FROM tags WHERE session_id = ?").run(sessionId);
|
|
16333
|
+
db.prepare("DELETE FROM session_meta WHERE session_id = ?").run(sessionId);
|
|
16334
|
+
db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
|
|
16335
|
+
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
16336
|
+
db.prepare("DELETE FROM session_notes WHERE session_id = ?").run(sessionId);
|
|
16337
|
+
db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
|
|
16338
|
+
db.prepare("DELETE FROM recomp_facts WHERE session_id = ?").run(sessionId);
|
|
16339
|
+
clearIndexedMessages(db, sessionId);
|
|
16340
|
+
})();
|
|
16289
16341
|
}
|
|
16290
|
-
|
|
16291
|
-
|
|
16292
|
-
|
|
16293
|
-
|
|
16294
|
-
|
|
16295
|
-
|
|
16296
|
-
const rootHash = getRootCommitHash(resolved);
|
|
16297
|
-
const identity = rootHash ? `git:${rootHash}` : directoryFallback(resolved);
|
|
16298
|
-
resolvedCache.set(resolved, identity);
|
|
16299
|
-
return identity;
|
|
16342
|
+
// src/features/magic-context/storage-notes.ts
|
|
16343
|
+
function isSessionNoteRow(row) {
|
|
16344
|
+
if (row === null || typeof row !== "object")
|
|
16345
|
+
return false;
|
|
16346
|
+
const candidate = row;
|
|
16347
|
+
return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number";
|
|
16300
16348
|
}
|
|
16301
|
-
|
|
16302
|
-
|
|
16303
|
-
|
|
16304
|
-
|
|
16305
|
-
|
|
16306
|
-
|
|
16307
|
-
|
|
16308
|
-
}
|
|
16309
|
-
let dropped = 0;
|
|
16310
|
-
db.transaction(() => {
|
|
16311
|
-
for (const op of pendingOps) {
|
|
16312
|
-
updateTagStatus(db, sessionId, op.tagId, "dropped");
|
|
16313
|
-
removePendingOp(db, sessionId, op.tagId);
|
|
16314
|
-
dropped++;
|
|
16315
|
-
}
|
|
16316
|
-
})();
|
|
16317
|
-
const parts = [];
|
|
16318
|
-
if (dropped > 0)
|
|
16319
|
-
parts.push(`${dropped} dropped`);
|
|
16320
|
-
if (dropped > 0) {
|
|
16321
|
-
clearPersistedStickyTurnReminder(db, sessionId);
|
|
16322
|
-
}
|
|
16323
|
-
return `Flushed: ${parts.join(", ")}. Changes take effect on next message.`;
|
|
16324
|
-
} catch (error48) {
|
|
16325
|
-
sessionLog(sessionId, "ctx-flush failed:", error48);
|
|
16326
|
-
return `Error: Failed to flush context operations. ${getErrorMessage(error48)}`;
|
|
16327
|
-
}
|
|
16349
|
+
function toSessionNote(row) {
|
|
16350
|
+
return {
|
|
16351
|
+
id: row.id,
|
|
16352
|
+
sessionId: row.session_id,
|
|
16353
|
+
content: row.content,
|
|
16354
|
+
createdAt: row.created_at
|
|
16355
|
+
};
|
|
16328
16356
|
}
|
|
16329
|
-
|
|
16330
|
-
|
|
16331
|
-
|
|
16332
|
-
|
|
16333
|
-
// src/shared/system-directive.ts
|
|
16334
|
-
var SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: MAGIC-CONTEXT";
|
|
16335
|
-
function isSystemDirective(text) {
|
|
16336
|
-
return text.trimStart().startsWith(SYSTEM_DIRECTIVE_PREFIX);
|
|
16357
|
+
function getSessionNotes(db, sessionId) {
|
|
16358
|
+
const rows = db.prepare("SELECT * FROM session_notes WHERE session_id = ? ORDER BY id ASC").all(sessionId).filter(isSessionNoteRow);
|
|
16359
|
+
return rows.map(toSessionNote);
|
|
16337
16360
|
}
|
|
16338
|
-
function
|
|
16339
|
-
|
|
16361
|
+
function addSessionNote(db, sessionId, content) {
|
|
16362
|
+
db.prepare("INSERT INTO session_notes (session_id, content, created_at) VALUES (?, ?, ?)").run(sessionId, content, Date.now());
|
|
16340
16363
|
}
|
|
16341
|
-
|
|
16342
|
-
|
|
16343
|
-
import { Database as Database2 } from "bun:sqlite";
|
|
16344
|
-
import { join as join6 } from "path";
|
|
16345
|
-
function getOpenCodeDbPath() {
|
|
16346
|
-
return join6(getDataDir(), "opencode", "opencode.db");
|
|
16364
|
+
function clearSessionNotes(db, sessionId) {
|
|
16365
|
+
db.prepare("DELETE FROM session_notes WHERE session_id = ?").run(sessionId);
|
|
16347
16366
|
}
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
|
|
16353
|
-
|
|
16354
|
-
|
|
16355
|
-
|
|
16356
|
-
|
|
16357
|
-
|
|
16358
|
-
cachedReadOnlyDb = null;
|
|
16367
|
+
// src/features/magic-context/storage-ops.ts
|
|
16368
|
+
var queuePendingOpStatements = new WeakMap;
|
|
16369
|
+
var getPendingOpsStatements = new WeakMap;
|
|
16370
|
+
var clearPendingOpsStatements = new WeakMap;
|
|
16371
|
+
var removePendingOpStatements = new WeakMap;
|
|
16372
|
+
function getQueuePendingOpStatement(db) {
|
|
16373
|
+
let stmt = queuePendingOpStatements.get(db);
|
|
16374
|
+
if (!stmt) {
|
|
16375
|
+
stmt = db.prepare("INSERT INTO pending_ops (session_id, tag_id, operation, queued_at) VALUES (?, ?, ?, ?)");
|
|
16376
|
+
queuePendingOpStatements.set(db, stmt);
|
|
16359
16377
|
}
|
|
16378
|
+
return stmt;
|
|
16360
16379
|
}
|
|
16361
|
-
function
|
|
16362
|
-
|
|
16363
|
-
if (
|
|
16364
|
-
|
|
16380
|
+
function getPendingOpsStatement(db) {
|
|
16381
|
+
let stmt = getPendingOpsStatements.get(db);
|
|
16382
|
+
if (!stmt) {
|
|
16383
|
+
stmt = db.prepare("SELECT id, session_id, tag_id, operation, queued_at FROM pending_ops WHERE session_id = ? ORDER BY queued_at ASC, id ASC");
|
|
16384
|
+
getPendingOpsStatements.set(db, stmt);
|
|
16365
16385
|
}
|
|
16366
|
-
|
|
16367
|
-
const db = new Database2(dbPath, { readonly: true });
|
|
16368
|
-
cachedReadOnlyDb = { path: dbPath, db };
|
|
16369
|
-
return db;
|
|
16386
|
+
return stmt;
|
|
16370
16387
|
}
|
|
16371
|
-
function
|
|
16372
|
-
|
|
16388
|
+
function getRemovePendingOpStatement(db) {
|
|
16389
|
+
let stmt = removePendingOpStatements.get(db);
|
|
16390
|
+
if (!stmt) {
|
|
16391
|
+
stmt = db.prepare("DELETE FROM pending_ops WHERE session_id = ? AND tag_id = ?");
|
|
16392
|
+
removePendingOpStatements.set(db, stmt);
|
|
16393
|
+
}
|
|
16394
|
+
return stmt;
|
|
16373
16395
|
}
|
|
16374
|
-
function
|
|
16375
|
-
|
|
16376
|
-
|
|
16396
|
+
function isPendingOpRow(row) {
|
|
16397
|
+
if (row === null || typeof row !== "object")
|
|
16398
|
+
return false;
|
|
16399
|
+
const r = row;
|
|
16400
|
+
return typeof r.id === "number" && typeof r.session_id === "string" && typeof r.tag_id === "number" && typeof r.operation === "string" && typeof r.queued_at === "number";
|
|
16377
16401
|
}
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
var MAX_COMMITS_PER_BLOCK = 5;
|
|
16383
|
-
function hasMeaningfulUserText(parts) {
|
|
16384
|
-
for (const part of parts) {
|
|
16385
|
-
if (part === null || typeof part !== "object")
|
|
16386
|
-
continue;
|
|
16387
|
-
const candidate = part;
|
|
16388
|
-
if (candidate.type !== "text" || typeof candidate.text !== "string")
|
|
16389
|
-
continue;
|
|
16390
|
-
if (candidate.ignored === true)
|
|
16391
|
-
continue;
|
|
16392
|
-
const cleaned = removeSystemReminders(candidate.text).replace(OMO_INTERNAL_INITIATOR_MARKER, "").trim();
|
|
16393
|
-
if (!cleaned)
|
|
16394
|
-
continue;
|
|
16395
|
-
if (isSystemDirective(cleaned))
|
|
16396
|
-
continue;
|
|
16397
|
-
return true;
|
|
16402
|
+
function toPendingOp(row) {
|
|
16403
|
+
if (row.operation !== "drop") {
|
|
16404
|
+
sessionLog(row.session_id, `unknown pending operation "${row.operation}"; ignoring`);
|
|
16405
|
+
return null;
|
|
16398
16406
|
}
|
|
16399
|
-
return
|
|
16407
|
+
return {
|
|
16408
|
+
id: row.id,
|
|
16409
|
+
sessionId: row.session_id,
|
|
16410
|
+
tagId: row.tag_id,
|
|
16411
|
+
operation: row.operation,
|
|
16412
|
+
queuedAt: row.queued_at
|
|
16413
|
+
};
|
|
16400
16414
|
}
|
|
16401
|
-
function
|
|
16402
|
-
|
|
16403
|
-
for (const part of parts) {
|
|
16404
|
-
if (part === null || typeof part !== "object")
|
|
16405
|
-
continue;
|
|
16406
|
-
const p = part;
|
|
16407
|
-
if (p.type === "text" && typeof p.text === "string" && p.text.trim().length > 0) {
|
|
16408
|
-
texts.push(p.text.trim());
|
|
16409
|
-
}
|
|
16410
|
-
}
|
|
16411
|
-
return texts;
|
|
16415
|
+
function queuePendingOp(db, sessionId, tagId, operation, queuedAt = Date.now()) {
|
|
16416
|
+
getQueuePendingOpStatement(db).run(sessionId, tagId, operation, queuedAt);
|
|
16412
16417
|
}
|
|
16413
|
-
function
|
|
16414
|
-
|
|
16418
|
+
function getPendingOps(db, sessionId) {
|
|
16419
|
+
const rows = getPendingOpsStatement(db).all(sessionId).filter(isPendingOpRow);
|
|
16420
|
+
return rows.map(toPendingOp).filter((op) => op !== null);
|
|
16415
16421
|
}
|
|
16416
|
-
function
|
|
16417
|
-
|
|
16422
|
+
function removePendingOp(db, sessionId, tagId) {
|
|
16423
|
+
getRemovePendingOpStatement(db).run(sessionId, tagId);
|
|
16418
16424
|
}
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
|
|
16422
|
-
|
|
16423
|
-
|
|
16424
|
-
return
|
|
16425
|
+
// src/features/magic-context/storage-source.ts
|
|
16426
|
+
function isSourceContentRow(row) {
|
|
16427
|
+
if (row === null || typeof row !== "object")
|
|
16428
|
+
return false;
|
|
16429
|
+
const r = row;
|
|
16430
|
+
return typeof r.tag_id === "number" && typeof r.content === "string";
|
|
16425
16431
|
}
|
|
16426
|
-
function
|
|
16427
|
-
|
|
16428
|
-
const commitSuffix = block.commitHashes.length > 0 ? ` commits: ${block.commitHashes.join(", ")}` : "";
|
|
16429
|
-
return `${range} ${block.role}:${commitSuffix} ${block.parts.join(" / ")}`;
|
|
16432
|
+
function saveSourceContent(db, sessionId, tagId, content) {
|
|
16433
|
+
db.prepare("INSERT OR IGNORE INTO source_contents (tag_id, session_id, content, created_at) VALUES (?, ?, ?, ?)").run(tagId, sessionId, content, Date.now());
|
|
16430
16434
|
}
|
|
16431
|
-
function
|
|
16432
|
-
|
|
16433
|
-
|
|
16434
|
-
|
|
16435
|
-
|
|
16436
|
-
|
|
16437
|
-
|
|
16438
|
-
|
|
16439
|
-
|
|
16440
|
-
if (hashes.length >= MAX_COMMITS_PER_BLOCK)
|
|
16441
|
-
break;
|
|
16435
|
+
function replaceSourceContent(db, sessionId, tagId, content) {
|
|
16436
|
+
db.prepare(`INSERT INTO source_contents (tag_id, session_id, content, created_at)
|
|
16437
|
+
VALUES (?, ?, ?, ?)
|
|
16438
|
+
ON CONFLICT(session_id, tag_id)
|
|
16439
|
+
DO UPDATE SET content = excluded.content, created_at = excluded.created_at`).run(tagId, sessionId, content, Date.now());
|
|
16440
|
+
}
|
|
16441
|
+
function getSourceContents(db, sessionId, tagIds) {
|
|
16442
|
+
if (tagIds.length === 0) {
|
|
16443
|
+
return new Map;
|
|
16442
16444
|
}
|
|
16443
|
-
|
|
16445
|
+
const placeholders = tagIds.map(() => "?").join(", ");
|
|
16446
|
+
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${placeholders})`).all(sessionId, ...tagIds).filter(isSourceContentRow);
|
|
16447
|
+
const sources = new Map;
|
|
16448
|
+
for (const row of rows) {
|
|
16449
|
+
sources.set(row.tag_id, row.content);
|
|
16450
|
+
}
|
|
16451
|
+
return sources;
|
|
16444
16452
|
}
|
|
16445
|
-
|
|
16446
|
-
|
|
16447
|
-
|
|
16448
|
-
|
|
16453
|
+
// src/features/magic-context/storage-tags.ts
|
|
16454
|
+
var insertTagStatements = new WeakMap;
|
|
16455
|
+
var updateTagStatusStatements = new WeakMap;
|
|
16456
|
+
var updateTagMessageIdStatements = new WeakMap;
|
|
16457
|
+
function getInsertTagStatement(db) {
|
|
16458
|
+
let stmt = insertTagStatements.get(db);
|
|
16459
|
+
if (!stmt) {
|
|
16460
|
+
stmt = db.prepare("INSERT INTO tags (session_id, message_id, type, byte_size, tag_number) VALUES (?, ?, ?, ?, ?)");
|
|
16461
|
+
insertTagStatements.set(db, stmt);
|
|
16449
16462
|
}
|
|
16450
|
-
|
|
16451
|
-
return {
|
|
16452
|
-
text: withoutHashes.length > 0 ? withoutHashes : text,
|
|
16453
|
-
commitHashes
|
|
16454
|
-
};
|
|
16463
|
+
return stmt;
|
|
16455
16464
|
}
|
|
16456
|
-
function
|
|
16457
|
-
|
|
16458
|
-
|
|
16459
|
-
|
|
16460
|
-
|
|
16461
|
-
if (merged.includes(hash2))
|
|
16462
|
-
continue;
|
|
16463
|
-
merged.push(hash2);
|
|
16464
|
-
if (merged.length >= MAX_COMMITS_PER_BLOCK)
|
|
16465
|
-
break;
|
|
16465
|
+
function getUpdateTagStatusStatement(db) {
|
|
16466
|
+
let stmt = updateTagStatusStatements.get(db);
|
|
16467
|
+
if (!stmt) {
|
|
16468
|
+
stmt = db.prepare("UPDATE tags SET status = ? WHERE session_id = ? AND tag_number = ?");
|
|
16469
|
+
updateTagStatusStatements.set(db, stmt);
|
|
16466
16470
|
}
|
|
16467
|
-
return
|
|
16471
|
+
return stmt;
|
|
16468
16472
|
}
|
|
16469
|
-
|
|
16470
|
-
|
|
16471
|
-
|
|
16472
|
-
|
|
16473
|
-
|
|
16474
|
-
|
|
16475
|
-
return
|
|
16473
|
+
function getUpdateTagMessageIdStatement(db) {
|
|
16474
|
+
let stmt = updateTagMessageIdStatements.get(db);
|
|
16475
|
+
if (!stmt) {
|
|
16476
|
+
stmt = db.prepare("UPDATE tags SET message_id = ? WHERE session_id = ? AND tag_number = ?");
|
|
16477
|
+
updateTagMessageIdStatements.set(db, stmt);
|
|
16478
|
+
}
|
|
16479
|
+
return stmt;
|
|
16476
16480
|
}
|
|
16477
|
-
function
|
|
16481
|
+
function isTagRow(row) {
|
|
16478
16482
|
if (row === null || typeof row !== "object")
|
|
16479
16483
|
return false;
|
|
16480
|
-
const
|
|
16481
|
-
return typeof
|
|
16484
|
+
const r = row;
|
|
16485
|
+
return typeof r.id === "number" && typeof r.message_id === "string" && typeof r.type === "string" && typeof r.status === "string" && typeof r.byte_size === "number" && typeof r.session_id === "string" && typeof r.tag_number === "number";
|
|
16482
16486
|
}
|
|
16483
|
-
function
|
|
16484
|
-
const
|
|
16485
|
-
|
|
16486
|
-
|
|
16487
|
-
|
|
16488
|
-
|
|
16487
|
+
function toTagEntry(row) {
|
|
16488
|
+
const type = row.type === "tool" ? "tool" : row.type === "file" ? "file" : "message";
|
|
16489
|
+
const status = row.status === "dropped" || row.status === "compacted" ? row.status : "active";
|
|
16490
|
+
return {
|
|
16491
|
+
tagNumber: row.tag_number,
|
|
16492
|
+
messageId: row.message_id,
|
|
16493
|
+
type,
|
|
16494
|
+
status,
|
|
16495
|
+
byteSize: row.byte_size,
|
|
16496
|
+
sessionId: row.session_id
|
|
16497
|
+
};
|
|
16489
16498
|
}
|
|
16490
|
-
function
|
|
16491
|
-
|
|
16499
|
+
function insertTag(db, sessionId, messageId, type, byteSize2, tagNumber) {
|
|
16500
|
+
getInsertTagStatement(db).run(sessionId, messageId, type, byteSize2, tagNumber);
|
|
16501
|
+
return tagNumber;
|
|
16492
16502
|
}
|
|
16493
|
-
function
|
|
16494
|
-
|
|
16495
|
-
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16503
|
+
function updateTagStatus(db, sessionId, tagId, status) {
|
|
16504
|
+
getUpdateTagStatusStatement(db).run(status, sessionId, tagId);
|
|
16505
|
+
}
|
|
16506
|
+
function updateTagMessageId(db, sessionId, tagId, messageId) {
|
|
16507
|
+
getUpdateTagMessageIdStatement(db).run(messageId, sessionId, tagId);
|
|
16508
|
+
}
|
|
16509
|
+
function getTagsBySession(db, sessionId) {
|
|
16510
|
+
const rows = db.prepare("SELECT id, message_id, type, status, byte_size, session_id, tag_number FROM tags WHERE session_id = ? ORDER BY tag_number ASC, id ASC").all(sessionId).filter(isTagRow);
|
|
16511
|
+
return rows.map(toTagEntry);
|
|
16512
|
+
}
|
|
16513
|
+
function getTopNBySize(db, sessionId, n) {
|
|
16514
|
+
if (n <= 0) {
|
|
16515
|
+
return [];
|
|
16501
16516
|
}
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
const role = typeof info.role === "string" ? info.role : "unknown";
|
|
16505
|
-
return {
|
|
16506
|
-
ordinal: index + 1,
|
|
16507
|
-
id: row.id,
|
|
16508
|
-
role,
|
|
16509
|
-
parts: partsByMessageId.get(row.id) ?? []
|
|
16510
|
-
};
|
|
16511
|
-
});
|
|
16517
|
+
const rows = db.prepare("SELECT id, message_id, type, status, byte_size, session_id, tag_number FROM tags WHERE session_id = ? AND status = 'active' ORDER BY byte_size DESC, tag_number ASC LIMIT ?").all(sessionId, n).filter(isTagRow);
|
|
16518
|
+
return rows.map(toTagEntry);
|
|
16512
16519
|
}
|
|
16513
|
-
|
|
16514
|
-
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
16520
|
+
// src/plugin/dream-timer.ts
|
|
16521
|
+
var DREAM_TIMER_INTERVAL_MS = 15 * 60 * 1000;
|
|
16522
|
+
function startDreamScheduleTimer(args) {
|
|
16523
|
+
const { client, dreamerConfig } = args;
|
|
16524
|
+
if (!dreamerConfig.enabled || !dreamerConfig.schedule?.trim()) {
|
|
16525
|
+
return;
|
|
16526
|
+
}
|
|
16527
|
+
const timer = setInterval(() => {
|
|
16528
|
+
try {
|
|
16529
|
+
const db = openDatabase();
|
|
16530
|
+
checkScheduleAndEnqueue(db, dreamerConfig.schedule);
|
|
16531
|
+
processDreamQueue({
|
|
16532
|
+
db,
|
|
16533
|
+
client,
|
|
16534
|
+
tasks: dreamerConfig.tasks,
|
|
16535
|
+
taskTimeoutMinutes: dreamerConfig.task_timeout_minutes,
|
|
16536
|
+
maxRuntimeMinutes: dreamerConfig.max_runtime_minutes
|
|
16537
|
+
}).catch((error48) => {
|
|
16538
|
+
log("[dreamer] timer-triggered queue processing failed:", error48);
|
|
16539
|
+
});
|
|
16540
|
+
} catch (error48) {
|
|
16541
|
+
log("[dreamer] timer-triggered schedule check failed:", error48);
|
|
16542
|
+
}
|
|
16543
|
+
}, DREAM_TIMER_INTERVAL_MS);
|
|
16544
|
+
if (typeof timer === "object" && "unref" in timer) {
|
|
16545
|
+
timer.unref();
|
|
16546
|
+
}
|
|
16547
|
+
log(`[dreamer] started independent schedule timer (every ${DREAM_TIMER_INTERVAL_MS / 60000}m)`);
|
|
16548
|
+
return () => {
|
|
16549
|
+
clearInterval(timer);
|
|
16550
|
+
log("[dreamer] stopped dream schedule timer");
|
|
16551
|
+
};
|
|
16519
16552
|
}
|
|
16520
|
-
|
|
16521
|
-
|
|
16553
|
+
|
|
16554
|
+
// src/plugin/event.ts
|
|
16555
|
+
function createEventHandler(args) {
|
|
16556
|
+
return async (input) => {
|
|
16557
|
+
await args.magicContext?.event?.(input);
|
|
16558
|
+
};
|
|
16522
16559
|
}
|
|
16523
|
-
|
|
16524
|
-
|
|
16525
|
-
|
|
16560
|
+
|
|
16561
|
+
// src/features/magic-context/compaction.ts
|
|
16562
|
+
function createCompactionHandler() {
|
|
16563
|
+
return {
|
|
16564
|
+
onCompacted(sessionId, db) {
|
|
16565
|
+
db.transaction(() => {
|
|
16566
|
+
db.prepare("UPDATE tags SET status = 'compacted' WHERE session_id = ? AND status IN ('active', 'dropped')").run(sessionId);
|
|
16567
|
+
db.prepare("DELETE FROM pending_ops WHERE session_id = ?").run(sessionId);
|
|
16568
|
+
updateSessionMeta(db, sessionId, { lastNudgeBand: null });
|
|
16569
|
+
})();
|
|
16570
|
+
}
|
|
16571
|
+
};
|
|
16526
16572
|
}
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
return candidate.type === "thinking" || candidate.type === "reasoning";
|
|
16573
|
+
|
|
16574
|
+
// src/hooks/is-anthropic-provider.ts
|
|
16575
|
+
function isAnthropicProvider(providerID) {
|
|
16576
|
+
return providerID === "anthropic" || providerID === "google-vertex-anthropic";
|
|
16532
16577
|
}
|
|
16533
16578
|
|
|
16534
|
-
// src/hooks/magic-context/
|
|
16535
|
-
|
|
16536
|
-
|
|
16537
|
-
|
|
16538
|
-
|
|
16539
|
-
|
|
16579
|
+
// src/hooks/magic-context/event-resolvers.ts
|
|
16580
|
+
var DEFAULT_CONTEXT_LIMIT = 200000;
|
|
16581
|
+
function resolveContextLimit(providerID, modelID, config2) {
|
|
16582
|
+
if (!providerID) {
|
|
16583
|
+
return DEFAULT_CONTEXT_LIMIT;
|
|
16584
|
+
}
|
|
16585
|
+
if (modelID) {
|
|
16586
|
+
const modelSpecific = config2.modelContextLimitsCache?.get(`${providerID}/${modelID}`);
|
|
16587
|
+
if (typeof modelSpecific === "number" && modelSpecific > 0) {
|
|
16588
|
+
return modelSpecific;
|
|
16589
|
+
}
|
|
16590
|
+
}
|
|
16591
|
+
if (isAnthropicProvider(providerID)) {
|
|
16592
|
+
return 1e6;
|
|
16593
|
+
}
|
|
16594
|
+
return DEFAULT_CONTEXT_LIMIT;
|
|
16540
16595
|
}
|
|
16541
|
-
function
|
|
16542
|
-
if (
|
|
16543
|
-
return
|
|
16544
|
-
|
|
16545
|
-
if (
|
|
16546
|
-
return
|
|
16547
|
-
|
|
16548
|
-
|
|
16549
|
-
|
|
16596
|
+
function resolveCacheTtl(cacheTtl, modelKey) {
|
|
16597
|
+
if (typeof cacheTtl === "string") {
|
|
16598
|
+
return cacheTtl;
|
|
16599
|
+
}
|
|
16600
|
+
if (modelKey && typeof cacheTtl[modelKey] === "string") {
|
|
16601
|
+
return cacheTtl[modelKey];
|
|
16602
|
+
}
|
|
16603
|
+
if (modelKey) {
|
|
16604
|
+
const bareModelId = modelKey.split("/").slice(1).join("/");
|
|
16605
|
+
if (bareModelId && typeof cacheTtl[bareModelId] === "string") {
|
|
16606
|
+
return cacheTtl[bareModelId];
|
|
16607
|
+
}
|
|
16608
|
+
}
|
|
16609
|
+
return cacheTtl.default ?? "5m";
|
|
16550
16610
|
}
|
|
16551
|
-
function
|
|
16552
|
-
if (
|
|
16553
|
-
return
|
|
16554
|
-
|
|
16555
|
-
|
|
16611
|
+
function resolveExecuteThreshold(config2, modelKey, fallback) {
|
|
16612
|
+
if (typeof config2 === "number") {
|
|
16613
|
+
return config2;
|
|
16614
|
+
}
|
|
16615
|
+
if (modelKey && typeof config2[modelKey] === "number") {
|
|
16616
|
+
return config2[modelKey];
|
|
16617
|
+
}
|
|
16618
|
+
if (modelKey) {
|
|
16619
|
+
const bareModelId = modelKey.split("/").slice(1).join("/");
|
|
16620
|
+
if (bareModelId && typeof config2[bareModelId] === "number") {
|
|
16621
|
+
return config2[bareModelId];
|
|
16622
|
+
}
|
|
16623
|
+
}
|
|
16624
|
+
return config2.default ?? fallback;
|
|
16556
16625
|
}
|
|
16557
|
-
function
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
|
|
16626
|
+
function resolveModelKey(providerID, modelID) {
|
|
16627
|
+
if (!providerID || !modelID) {
|
|
16628
|
+
return;
|
|
16629
|
+
}
|
|
16630
|
+
return `${providerID}/${modelID}`;
|
|
16631
|
+
}
|
|
16632
|
+
function resolveSessionId(properties) {
|
|
16633
|
+
if (typeof properties?.sessionID === "string") {
|
|
16634
|
+
return properties.sessionID;
|
|
16635
|
+
}
|
|
16636
|
+
const info = properties?.info;
|
|
16637
|
+
if (info === null || typeof info !== "object") {
|
|
16638
|
+
return;
|
|
16639
|
+
}
|
|
16640
|
+
const record2 = info;
|
|
16641
|
+
if (typeof record2.sessionID === "string") {
|
|
16642
|
+
return record2.sessionID;
|
|
16643
|
+
}
|
|
16644
|
+
if (typeof record2.id === "string") {
|
|
16645
|
+
return record2.id;
|
|
16646
|
+
}
|
|
16647
|
+
return;
|
|
16561
16648
|
}
|
|
16562
16649
|
|
|
16563
|
-
// src/
|
|
16564
|
-
|
|
16565
|
-
|
|
16650
|
+
// src/features/magic-context/scheduler.ts
|
|
16651
|
+
var TTL_PATTERN = /^(\d+)([smh])$/;
|
|
16652
|
+
var NUMERIC_PATTERN = /^\d+$/;
|
|
16653
|
+
var UNIT_TO_MS = {
|
|
16654
|
+
s: 1000,
|
|
16655
|
+
m: 60 * 1000,
|
|
16656
|
+
h: 60 * 60 * 1000
|
|
16657
|
+
};
|
|
16658
|
+
function parseCacheTtl(ttl) {
|
|
16659
|
+
const normalizedTtl = ttl.trim();
|
|
16660
|
+
if (NUMERIC_PATTERN.test(normalizedTtl)) {
|
|
16661
|
+
return Number(normalizedTtl);
|
|
16662
|
+
}
|
|
16663
|
+
const match = normalizedTtl.match(TTL_PATTERN);
|
|
16664
|
+
if (!match) {
|
|
16665
|
+
throw new Error(`Invalid cache TTL format: ${ttl}`);
|
|
16666
|
+
}
|
|
16667
|
+
const value = Number(match[1]);
|
|
16668
|
+
const unit = match[2];
|
|
16669
|
+
return value * UNIT_TO_MS[unit];
|
|
16566
16670
|
}
|
|
16567
|
-
function
|
|
16568
|
-
return
|
|
16671
|
+
function createScheduler(config2) {
|
|
16672
|
+
return {
|
|
16673
|
+
shouldExecute(sessionMeta, contextUsage, currentTime = Date.now(), sessionId, modelKey) {
|
|
16674
|
+
const threshold = resolveExecuteThreshold(config2.executeThresholdPercentage, modelKey, 65);
|
|
16675
|
+
if (contextUsage.percentage >= threshold) {
|
|
16676
|
+
return "execute";
|
|
16677
|
+
}
|
|
16678
|
+
let ttlMs;
|
|
16679
|
+
try {
|
|
16680
|
+
ttlMs = parseCacheTtl(sessionMeta.cacheTtl);
|
|
16681
|
+
} catch (error48) {
|
|
16682
|
+
if (sessionId) {
|
|
16683
|
+
sessionLog(sessionId, `invalid cache_ttl "${sessionMeta.cacheTtl}"; falling back to default 5m`, error48);
|
|
16684
|
+
} else {
|
|
16685
|
+
log(`[magic-context] invalid cache_ttl "${sessionMeta.cacheTtl}"; falling back to default 5m`, error48);
|
|
16686
|
+
}
|
|
16687
|
+
ttlMs = parseCacheTtl("5m");
|
|
16688
|
+
}
|
|
16689
|
+
const elapsedTime = currentTime - sessionMeta.lastResponseTime;
|
|
16690
|
+
if (elapsedTime > ttlMs) {
|
|
16691
|
+
return "execute";
|
|
16692
|
+
}
|
|
16693
|
+
return "defer";
|
|
16694
|
+
}
|
|
16695
|
+
};
|
|
16569
16696
|
}
|
|
16570
|
-
|
|
16571
|
-
|
|
16697
|
+
|
|
16698
|
+
// src/features/magic-context/tagger.ts
|
|
16699
|
+
var GET_COUNTER_SQL = `SELECT counter FROM session_meta WHERE session_id = ?`;
|
|
16700
|
+
var GET_ASSIGNMENTS_SQL = "SELECT message_id, tag_number FROM tags WHERE session_id = ? ORDER BY tag_number ASC";
|
|
16701
|
+
function isAssignmentRow(row) {
|
|
16702
|
+
if (row === null || typeof row !== "object") {
|
|
16703
|
+
return false;
|
|
16704
|
+
}
|
|
16705
|
+
const candidate = row;
|
|
16706
|
+
return typeof candidate.message_id === "string" && typeof candidate.tag_number === "number";
|
|
16572
16707
|
}
|
|
16573
|
-
|
|
16574
|
-
|
|
16575
|
-
|
|
16576
|
-
|
|
16577
|
-
|
|
16578
|
-
|
|
16579
|
-
|
|
16580
|
-
|
|
16581
|
-
|
|
16582
|
-
|
|
16583
|
-
|
|
16584
|
-
|
|
16585
|
-
|
|
16586
|
-
|
|
16587
|
-
|
|
16588
|
-
|
|
16589
|
-
|
|
16708
|
+
var UPSERT_COUNTER_SQL = `
|
|
16709
|
+
INSERT INTO session_meta (session_id, counter)
|
|
16710
|
+
VALUES (?, ?)
|
|
16711
|
+
ON CONFLICT(session_id) DO UPDATE SET counter = excluded.counter
|
|
16712
|
+
`;
|
|
16713
|
+
var upsertCounterStatements = new WeakMap;
|
|
16714
|
+
function getUpsertCounterStatement(db) {
|
|
16715
|
+
let stmt = upsertCounterStatements.get(db);
|
|
16716
|
+
if (!stmt) {
|
|
16717
|
+
stmt = db.prepare(UPSERT_COUNTER_SQL);
|
|
16718
|
+
upsertCounterStatements.set(db, stmt);
|
|
16719
|
+
}
|
|
16720
|
+
return stmt;
|
|
16721
|
+
}
|
|
16722
|
+
function createTagger() {
|
|
16723
|
+
const counters = new Map;
|
|
16724
|
+
const assignments = new Map;
|
|
16725
|
+
function getSessionAssignments(sessionId) {
|
|
16726
|
+
let map2 = assignments.get(sessionId);
|
|
16727
|
+
if (!map2) {
|
|
16728
|
+
map2 = new Map;
|
|
16729
|
+
assignments.set(sessionId, map2);
|
|
16730
|
+
}
|
|
16731
|
+
return map2;
|
|
16732
|
+
}
|
|
16733
|
+
function assignTag(sessionId, messageId, type, byteSize2, db) {
|
|
16734
|
+
const sessionAssignments = getSessionAssignments(sessionId);
|
|
16735
|
+
const existing = sessionAssignments.get(messageId);
|
|
16736
|
+
if (existing !== undefined) {
|
|
16737
|
+
return existing;
|
|
16738
|
+
}
|
|
16739
|
+
const current = counters.get(sessionId) ?? 0;
|
|
16740
|
+
const next = current + 1;
|
|
16741
|
+
db.transaction(() => {
|
|
16742
|
+
insertTag(db, sessionId, messageId, type, byteSize2, next);
|
|
16743
|
+
getUpsertCounterStatement(db).run(sessionId, next);
|
|
16744
|
+
})();
|
|
16745
|
+
counters.set(sessionId, next);
|
|
16746
|
+
sessionAssignments.set(messageId, next);
|
|
16747
|
+
return next;
|
|
16748
|
+
}
|
|
16749
|
+
function getTag(sessionId, messageId) {
|
|
16750
|
+
return assignments.get(sessionId)?.get(messageId);
|
|
16751
|
+
}
|
|
16752
|
+
function bindTag(sessionId, messageId, tagNumber) {
|
|
16753
|
+
getSessionAssignments(sessionId).set(messageId, tagNumber);
|
|
16754
|
+
}
|
|
16755
|
+
function getAssignments(sessionId) {
|
|
16756
|
+
return getSessionAssignments(sessionId);
|
|
16757
|
+
}
|
|
16758
|
+
function resetCounter(sessionId, db) {
|
|
16759
|
+
counters.set(sessionId, 0);
|
|
16760
|
+
assignments.delete(sessionId);
|
|
16761
|
+
getUpsertCounterStatement(db).run(sessionId, 0);
|
|
16762
|
+
}
|
|
16763
|
+
function getCounter(sessionId) {
|
|
16764
|
+
return counters.get(sessionId) ?? 0;
|
|
16765
|
+
}
|
|
16766
|
+
function initFromDb(sessionId, db) {
|
|
16767
|
+
if (counters.has(sessionId)) {
|
|
16768
|
+
return;
|
|
16769
|
+
}
|
|
16770
|
+
const row = db.prepare(GET_COUNTER_SQL).get(sessionId);
|
|
16771
|
+
const assignmentRows = db.prepare(GET_ASSIGNMENTS_SQL).all(sessionId).filter(isAssignmentRow);
|
|
16772
|
+
const sessionAssignments = getSessionAssignments(sessionId);
|
|
16773
|
+
sessionAssignments.clear();
|
|
16774
|
+
let maxTagNumber = 0;
|
|
16775
|
+
for (const assignment of assignmentRows) {
|
|
16776
|
+
sessionAssignments.set(assignment.message_id, assignment.tag_number);
|
|
16777
|
+
if (assignment.tag_number > maxTagNumber) {
|
|
16778
|
+
maxTagNumber = assignment.tag_number;
|
|
16590
16779
|
}
|
|
16591
16780
|
}
|
|
16592
|
-
|
|
16593
|
-
|
|
16781
|
+
const counter = Math.max(row?.counter ?? 0, maxTagNumber);
|
|
16782
|
+
counters.set(sessionId, counter);
|
|
16783
|
+
}
|
|
16784
|
+
function cleanup(sessionId) {
|
|
16785
|
+
counters.delete(sessionId);
|
|
16786
|
+
assignments.delete(sessionId);
|
|
16787
|
+
}
|
|
16788
|
+
return {
|
|
16789
|
+
assignTag,
|
|
16790
|
+
getTag,
|
|
16791
|
+
bindTag,
|
|
16792
|
+
getAssignments,
|
|
16793
|
+
resetCounter,
|
|
16794
|
+
getCounter,
|
|
16795
|
+
initFromDb,
|
|
16796
|
+
cleanup
|
|
16797
|
+
};
|
|
16594
16798
|
}
|
|
16595
|
-
|
|
16596
|
-
|
|
16597
|
-
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16601
|
-
|
|
16602
|
-
|
|
16603
|
-
|
|
16604
|
-
|
|
16799
|
+
|
|
16800
|
+
// src/features/magic-context/memory/project-identity.ts
|
|
16801
|
+
import { execSync } from "child_process";
|
|
16802
|
+
import path3 from "path";
|
|
16803
|
+
var GIT_TIMEOUT_MS = 5000;
|
|
16804
|
+
var resolvedCache = new Map;
|
|
16805
|
+
function getRootCommitHash(directory) {
|
|
16806
|
+
try {
|
|
16807
|
+
const hash2 = execSync("git rev-list --max-parents=0 HEAD", {
|
|
16808
|
+
cwd: directory,
|
|
16809
|
+
encoding: "utf-8",
|
|
16810
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
16811
|
+
timeout: GIT_TIMEOUT_MS
|
|
16812
|
+
}).trim();
|
|
16813
|
+
const firstLine = hash2.split(`
|
|
16814
|
+
`)[0]?.trim();
|
|
16815
|
+
return firstLine && firstLine.length >= 7 ? firstLine : undefined;
|
|
16816
|
+
} catch {
|
|
16817
|
+
return;
|
|
16818
|
+
}
|
|
16605
16819
|
}
|
|
16606
|
-
function
|
|
16607
|
-
const
|
|
16608
|
-
const
|
|
16609
|
-
|
|
16610
|
-
|
|
16611
|
-
|
|
16612
|
-
|
|
16613
|
-
|
|
16614
|
-
|
|
16615
|
-
|
|
16616
|
-
let currentBlock = null;
|
|
16617
|
-
let pendingNoiseMeta = [];
|
|
16618
|
-
let commitClusters = 0;
|
|
16619
|
-
let lastFlushedRole = "";
|
|
16620
|
-
function flushCurrentBlock() {
|
|
16621
|
-
if (!currentBlock)
|
|
16622
|
-
return true;
|
|
16623
|
-
const blockText = formatBlock(currentBlock);
|
|
16624
|
-
const blockTokens = estimateTokens(blockText);
|
|
16625
|
-
if (totalTokens + blockTokens > tokenBudget && totalTokens > 0) {
|
|
16626
|
-
return false;
|
|
16627
|
-
}
|
|
16628
|
-
if (currentBlock.role === "A" && currentBlock.commitHashes.length > 0 && lastFlushedRole !== "A") {
|
|
16629
|
-
commitClusters++;
|
|
16630
|
-
}
|
|
16631
|
-
lastFlushedRole = currentBlock.role;
|
|
16632
|
-
if (!firstMessageId)
|
|
16633
|
-
firstMessageId = currentBlock.meta[0]?.messageId ?? "";
|
|
16634
|
-
lastOrdinal = currentBlock.meta[currentBlock.meta.length - 1]?.ordinal ?? currentBlock.endOrdinal;
|
|
16635
|
-
lastMessageId = currentBlock.meta[currentBlock.meta.length - 1]?.messageId ?? "";
|
|
16636
|
-
messagesProcessed += currentBlock.meta.length;
|
|
16637
|
-
lines.push(blockText);
|
|
16638
|
-
lineMeta.push(...currentBlock.meta);
|
|
16639
|
-
totalTokens += blockTokens;
|
|
16640
|
-
currentBlock = null;
|
|
16641
|
-
return true;
|
|
16820
|
+
function directoryFallback(directory) {
|
|
16821
|
+
const canonical = path3.resolve(directory);
|
|
16822
|
+
const hash2 = Bun.hash(canonical).toString(16).slice(0, 12);
|
|
16823
|
+
return `dir:${hash2}`;
|
|
16824
|
+
}
|
|
16825
|
+
function resolveProjectIdentity(directory) {
|
|
16826
|
+
const resolved = path3.resolve(directory);
|
|
16827
|
+
const cached2 = resolvedCache.get(resolved);
|
|
16828
|
+
if (cached2 !== undefined) {
|
|
16829
|
+
return cached2;
|
|
16642
16830
|
}
|
|
16643
|
-
|
|
16644
|
-
|
|
16645
|
-
|
|
16646
|
-
|
|
16647
|
-
|
|
16648
|
-
|
|
16649
|
-
|
|
16650
|
-
|
|
16651
|
-
|
|
16652
|
-
|
|
16653
|
-
|
|
16654
|
-
|
|
16655
|
-
const text = compacted.text;
|
|
16656
|
-
if (!text) {
|
|
16657
|
-
pendingNoiseMeta.push(meta3);
|
|
16658
|
-
continue;
|
|
16831
|
+
const rootHash = getRootCommitHash(resolved);
|
|
16832
|
+
const identity = rootHash ? `git:${rootHash}` : directoryFallback(resolved);
|
|
16833
|
+
resolvedCache.set(resolved, identity);
|
|
16834
|
+
return identity;
|
|
16835
|
+
}
|
|
16836
|
+
|
|
16837
|
+
// src/hooks/magic-context/execute-flush.ts
|
|
16838
|
+
function executeFlush(db, sessionId) {
|
|
16839
|
+
try {
|
|
16840
|
+
const pendingOps = getPendingOps(db, sessionId);
|
|
16841
|
+
if (pendingOps.length === 0) {
|
|
16842
|
+
return "No pending operations to flush.";
|
|
16659
16843
|
}
|
|
16660
|
-
|
|
16661
|
-
|
|
16662
|
-
|
|
16663
|
-
|
|
16664
|
-
|
|
16665
|
-
|
|
16666
|
-
|
|
16844
|
+
let dropped = 0;
|
|
16845
|
+
db.transaction(() => {
|
|
16846
|
+
for (const op of pendingOps) {
|
|
16847
|
+
updateTagStatus(db, sessionId, op.tagId, "dropped");
|
|
16848
|
+
removePendingOp(db, sessionId, op.tagId);
|
|
16849
|
+
dropped++;
|
|
16850
|
+
}
|
|
16851
|
+
})();
|
|
16852
|
+
const parts = [];
|
|
16853
|
+
if (dropped > 0)
|
|
16854
|
+
parts.push(`${dropped} dropped`);
|
|
16855
|
+
if (dropped > 0) {
|
|
16856
|
+
clearPersistedStickyTurnReminder(db, sessionId);
|
|
16667
16857
|
}
|
|
16668
|
-
|
|
16669
|
-
|
|
16670
|
-
|
|
16671
|
-
|
|
16672
|
-
startOrdinal: pendingNoiseMeta[0]?.ordinal ?? msg.ordinal,
|
|
16673
|
-
endOrdinal: msg.ordinal,
|
|
16674
|
-
parts: [text],
|
|
16675
|
-
meta: [...pendingNoiseMeta, meta3],
|
|
16676
|
-
commitHashes: [...compacted.commitHashes]
|
|
16677
|
-
};
|
|
16678
|
-
pendingNoiseMeta = [];
|
|
16858
|
+
return `Flushed: ${parts.join(", ")}. Changes take effect on next message.`;
|
|
16859
|
+
} catch (error48) {
|
|
16860
|
+
sessionLog(sessionId, "ctx-flush failed:", error48);
|
|
16861
|
+
return `Error: Failed to flush context operations. ${getErrorMessage(error48)}`;
|
|
16679
16862
|
}
|
|
16680
|
-
flushCurrentBlock();
|
|
16681
|
-
return {
|
|
16682
|
-
startIndex: startOrdinal,
|
|
16683
|
-
endIndex: lastOrdinal,
|
|
16684
|
-
startMessageId: firstMessageId,
|
|
16685
|
-
endMessageId: lastMessageId,
|
|
16686
|
-
messageCount: messagesProcessed,
|
|
16687
|
-
tokenEstimate: totalTokens,
|
|
16688
|
-
hasMore: lastOrdinal < (eligibleEndOrdinal !== undefined ? Math.min(eligibleEndOrdinal - 1, messages.length) : messages.length),
|
|
16689
|
-
text: lines.join(`
|
|
16690
|
-
`),
|
|
16691
|
-
lines: lineMeta,
|
|
16692
|
-
commitClusterCount: commitClusters
|
|
16693
|
-
};
|
|
16694
16863
|
}
|
|
16695
16864
|
|
|
16696
16865
|
// src/hooks/magic-context/compartment-trigger.ts
|
|
@@ -16727,29 +16896,31 @@ var TAIL_INFO_DEFAULTS = {
|
|
|
16727
16896
|
commitClusterCount: 0
|
|
16728
16897
|
};
|
|
16729
16898
|
function getUnsummarizedTailInfo(db, sessionId, compartmentTokenBudget) {
|
|
16730
|
-
|
|
16731
|
-
|
|
16732
|
-
|
|
16733
|
-
|
|
16734
|
-
|
|
16735
|
-
|
|
16736
|
-
|
|
16737
|
-
|
|
16899
|
+
return withRawSessionMessageCache(() => {
|
|
16900
|
+
try {
|
|
16901
|
+
const lastCompartmentEnd = getLastCompartmentEndMessage(db, sessionId);
|
|
16902
|
+
const nextStartOrdinal = Math.max(1, lastCompartmentEnd + 1);
|
|
16903
|
+
const rawMessageCount = getRawSessionMessageCount(sessionId);
|
|
16904
|
+
const protectedTailStart = getProtectedTailStartOrdinal(sessionId);
|
|
16905
|
+
const hasEligibleHistory = rawMessageCount >= nextStartOrdinal && nextStartOrdinal < protectedTailStart;
|
|
16906
|
+
if (!hasEligibleHistory) {
|
|
16907
|
+
return { ...TAIL_INFO_DEFAULTS, nextStartOrdinal };
|
|
16908
|
+
}
|
|
16909
|
+
const scanBudget = Math.max(MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE, compartmentTokenBudget * TAIL_SIZE_TRIGGER_MULTIPLIER);
|
|
16910
|
+
const chunk = readSessionChunk(sessionId, scanBudget, nextStartOrdinal, protectedTailStart);
|
|
16911
|
+
const isMeaningful = chunk.hasMore || chunk.tokenEstimate >= MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE || chunk.messageCount >= MIN_PROACTIVE_TAIL_MESSAGE_COUNT;
|
|
16912
|
+
return {
|
|
16913
|
+
nextStartOrdinal,
|
|
16914
|
+
hasNewRawHistory: true,
|
|
16915
|
+
isMeaningful,
|
|
16916
|
+
tokenEstimate: chunk.tokenEstimate,
|
|
16917
|
+
commitClusterCount: chunk.commitClusterCount
|
|
16918
|
+
};
|
|
16919
|
+
} catch (error48) {
|
|
16920
|
+
sessionLog(sessionId, "compartment trigger: raw tail inspection failed:", error48);
|
|
16921
|
+
return TAIL_INFO_DEFAULTS;
|
|
16738
16922
|
}
|
|
16739
|
-
|
|
16740
|
-
const chunk = readSessionChunk(sessionId, scanBudget, nextStartOrdinal, protectedTailStart);
|
|
16741
|
-
const isMeaningful = chunk.hasMore || chunk.tokenEstimate >= MIN_PROACTIVE_TAIL_TOKEN_ESTIMATE || chunk.messageCount >= MIN_PROACTIVE_TAIL_MESSAGE_COUNT;
|
|
16742
|
-
return {
|
|
16743
|
-
nextStartOrdinal,
|
|
16744
|
-
hasNewRawHistory: true,
|
|
16745
|
-
isMeaningful,
|
|
16746
|
-
tokenEstimate: chunk.tokenEstimate,
|
|
16747
|
-
commitClusterCount: chunk.commitClusterCount
|
|
16748
|
-
};
|
|
16749
|
-
} catch (error48) {
|
|
16750
|
-
sessionLog(sessionId, "compartment trigger: raw tail inspection failed:", error48);
|
|
16751
|
-
return TAIL_INFO_DEFAULTS;
|
|
16752
|
-
}
|
|
16923
|
+
});
|
|
16753
16924
|
}
|
|
16754
16925
|
function checkCompartmentTrigger(db, sessionId, sessionMeta, usage, _previousPercentage, executeThresholdPercentage, compartmentTokenBudget = DEFAULT_COMPARTMENT_TOKEN_BUDGET) {
|
|
16755
16926
|
if (sessionMeta.compartmentInProgress) {
|
|
@@ -17334,33 +17505,145 @@ function createEventHandler2(deps) {
|
|
|
17334
17505
|
};
|
|
17335
17506
|
}
|
|
17336
17507
|
|
|
17337
|
-
// src/features/magic-context/memory/constants.ts
|
|
17338
|
-
var PROMOTABLE_CATEGORIES = [
|
|
17339
|
-
"ARCHITECTURE_DECISIONS",
|
|
17340
|
-
"CONSTRAINTS",
|
|
17341
|
-
"CONFIG_DEFAULTS",
|
|
17342
|
-
"NAMING",
|
|
17343
|
-
"USER_PREFERENCES",
|
|
17344
|
-
"USER_DIRECTIVES",
|
|
17345
|
-
"ENVIRONMENT",
|
|
17346
|
-
"WORKFLOW_RULES",
|
|
17347
|
-
"KNOWN_ISSUES"
|
|
17348
|
-
];
|
|
17349
|
-
var CATEGORY_PRIORITY = [
|
|
17350
|
-
"USER_DIRECTIVES",
|
|
17351
|
-
"USER_PREFERENCES",
|
|
17352
|
-
"NAMING",
|
|
17353
|
-
"CONFIG_DEFAULTS",
|
|
17354
|
-
"CONSTRAINTS",
|
|
17355
|
-
"ARCHITECTURE_DECISIONS",
|
|
17356
|
-
"ENVIRONMENT",
|
|
17357
|
-
"WORKFLOW_RULES",
|
|
17358
|
-
"KNOWN_ISSUES"
|
|
17359
|
-
];
|
|
17360
|
-
var CATEGORY_DEFAULT_TTL = {
|
|
17361
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
17362
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
17363
|
-
};
|
|
17508
|
+
// src/features/magic-context/memory/constants.ts
|
|
17509
|
+
var PROMOTABLE_CATEGORIES = [
|
|
17510
|
+
"ARCHITECTURE_DECISIONS",
|
|
17511
|
+
"CONSTRAINTS",
|
|
17512
|
+
"CONFIG_DEFAULTS",
|
|
17513
|
+
"NAMING",
|
|
17514
|
+
"USER_PREFERENCES",
|
|
17515
|
+
"USER_DIRECTIVES",
|
|
17516
|
+
"ENVIRONMENT",
|
|
17517
|
+
"WORKFLOW_RULES",
|
|
17518
|
+
"KNOWN_ISSUES"
|
|
17519
|
+
];
|
|
17520
|
+
var CATEGORY_PRIORITY = [
|
|
17521
|
+
"USER_DIRECTIVES",
|
|
17522
|
+
"USER_PREFERENCES",
|
|
17523
|
+
"NAMING",
|
|
17524
|
+
"CONFIG_DEFAULTS",
|
|
17525
|
+
"CONSTRAINTS",
|
|
17526
|
+
"ARCHITECTURE_DECISIONS",
|
|
17527
|
+
"ENVIRONMENT",
|
|
17528
|
+
"WORKFLOW_RULES",
|
|
17529
|
+
"KNOWN_ISSUES"
|
|
17530
|
+
];
|
|
17531
|
+
var CATEGORY_DEFAULT_TTL = {
|
|
17532
|
+
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
17533
|
+
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
17534
|
+
};
|
|
17535
|
+
|
|
17536
|
+
// src/features/magic-context/memory/storage-memory-embeddings.ts
|
|
17537
|
+
var saveEmbeddingStatements = new WeakMap;
|
|
17538
|
+
var loadAllEmbeddingsStatements = new WeakMap;
|
|
17539
|
+
var deleteEmbeddingStatements = new WeakMap;
|
|
17540
|
+
var getStoredModelIdStatements = new WeakMap;
|
|
17541
|
+
var clearAllEmbeddingsStatements = new WeakMap;
|
|
17542
|
+
function isEmbeddingBlob(value) {
|
|
17543
|
+
return value instanceof Uint8Array || value instanceof ArrayBuffer;
|
|
17544
|
+
}
|
|
17545
|
+
function isEmbeddingRow(row) {
|
|
17546
|
+
if (row === null || typeof row !== "object")
|
|
17547
|
+
return false;
|
|
17548
|
+
const candidate = row;
|
|
17549
|
+
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding);
|
|
17550
|
+
}
|
|
17551
|
+
function toFloat32Array(blob) {
|
|
17552
|
+
if (blob instanceof Uint8Array) {
|
|
17553
|
+
const buffer2 = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
17554
|
+
return new Float32Array(buffer2);
|
|
17555
|
+
}
|
|
17556
|
+
return new Float32Array(blob.slice(0));
|
|
17557
|
+
}
|
|
17558
|
+
function getSaveEmbeddingStatement(db) {
|
|
17559
|
+
let stmt = saveEmbeddingStatements.get(db);
|
|
17560
|
+
if (!stmt) {
|
|
17561
|
+
stmt = db.prepare("INSERT INTO memory_embeddings (memory_id, embedding, model_id) VALUES (?, ?, ?) ON CONFLICT(memory_id) DO UPDATE SET embedding = excluded.embedding, model_id = excluded.model_id");
|
|
17562
|
+
saveEmbeddingStatements.set(db, stmt);
|
|
17563
|
+
}
|
|
17564
|
+
return stmt;
|
|
17565
|
+
}
|
|
17566
|
+
function getLoadAllEmbeddingsStatement(db) {
|
|
17567
|
+
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
17568
|
+
if (!stmt) {
|
|
17569
|
+
stmt = db.prepare("SELECT memory_embeddings.memory_id AS memoryId, memory_embeddings.embedding AS embedding FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? ORDER BY memory_embeddings.memory_id ASC");
|
|
17570
|
+
loadAllEmbeddingsStatements.set(db, stmt);
|
|
17571
|
+
}
|
|
17572
|
+
return stmt;
|
|
17573
|
+
}
|
|
17574
|
+
function getStoredModelIdStatement(db) {
|
|
17575
|
+
let stmt = getStoredModelIdStatements.get(db);
|
|
17576
|
+
if (!stmt) {
|
|
17577
|
+
stmt = db.prepare("SELECT memory_embeddings.model_id AS modelId FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? AND memory_embeddings.model_id IS NOT NULL LIMIT 1");
|
|
17578
|
+
getStoredModelIdStatements.set(db, stmt);
|
|
17579
|
+
}
|
|
17580
|
+
return stmt;
|
|
17581
|
+
}
|
|
17582
|
+
function getClearAllEmbeddingsStatement(db) {
|
|
17583
|
+
let stmt = clearAllEmbeddingsStatements.get(db);
|
|
17584
|
+
if (!stmt) {
|
|
17585
|
+
stmt = db.prepare("DELETE FROM memory_embeddings WHERE memory_id IN (SELECT id FROM memories WHERE project_path = ?)");
|
|
17586
|
+
clearAllEmbeddingsStatements.set(db, stmt);
|
|
17587
|
+
}
|
|
17588
|
+
return stmt;
|
|
17589
|
+
}
|
|
17590
|
+
function saveEmbedding(db, memoryId, embedding, modelId) {
|
|
17591
|
+
const blob = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
17592
|
+
getSaveEmbeddingStatement(db).run(memoryId, blob, modelId);
|
|
17593
|
+
}
|
|
17594
|
+
function loadAllEmbeddings(db, projectPath) {
|
|
17595
|
+
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath).filter(isEmbeddingRow);
|
|
17596
|
+
const embeddings = new Map;
|
|
17597
|
+
for (const row of rows) {
|
|
17598
|
+
embeddings.set(row.memoryId, toFloat32Array(row.embedding));
|
|
17599
|
+
}
|
|
17600
|
+
return embeddings;
|
|
17601
|
+
}
|
|
17602
|
+
function getStoredModelId(db, projectPath) {
|
|
17603
|
+
const row = getStoredModelIdStatement(db).get(projectPath);
|
|
17604
|
+
return typeof row?.modelId === "string" ? row.modelId : null;
|
|
17605
|
+
}
|
|
17606
|
+
function clearEmbeddingsForProject(db, projectPath) {
|
|
17607
|
+
getClearAllEmbeddingsStatement(db).run(projectPath);
|
|
17608
|
+
}
|
|
17609
|
+
|
|
17610
|
+
// src/features/magic-context/memory/embedding-cache.ts
|
|
17611
|
+
var DEFAULT_EMBEDDING_CACHE_TTL_MS = 60000;
|
|
17612
|
+
var projectEmbeddingCache = new Map;
|
|
17613
|
+
var embeddingCacheTtlMs = DEFAULT_EMBEDDING_CACHE_TTL_MS;
|
|
17614
|
+
function getValidCacheEntry(projectPath) {
|
|
17615
|
+
const entry = projectEmbeddingCache.get(projectPath);
|
|
17616
|
+
if (!entry) {
|
|
17617
|
+
return null;
|
|
17618
|
+
}
|
|
17619
|
+
if (entry.expiresAt <= Date.now()) {
|
|
17620
|
+
projectEmbeddingCache.delete(projectPath);
|
|
17621
|
+
return null;
|
|
17622
|
+
}
|
|
17623
|
+
return entry;
|
|
17624
|
+
}
|
|
17625
|
+
function getProjectEmbeddings(db, projectPath) {
|
|
17626
|
+
const cached2 = getValidCacheEntry(projectPath);
|
|
17627
|
+
if (cached2) {
|
|
17628
|
+
return cached2.embeddings;
|
|
17629
|
+
}
|
|
17630
|
+
const embeddings = loadAllEmbeddings(db, projectPath);
|
|
17631
|
+
projectEmbeddingCache.set(projectPath, {
|
|
17632
|
+
embeddings,
|
|
17633
|
+
expiresAt: Date.now() + embeddingCacheTtlMs
|
|
17634
|
+
});
|
|
17635
|
+
return embeddings;
|
|
17636
|
+
}
|
|
17637
|
+
function peekProjectEmbeddings(projectPath) {
|
|
17638
|
+
return getValidCacheEntry(projectPath)?.embeddings ?? null;
|
|
17639
|
+
}
|
|
17640
|
+
function invalidateProject(projectPath) {
|
|
17641
|
+
projectEmbeddingCache.delete(projectPath);
|
|
17642
|
+
}
|
|
17643
|
+
function invalidateMemory(projectPath, memoryId) {
|
|
17644
|
+
const cached2 = getValidCacheEntry(projectPath);
|
|
17645
|
+
cached2?.embeddings.delete(memoryId);
|
|
17646
|
+
}
|
|
17364
17647
|
|
|
17365
17648
|
// src/features/magic-context/memory/normalize-hash.ts
|
|
17366
17649
|
function normalizeMemoryContent(content) {
|
|
@@ -17526,7 +17809,7 @@ function getMemoriesByProjectStatement(db, statuses) {
|
|
|
17526
17809
|
let stmt = statements.get(db);
|
|
17527
17810
|
if (!stmt) {
|
|
17528
17811
|
const placeholders = statuses.map(() => "?").join(", ");
|
|
17529
|
-
stmt = db.prepare(`SELECT ${getMemorySelectColumns()} FROM memories WHERE project_path = ? AND status IN (${placeholders}) ORDER BY category ASC, updated_at DESC, id ASC`);
|
|
17812
|
+
stmt = db.prepare(`SELECT ${getMemorySelectColumns()} FROM memories WHERE project_path = ? AND status IN (${placeholders}) AND (expires_at IS NULL OR expires_at > ?) ORDER BY category ASC, updated_at DESC, id ASC`);
|
|
17530
17813
|
statements.set(db, stmt);
|
|
17531
17814
|
}
|
|
17532
17815
|
return stmt;
|
|
@@ -17596,6 +17879,7 @@ function insertMemory(db, input) {
|
|
|
17596
17879
|
if (!inserted) {
|
|
17597
17880
|
throw new Error("Failed to load inserted memory row");
|
|
17598
17881
|
}
|
|
17882
|
+
invalidateProject(input.projectPath);
|
|
17599
17883
|
return inserted;
|
|
17600
17884
|
}
|
|
17601
17885
|
function getMemoryByHash(db, projectPath, category, normalizedHash) {
|
|
@@ -17609,7 +17893,7 @@ function getMemoriesByProject(db, projectPath, statuses = ["active", "permanent"
|
|
|
17609
17893
|
if (statuses.length === 0) {
|
|
17610
17894
|
return [];
|
|
17611
17895
|
}
|
|
17612
|
-
const rows = getMemoriesByProjectStatement(db, statuses).all(projectPath, ...statuses).filter(isMemoryRow);
|
|
17896
|
+
const rows = getMemoriesByProjectStatement(db, statuses).all(projectPath, ...statuses, Date.now()).filter(isMemoryRow);
|
|
17613
17897
|
return rows.map(toMemory);
|
|
17614
17898
|
}
|
|
17615
17899
|
function getMemoryById(db, id) {
|
|
@@ -17645,6 +17929,7 @@ function mergeMetadataJson(existing, patch) {
|
|
|
17645
17929
|
return JSON.stringify({ ...base, ...patch });
|
|
17646
17930
|
}
|
|
17647
17931
|
function updateMemoryContent(db, id, content, normalizedHash) {
|
|
17932
|
+
const memory = getMemoryById(db, id);
|
|
17648
17933
|
db.transaction(() => {
|
|
17649
17934
|
getUpdateMemoryContentStatement(db).run(content, normalizedHash, Date.now(), id);
|
|
17650
17935
|
let stmt = deleteEmbeddingOnContentUpdateStatements.get(db);
|
|
@@ -17654,6 +17939,9 @@ function updateMemoryContent(db, id, content, normalizedHash) {
|
|
|
17654
17939
|
}
|
|
17655
17940
|
stmt.run(id);
|
|
17656
17941
|
})();
|
|
17942
|
+
if (memory) {
|
|
17943
|
+
invalidateMemory(memory.projectPath, id);
|
|
17944
|
+
}
|
|
17657
17945
|
}
|
|
17658
17946
|
function supersededMemory(db, id, supersededById) {
|
|
17659
17947
|
getSupersededMemoryStatement(db).run(supersededById, Date.now(), id);
|
|
@@ -18335,19 +18623,19 @@ function cosineSimilarity(a, b) {
|
|
|
18335
18623
|
function isArrayLikeNumber(value) {
|
|
18336
18624
|
return typeof value === "object" && value !== null && "length" in value;
|
|
18337
18625
|
}
|
|
18338
|
-
function
|
|
18626
|
+
function toFloat32Array2(values) {
|
|
18339
18627
|
return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
|
|
18340
18628
|
}
|
|
18341
18629
|
function extractBatchEmbeddings(result, expectedCount) {
|
|
18342
18630
|
const { data } = result;
|
|
18343
18631
|
if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
|
|
18344
|
-
return data.map((entry) =>
|
|
18632
|
+
return data.map((entry) => toFloat32Array2(entry));
|
|
18345
18633
|
}
|
|
18346
18634
|
if (!isArrayLikeNumber(data)) {
|
|
18347
18635
|
log("[magic-context] embedding batch returned unexpected data shape");
|
|
18348
18636
|
return Array.from({ length: expectedCount }, () => null);
|
|
18349
18637
|
}
|
|
18350
|
-
const flatData =
|
|
18638
|
+
const flatData = toFloat32Array2(data);
|
|
18351
18639
|
const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
|
|
18352
18640
|
if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
|
|
18353
18641
|
log("[magic-context] embedding batch returned invalid dimensions");
|
|
@@ -18563,7 +18851,8 @@ function resolveModelId(config2) {
|
|
|
18563
18851
|
if (config2.provider === "openai-compatible") {
|
|
18564
18852
|
const endpoint = config2.endpoint.trim();
|
|
18565
18853
|
const model = config2.model.trim();
|
|
18566
|
-
|
|
18854
|
+
const keyHash = config2.api_key ? computeNormalizedHash(config2.api_key) : "nokey";
|
|
18855
|
+
return `openai-compat:${endpoint}:${model}:${keyHash}`;
|
|
18567
18856
|
}
|
|
18568
18857
|
return config2.model.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL;
|
|
18569
18858
|
}
|
|
@@ -18633,80 +18922,6 @@ async function embedBatch(texts) {
|
|
|
18633
18922
|
function getEmbeddingModelId() {
|
|
18634
18923
|
return getOrCreateProvider()?.modelId ?? "off";
|
|
18635
18924
|
}
|
|
18636
|
-
// src/features/magic-context/memory/storage-memory-embeddings.ts
|
|
18637
|
-
var saveEmbeddingStatements = new WeakMap;
|
|
18638
|
-
var loadAllEmbeddingsStatements = new WeakMap;
|
|
18639
|
-
var deleteEmbeddingStatements = new WeakMap;
|
|
18640
|
-
var getStoredModelIdStatements = new WeakMap;
|
|
18641
|
-
var clearAllEmbeddingsStatements = new WeakMap;
|
|
18642
|
-
function isEmbeddingBlob(value) {
|
|
18643
|
-
return value instanceof Uint8Array || value instanceof ArrayBuffer;
|
|
18644
|
-
}
|
|
18645
|
-
function isEmbeddingRow(row) {
|
|
18646
|
-
if (row === null || typeof row !== "object")
|
|
18647
|
-
return false;
|
|
18648
|
-
const candidate = row;
|
|
18649
|
-
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding);
|
|
18650
|
-
}
|
|
18651
|
-
function toFloat32Array2(blob) {
|
|
18652
|
-
if (blob instanceof Uint8Array) {
|
|
18653
|
-
const buffer2 = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
18654
|
-
return new Float32Array(buffer2);
|
|
18655
|
-
}
|
|
18656
|
-
return new Float32Array(blob.slice(0));
|
|
18657
|
-
}
|
|
18658
|
-
function getSaveEmbeddingStatement(db) {
|
|
18659
|
-
let stmt = saveEmbeddingStatements.get(db);
|
|
18660
|
-
if (!stmt) {
|
|
18661
|
-
stmt = db.prepare("INSERT INTO memory_embeddings (memory_id, embedding, model_id) VALUES (?, ?, ?) ON CONFLICT(memory_id) DO UPDATE SET embedding = excluded.embedding, model_id = excluded.model_id");
|
|
18662
|
-
saveEmbeddingStatements.set(db, stmt);
|
|
18663
|
-
}
|
|
18664
|
-
return stmt;
|
|
18665
|
-
}
|
|
18666
|
-
function getLoadAllEmbeddingsStatement(db) {
|
|
18667
|
-
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
18668
|
-
if (!stmt) {
|
|
18669
|
-
stmt = db.prepare("SELECT memory_embeddings.memory_id AS memoryId, memory_embeddings.embedding AS embedding FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? ORDER BY memory_embeddings.memory_id ASC");
|
|
18670
|
-
loadAllEmbeddingsStatements.set(db, stmt);
|
|
18671
|
-
}
|
|
18672
|
-
return stmt;
|
|
18673
|
-
}
|
|
18674
|
-
function getStoredModelIdStatement(db) {
|
|
18675
|
-
let stmt = getStoredModelIdStatements.get(db);
|
|
18676
|
-
if (!stmt) {
|
|
18677
|
-
stmt = db.prepare("SELECT memory_embeddings.model_id AS modelId FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? AND memory_embeddings.model_id IS NOT NULL LIMIT 1");
|
|
18678
|
-
getStoredModelIdStatements.set(db, stmt);
|
|
18679
|
-
}
|
|
18680
|
-
return stmt;
|
|
18681
|
-
}
|
|
18682
|
-
function getClearAllEmbeddingsStatement(db) {
|
|
18683
|
-
let stmt = clearAllEmbeddingsStatements.get(db);
|
|
18684
|
-
if (!stmt) {
|
|
18685
|
-
stmt = db.prepare("DELETE FROM memory_embeddings WHERE memory_id IN (SELECT id FROM memories WHERE project_path = ?)");
|
|
18686
|
-
clearAllEmbeddingsStatements.set(db, stmt);
|
|
18687
|
-
}
|
|
18688
|
-
return stmt;
|
|
18689
|
-
}
|
|
18690
|
-
function saveEmbedding(db, memoryId, embedding, modelId) {
|
|
18691
|
-
const blob = Buffer.from(embedding.buffer, embedding.byteOffset, embedding.byteLength);
|
|
18692
|
-
getSaveEmbeddingStatement(db).run(memoryId, blob, modelId);
|
|
18693
|
-
}
|
|
18694
|
-
function loadAllEmbeddings(db, projectPath) {
|
|
18695
|
-
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath).filter(isEmbeddingRow);
|
|
18696
|
-
const embeddings = new Map;
|
|
18697
|
-
for (const row of rows) {
|
|
18698
|
-
embeddings.set(row.memoryId, toFloat32Array2(row.embedding));
|
|
18699
|
-
}
|
|
18700
|
-
return embeddings;
|
|
18701
|
-
}
|
|
18702
|
-
function getStoredModelId(db, projectPath) {
|
|
18703
|
-
const row = getStoredModelIdStatement(db).get(projectPath);
|
|
18704
|
-
return typeof row?.modelId === "string" ? row.modelId : null;
|
|
18705
|
-
}
|
|
18706
|
-
function clearEmbeddingsForProject(db, projectPath) {
|
|
18707
|
-
getClearAllEmbeddingsStatement(db).run(projectPath);
|
|
18708
|
-
}
|
|
18709
|
-
|
|
18710
18925
|
// src/features/magic-context/memory/embedding-backfill.ts
|
|
18711
18926
|
async function ensureMemoryEmbeddings(args) {
|
|
18712
18927
|
if (!isEmbeddingEnabled()) {
|
|
@@ -18790,7 +19005,7 @@ function getSearchStatement(db) {
|
|
|
18790
19005
|
let stmt = searchStatements.get(db);
|
|
18791
19006
|
if (!stmt) {
|
|
18792
19007
|
const selectColumns = Object.entries(COLUMN_MAP).map(([property, column]) => `memories.${column} AS ${property}`).join(", ");
|
|
18793
|
-
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_fts MATCH ? ORDER BY bm25(memories_fts), memories.updated_at DESC, memories.id ASC LIMIT ?`);
|
|
19008
|
+
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 ?`);
|
|
18794
19009
|
searchStatements.set(db, stmt);
|
|
18795
19010
|
}
|
|
18796
19011
|
return stmt;
|
|
@@ -18810,7 +19025,7 @@ function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT)
|
|
|
18810
19025
|
if (sanitized.length === 0) {
|
|
18811
19026
|
return [];
|
|
18812
19027
|
}
|
|
18813
|
-
const rows = getSearchStatement(db).all(projectPath, sanitized, limit).filter(isMemoryRow);
|
|
19028
|
+
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
18814
19029
|
return rows.map((row) => ({ ...row }));
|
|
18815
19030
|
}
|
|
18816
19031
|
// src/hooks/magic-context/compartment-parser.ts
|
|
@@ -19885,9 +20100,9 @@ function loadContextUsage(contextUsageMap, db, sessionId) {
|
|
|
19885
20100
|
}
|
|
19886
20101
|
return contextUsageEntry?.usage ?? { percentage: 0, inputTokens: 0 };
|
|
19887
20102
|
}
|
|
19888
|
-
function resolveSchedulerDecision(scheduler2, sessionMeta, contextUsage, sessionId) {
|
|
20103
|
+
function resolveSchedulerDecision(scheduler2, sessionMeta, contextUsage, sessionId, modelKey) {
|
|
19889
20104
|
try {
|
|
19890
|
-
const schedulerDecision = scheduler2.shouldExecute(sessionMeta, contextUsage, undefined, sessionId);
|
|
20105
|
+
const schedulerDecision = scheduler2.shouldExecute(sessionMeta, contextUsage, undefined, sessionId, modelKey);
|
|
19891
20106
|
sessionLog(sessionId, `transform scheduler: percentage=${contextUsage.percentage.toFixed(1)}% inputTokens=${contextUsage.inputTokens} cacheTtl=${sessionMeta.cacheTtl} lastResponseTime=${sessionMeta.lastResponseTime} decision=${schedulerDecision}`);
|
|
19892
20107
|
return schedulerDecision;
|
|
19893
20108
|
} catch (error48) {
|
|
@@ -20129,9 +20344,17 @@ function createScopedAssignments(assignments) {
|
|
|
20129
20344
|
return scoped;
|
|
20130
20345
|
}
|
|
20131
20346
|
function createExistingTagResolver(sessionId, tagger, db) {
|
|
20132
|
-
const assignments =
|
|
20133
|
-
|
|
20347
|
+
const assignments = tagger.getAssignments(sessionId);
|
|
20348
|
+
let cachedAssignmentSize = -1;
|
|
20349
|
+
let cachedScopedAssignments = null;
|
|
20134
20350
|
const usedTagNumbers = new Set;
|
|
20351
|
+
function getScopedAssignments() {
|
|
20352
|
+
if (!cachedScopedAssignments || cachedAssignmentSize !== assignments.size) {
|
|
20353
|
+
cachedScopedAssignments = createScopedAssignments(assignments);
|
|
20354
|
+
cachedAssignmentSize = assignments.size;
|
|
20355
|
+
}
|
|
20356
|
+
return cachedScopedAssignments;
|
|
20357
|
+
}
|
|
20135
20358
|
return {
|
|
20136
20359
|
resolve(messageId, type, currentContentId, ordinal) {
|
|
20137
20360
|
const exactTagId = assignments.get(currentContentId);
|
|
@@ -20139,13 +20362,12 @@ function createExistingTagResolver(sessionId, tagger, db) {
|
|
|
20139
20362
|
usedTagNumbers.add(exactTagId);
|
|
20140
20363
|
return exactTagId;
|
|
20141
20364
|
}
|
|
20142
|
-
const fallback =
|
|
20365
|
+
const fallback = getScopedAssignments().get(messageId)?.[type][ordinal];
|
|
20143
20366
|
if (!fallback || usedTagNumbers.has(fallback.tagNumber)) {
|
|
20144
20367
|
return;
|
|
20145
20368
|
}
|
|
20146
20369
|
updateTagMessageId(db, sessionId, fallback.tagNumber, currentContentId);
|
|
20147
20370
|
tagger.bindTag(sessionId, currentContentId, fallback.tagNumber);
|
|
20148
|
-
assignments.set(currentContentId, fallback.tagNumber);
|
|
20149
20371
|
usedTagNumbers.add(fallback.tagNumber);
|
|
20150
20372
|
return fallback.tagNumber;
|
|
20151
20373
|
}
|
|
@@ -21027,7 +21249,7 @@ function createTransform(deps) {
|
|
|
21027
21249
|
const compartmentDirectory = deps.directory ?? "";
|
|
21028
21250
|
const canRunCompartments = fullFeatureMode && deps.client !== undefined && compartmentDirectory.length > 0;
|
|
21029
21251
|
const contextUsageEarly = loadContextUsage(deps.contextUsageMap, db, sessionId);
|
|
21030
|
-
const schedulerDecisionEarly = resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId);
|
|
21252
|
+
const schedulerDecisionEarly = resolveSchedulerDecision(deps.scheduler, sessionMeta, contextUsageEarly, sessionId, deps.getModelKey?.(sessionId));
|
|
21031
21253
|
const isCacheBusting = deps.flushedSessions.has(sessionId) || schedulerDecisionEarly === "execute";
|
|
21032
21254
|
let pendingCompartmentInjection = null;
|
|
21033
21255
|
if (fullFeatureMode) {
|
|
@@ -21572,7 +21794,11 @@ function createMagicContextHook(deps) {
|
|
|
21572
21794
|
compartmentTokenBudget: deps.config.compartment_token_budget ?? DEFAULT_COMPARTMENT_TOKEN_BUDGET,
|
|
21573
21795
|
historyBudgetPercentage: deps.config.history_budget_percentage,
|
|
21574
21796
|
historianTimeoutMs: deps.config.historian_timeout_ms ?? DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
21575
|
-
getNotificationParams: (sessionId) => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession)
|
|
21797
|
+
getNotificationParams: (sessionId) => getLiveNotificationParams(sessionId, liveModelBySession, variantBySession),
|
|
21798
|
+
getModelKey: (sessionId) => {
|
|
21799
|
+
const model = liveModelBySession.get(sessionId);
|
|
21800
|
+
return resolveModelKey(model?.providerID, model?.modelID);
|
|
21801
|
+
}
|
|
21576
21802
|
});
|
|
21577
21803
|
const eventHandler = createEventHandler2({
|
|
21578
21804
|
contextUsageMap,
|
|
@@ -22212,8 +22438,7 @@ function createCtxReduceTool(deps) {
|
|
|
22212
22438
|
}
|
|
22213
22439
|
let dropIds = [];
|
|
22214
22440
|
try {
|
|
22215
|
-
|
|
22216
|
-
dropIds = parseRangeString(args.drop);
|
|
22441
|
+
dropIds = parseRangeString(args.drop);
|
|
22217
22442
|
} catch (e) {
|
|
22218
22443
|
return `Error: Invalid range syntax. ${e.message}`;
|
|
22219
22444
|
}
|
|
@@ -22285,107 +22510,9 @@ var DEFAULT_CTX_SEARCH_LIMIT = 10;
|
|
|
22285
22510
|
// src/tools/ctx-search/tools.ts
|
|
22286
22511
|
import { tool as tool5 } from "@opencode-ai/plugin";
|
|
22287
22512
|
|
|
22288
|
-
// src/features/magic-context/message-index.ts
|
|
22289
|
-
var lastIndexedStatements = new WeakMap;
|
|
22290
|
-
var insertMessageStatements = new WeakMap;
|
|
22291
|
-
var upsertIndexStatements = new WeakMap;
|
|
22292
|
-
var deleteFtsStatements = new WeakMap;
|
|
22293
|
-
var deleteIndexStatements = new WeakMap;
|
|
22294
|
-
function normalizeIndexText(text) {
|
|
22295
|
-
return text.replace(/\s+/g, " ").trim();
|
|
22296
|
-
}
|
|
22297
|
-
function getLastIndexedStatement(db) {
|
|
22298
|
-
let stmt = lastIndexedStatements.get(db);
|
|
22299
|
-
if (!stmt) {
|
|
22300
|
-
stmt = db.prepare("SELECT last_indexed_ordinal FROM message_history_index WHERE session_id = ?");
|
|
22301
|
-
lastIndexedStatements.set(db, stmt);
|
|
22302
|
-
}
|
|
22303
|
-
return stmt;
|
|
22304
|
-
}
|
|
22305
|
-
function getInsertMessageStatement(db) {
|
|
22306
|
-
let stmt = insertMessageStatements.get(db);
|
|
22307
|
-
if (!stmt) {
|
|
22308
|
-
stmt = db.prepare("INSERT INTO message_history_fts (session_id, message_ordinal, message_id, role, content) VALUES (?, ?, ?, ?, ?)");
|
|
22309
|
-
insertMessageStatements.set(db, stmt);
|
|
22310
|
-
}
|
|
22311
|
-
return stmt;
|
|
22312
|
-
}
|
|
22313
|
-
function getUpsertIndexStatement(db) {
|
|
22314
|
-
let stmt = upsertIndexStatements.get(db);
|
|
22315
|
-
if (!stmt) {
|
|
22316
|
-
stmt = db.prepare("INSERT INTO message_history_index (session_id, last_indexed_ordinal, updated_at) VALUES (?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET last_indexed_ordinal = excluded.last_indexed_ordinal, updated_at = excluded.updated_at");
|
|
22317
|
-
upsertIndexStatements.set(db, stmt);
|
|
22318
|
-
}
|
|
22319
|
-
return stmt;
|
|
22320
|
-
}
|
|
22321
|
-
function getDeleteFtsStatement(db) {
|
|
22322
|
-
let stmt = deleteFtsStatements.get(db);
|
|
22323
|
-
if (!stmt) {
|
|
22324
|
-
stmt = db.prepare("DELETE FROM message_history_fts WHERE session_id = ?");
|
|
22325
|
-
deleteFtsStatements.set(db, stmt);
|
|
22326
|
-
}
|
|
22327
|
-
return stmt;
|
|
22328
|
-
}
|
|
22329
|
-
function getDeleteIndexStatement(db) {
|
|
22330
|
-
let stmt = deleteIndexStatements.get(db);
|
|
22331
|
-
if (!stmt) {
|
|
22332
|
-
stmt = db.prepare("DELETE FROM message_history_index WHERE session_id = ?");
|
|
22333
|
-
deleteIndexStatements.set(db, stmt);
|
|
22334
|
-
}
|
|
22335
|
-
return stmt;
|
|
22336
|
-
}
|
|
22337
|
-
function getLastIndexedOrdinal(db, sessionId) {
|
|
22338
|
-
const row = getLastIndexedStatement(db).get(sessionId);
|
|
22339
|
-
return typeof row?.last_indexed_ordinal === "number" ? row.last_indexed_ordinal : 0;
|
|
22340
|
-
}
|
|
22341
|
-
function clearIndexedMessages(db, sessionId) {
|
|
22342
|
-
getDeleteFtsStatement(db).run(sessionId);
|
|
22343
|
-
getDeleteIndexStatement(db).run(sessionId);
|
|
22344
|
-
}
|
|
22345
|
-
function getIndexableContent(role, parts) {
|
|
22346
|
-
if (role === "user") {
|
|
22347
|
-
if (!hasMeaningfulUserText(parts)) {
|
|
22348
|
-
return "";
|
|
22349
|
-
}
|
|
22350
|
-
return extractTexts(parts).map(cleanUserText).map(normalizeIndexText).filter((text) => text.length > 0).join(" / ");
|
|
22351
|
-
}
|
|
22352
|
-
if (role === "assistant") {
|
|
22353
|
-
return extractTexts(parts).map(removeSystemReminders).map(normalizeIndexText).filter((text) => text.length > 0).join(" / ");
|
|
22354
|
-
}
|
|
22355
|
-
return "";
|
|
22356
|
-
}
|
|
22357
|
-
function ensureMessagesIndexed(db, sessionId, readMessages) {
|
|
22358
|
-
const messages = readMessages(sessionId);
|
|
22359
|
-
if (messages.length === 0) {
|
|
22360
|
-
db.transaction(() => clearIndexedMessages(db, sessionId))();
|
|
22361
|
-
return;
|
|
22362
|
-
}
|
|
22363
|
-
let lastIndexedOrdinal = getLastIndexedOrdinal(db, sessionId);
|
|
22364
|
-
if (lastIndexedOrdinal > messages.length) {
|
|
22365
|
-
db.transaction(() => clearIndexedMessages(db, sessionId))();
|
|
22366
|
-
lastIndexedOrdinal = 0;
|
|
22367
|
-
}
|
|
22368
|
-
if (lastIndexedOrdinal >= messages.length) {
|
|
22369
|
-
return;
|
|
22370
|
-
}
|
|
22371
|
-
const messagesToInsert = messages.filter((message) => message.ordinal > lastIndexedOrdinal).filter((message) => message.role === "user" || message.role === "assistant").map((message) => ({
|
|
22372
|
-
ordinal: message.ordinal,
|
|
22373
|
-
id: message.id,
|
|
22374
|
-
role: message.role,
|
|
22375
|
-
content: getIndexableContent(message.role, message.parts)
|
|
22376
|
-
})).filter((message) => message.content.length > 0);
|
|
22377
|
-
const now = Date.now();
|
|
22378
|
-
db.transaction(() => {
|
|
22379
|
-
const insertMessage = getInsertMessageStatement(db);
|
|
22380
|
-
for (const message of messagesToInsert) {
|
|
22381
|
-
insertMessage.run(sessionId, message.ordinal, message.id, message.role, message.content);
|
|
22382
|
-
}
|
|
22383
|
-
getUpsertIndexStatement(db).run(sessionId, messages.length, now);
|
|
22384
|
-
})();
|
|
22385
|
-
}
|
|
22386
|
-
|
|
22387
22513
|
// src/features/magic-context/search.ts
|
|
22388
22514
|
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
22515
|
+
var FTS_SEMANTIC_CANDIDATE_LIMIT = 50;
|
|
22389
22516
|
var SEMANTIC_WEIGHT = 0.7;
|
|
22390
22517
|
var FTS_WEIGHT = 0.3;
|
|
22391
22518
|
var SINGLE_SOURCE_PENALTY = 0.8;
|
|
@@ -22465,10 +22592,11 @@ async function getSemanticScores(args) {
|
|
|
22465
22592
|
if (!queryEmbedding) {
|
|
22466
22593
|
return semanticScores;
|
|
22467
22594
|
}
|
|
22595
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
22468
22596
|
const embeddings = await ensureMemoryEmbeddings({
|
|
22469
22597
|
db: args.db,
|
|
22470
22598
|
memories: args.memories,
|
|
22471
|
-
existingEmbeddings:
|
|
22599
|
+
existingEmbeddings: cachedEmbeddings
|
|
22472
22600
|
});
|
|
22473
22601
|
for (const memory of args.memories) {
|
|
22474
22602
|
const memoryEmbedding = embeddings.get(memory.id);
|
|
@@ -22479,13 +22607,28 @@ async function getSemanticScores(args) {
|
|
|
22479
22607
|
}
|
|
22480
22608
|
return semanticScores;
|
|
22481
22609
|
}
|
|
22482
|
-
function
|
|
22610
|
+
function getFtsMatches(args) {
|
|
22483
22611
|
try {
|
|
22484
|
-
|
|
22485
|
-
return new Map(matches.map((memory, rank) => [memory.id, 1 / (rank + 1)]));
|
|
22612
|
+
return searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
22486
22613
|
} catch {
|
|
22487
|
-
return
|
|
22614
|
+
return [];
|
|
22615
|
+
}
|
|
22616
|
+
}
|
|
22617
|
+
function getFtsScores(matches) {
|
|
22618
|
+
return new Map(matches.map((memory, rank) => [memory.id, 1 / (rank + 1)]));
|
|
22619
|
+
}
|
|
22620
|
+
function selectSemanticCandidates(args) {
|
|
22621
|
+
if (args.ftsMatches.length === 0) {
|
|
22622
|
+
return args.memories;
|
|
22623
|
+
}
|
|
22624
|
+
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
22625
|
+
const cachedEmbeddings = peekProjectEmbeddings(args.projectPath);
|
|
22626
|
+
if (cachedEmbeddings) {
|
|
22627
|
+
for (const memoryId of cachedEmbeddings.keys()) {
|
|
22628
|
+
candidateIds.add(memoryId);
|
|
22629
|
+
}
|
|
22488
22630
|
}
|
|
22631
|
+
return args.memories.filter((memory) => candidateIds.has(memory.id));
|
|
22489
22632
|
}
|
|
22490
22633
|
function mergeMemoryResults(args) {
|
|
22491
22634
|
const memoryById = new Map(args.memories.map((memory) => [memory.id, memory]));
|
|
@@ -22537,16 +22680,27 @@ async function searchMemories(args) {
|
|
|
22537
22680
|
if (memories.length === 0) {
|
|
22538
22681
|
return [];
|
|
22539
22682
|
}
|
|
22540
|
-
const
|
|
22683
|
+
const ftsMatches = getFtsMatches({
|
|
22541
22684
|
db: args.db,
|
|
22542
22685
|
projectPath: args.projectPath,
|
|
22543
22686
|
query: args.query,
|
|
22687
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
22688
|
+
});
|
|
22689
|
+
const ftsScores = getFtsScores(ftsMatches);
|
|
22690
|
+
const semanticCandidates = selectSemanticCandidates({
|
|
22544
22691
|
memories,
|
|
22692
|
+
projectPath: args.projectPath,
|
|
22693
|
+
ftsMatches
|
|
22694
|
+
});
|
|
22695
|
+
const semanticScores = await getSemanticScores({
|
|
22696
|
+
db: args.db,
|
|
22697
|
+
projectPath: args.projectPath,
|
|
22698
|
+
query: args.query,
|
|
22699
|
+
memories: semanticCandidates,
|
|
22545
22700
|
embeddingEnabled: args.embeddingEnabled,
|
|
22546
22701
|
embedQuery: args.embedQuery,
|
|
22547
22702
|
isEmbeddingRuntimeEnabled: args.isEmbeddingRuntimeEnabled
|
|
22548
22703
|
});
|
|
22549
|
-
const ftsScores = getFtsScores(args);
|
|
22550
22704
|
return mergeMemoryResults({
|
|
22551
22705
|
memories,
|
|
22552
22706
|
semanticScores,
|