@cortexkit/pi-magic-context 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2222 -287
- package/dist/subagent-entry.js +2071 -409
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -141961,6 +141961,7 @@ var SESSION_META_SELECT_COLUMNS = [
|
|
|
141961
141961
|
"cached_m0_bytes",
|
|
141962
141962
|
"cached_m1_bytes",
|
|
141963
141963
|
"cached_m0_project_memory_epoch",
|
|
141964
|
+
"cached_m0_workspace_fingerprint",
|
|
141964
141965
|
"cached_m0_project_user_profile_version",
|
|
141965
141966
|
"cached_m0_max_compartment_seq",
|
|
141966
141967
|
"cached_m0_max_memory_id",
|
|
@@ -142008,6 +142009,7 @@ var META_COLUMNS = {
|
|
|
142008
142009
|
cachedM0Bytes: "cached_m0_bytes",
|
|
142009
142010
|
cachedM1Bytes: "cached_m1_bytes",
|
|
142010
142011
|
cachedM0ProjectMemoryEpoch: "cached_m0_project_memory_epoch",
|
|
142012
|
+
cachedM0WorkspaceFingerprint: "cached_m0_workspace_fingerprint",
|
|
142011
142013
|
cachedM0ProjectUserProfileVersion: "cached_m0_project_user_profile_version",
|
|
142012
142014
|
cachedM0MaxCompartmentSeq: "cached_m0_max_compartment_seq",
|
|
142013
142015
|
cachedM0MaxMemoryId: "cached_m0_max_memory_id",
|
|
@@ -142037,6 +142039,7 @@ var NULL_BIND_META_KEYS = new Set([
|
|
|
142037
142039
|
"cachedM0Bytes",
|
|
142038
142040
|
"cachedM1Bytes",
|
|
142039
142041
|
"cachedM0ProjectMemoryEpoch",
|
|
142042
|
+
"cachedM0WorkspaceFingerprint",
|
|
142040
142043
|
"cachedM0ProjectUserProfileVersion",
|
|
142041
142044
|
"cachedM0MaxCompartmentSeq",
|
|
142042
142045
|
"cachedM0MaxMemoryId",
|
|
@@ -142070,7 +142073,7 @@ function isSessionMetaRow(row) {
|
|
|
142070
142073
|
if (row === null || typeof row !== "object")
|
|
142071
142074
|
return false;
|
|
142072
142075
|
const r = row;
|
|
142073
|
-
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
142076
|
+
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isStringOrNull(r.cached_m0_workspace_fingerprint) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
142074
142077
|
}
|
|
142075
142078
|
function getDefaultSessionMeta(sessionId) {
|
|
142076
142079
|
return {
|
|
@@ -142097,6 +142100,7 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
142097
142100
|
cachedM0Bytes: null,
|
|
142098
142101
|
cachedM1Bytes: null,
|
|
142099
142102
|
cachedM0ProjectMemoryEpoch: null,
|
|
142103
|
+
cachedM0WorkspaceFingerprint: null,
|
|
142100
142104
|
cachedM0ProjectUserProfileVersion: null,
|
|
142101
142105
|
cachedM0MaxCompartmentSeq: null,
|
|
142102
142106
|
cachedM0MaxMemoryId: null,
|
|
@@ -142159,6 +142163,7 @@ function toSessionMeta(row) {
|
|
|
142159
142163
|
cachedM0Bytes: toBufferOrNull(row.cached_m0_bytes),
|
|
142160
142164
|
cachedM1Bytes: toBufferOrNull(row.cached_m1_bytes),
|
|
142161
142165
|
cachedM0ProjectMemoryEpoch: numOrNull(row.cached_m0_project_memory_epoch),
|
|
142166
|
+
cachedM0WorkspaceFingerprint: stringOrNull(row.cached_m0_workspace_fingerprint),
|
|
142162
142167
|
cachedM0ProjectUserProfileVersion: numOrNull(row.cached_m0_project_user_profile_version),
|
|
142163
142168
|
cachedM0MaxCompartmentSeq: numOrNull(row.cached_m0_max_compartment_seq),
|
|
142164
142169
|
cachedM0MaxMemoryId: numOrNull(row.cached_m0_max_memory_id),
|
|
@@ -142189,6 +142194,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
142189
142194
|
db.prepare(`UPDATE session_meta SET
|
|
142190
142195
|
cached_m0_bytes = ?,
|
|
142191
142196
|
cached_m0_project_memory_epoch = ?,
|
|
142197
|
+
cached_m0_workspace_fingerprint = ?,
|
|
142192
142198
|
cached_m0_project_user_profile_version = ?,
|
|
142193
142199
|
cached_m0_max_compartment_seq = ?,
|
|
142194
142200
|
cached_m0_max_memory_id = ?,
|
|
@@ -142201,7 +142207,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
142201
142207
|
cached_m0_upgrade_state = ?,
|
|
142202
142208
|
cached_m0_system_hash = ?,
|
|
142203
142209
|
cached_m0_model_key = ?
|
|
142204
|
-
WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.modelKey ?? "", sessionId);
|
|
142210
|
+
WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.workspaceFingerprint ?? null, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.modelKey ?? "", sessionId);
|
|
142205
142211
|
}
|
|
142206
142212
|
function clearCachedM0M1(db, sessionId) {
|
|
142207
142213
|
ensureSessionMetaRow(db, sessionId);
|
|
@@ -142210,6 +142216,7 @@ function clearCachedM0M1(db, sessionId) {
|
|
|
142210
142216
|
["cached_m0_bytes", null],
|
|
142211
142217
|
["cached_m1_bytes", null],
|
|
142212
142218
|
["cached_m0_project_memory_epoch", null],
|
|
142219
|
+
["cached_m0_workspace_fingerprint", null],
|
|
142213
142220
|
["cached_m0_project_user_profile_version", null],
|
|
142214
142221
|
["cached_m0_max_compartment_seq", null],
|
|
142215
142222
|
["cached_m0_max_memory_id", null],
|
|
@@ -142924,7 +142931,7 @@ var databases = new Map;
|
|
|
142924
142931
|
var persistenceByDatabase = new WeakMap;
|
|
142925
142932
|
var persistenceErrorByDatabase = new WeakMap;
|
|
142926
142933
|
var lastSchemaFenceRejection = null;
|
|
142927
|
-
var LATEST_SUPPORTED_VERSION =
|
|
142934
|
+
var LATEST_SUPPORTED_VERSION = 36;
|
|
142928
142935
|
function resolveDatabasePath(dbPathOverride) {
|
|
142929
142936
|
if (dbPathOverride) {
|
|
142930
142937
|
return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
|
|
@@ -143090,6 +143097,35 @@ function initializeDatabase(db) {
|
|
|
143090
143097
|
);
|
|
143091
143098
|
CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
|
|
143092
143099
|
|
|
143100
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
143101
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143102
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
143103
|
+
session_id TEXT NOT NULL,
|
|
143104
|
+
project_path TEXT NOT NULL,
|
|
143105
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
143106
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
143107
|
+
start_ordinal INTEGER NOT NULL,
|
|
143108
|
+
end_ordinal INTEGER NOT NULL,
|
|
143109
|
+
chunk_hash TEXT NOT NULL,
|
|
143110
|
+
model_id TEXT NOT NULL,
|
|
143111
|
+
dims INTEGER NOT NULL,
|
|
143112
|
+
vector BLOB NOT NULL,
|
|
143113
|
+
created_at INTEGER NOT NULL,
|
|
143114
|
+
UNIQUE(compartment_id, window_index)
|
|
143115
|
+
);
|
|
143116
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session ON compartment_chunk_embeddings(session_id);
|
|
143117
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model ON compartment_chunk_embeddings(project_path, model_id);
|
|
143118
|
+
|
|
143119
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
143120
|
+
session_id TEXT NOT NULL,
|
|
143121
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
143122
|
+
project_path TEXT NOT NULL,
|
|
143123
|
+
updated_at INTEGER NOT NULL,
|
|
143124
|
+
PRIMARY KEY(session_id, harness)
|
|
143125
|
+
);
|
|
143126
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
143127
|
+
ON session_projects(project_path);
|
|
143128
|
+
|
|
143093
143129
|
CREATE TABLE IF NOT EXISTS compartment_events (
|
|
143094
143130
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143095
143131
|
session_id TEXT NOT NULL,
|
|
@@ -143275,6 +143311,25 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143275
143311
|
rekeyed_at INTEGER NOT NULL
|
|
143276
143312
|
);
|
|
143277
143313
|
|
|
143314
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
143315
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143316
|
+
name TEXT NOT NULL UNIQUE,
|
|
143317
|
+
created_at INTEGER NOT NULL,
|
|
143318
|
+
updated_at INTEGER NOT NULL,
|
|
143319
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
143320
|
+
);
|
|
143321
|
+
|
|
143322
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
143323
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
143324
|
+
project_path TEXT NOT NULL,
|
|
143325
|
+
display_name TEXT NOT NULL,
|
|
143326
|
+
display_path TEXT NOT NULL,
|
|
143327
|
+
added_at INTEGER NOT NULL,
|
|
143328
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
143329
|
+
);
|
|
143330
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
143331
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
143332
|
+
|
|
143278
143333
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
143279
143334
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143280
143335
|
table_name TEXT NOT NULL,
|
|
@@ -143386,6 +143441,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143386
143441
|
deferred_execute_state TEXT,
|
|
143387
143442
|
cached_m0_bytes BLOB,
|
|
143388
143443
|
cached_m0_project_memory_epoch INTEGER,
|
|
143444
|
+
cached_m0_workspace_fingerprint TEXT,
|
|
143389
143445
|
cached_m0_project_user_profile_version INTEGER,
|
|
143390
143446
|
cached_m0_max_compartment_seq INTEGER,
|
|
143391
143447
|
cached_m0_max_memory_id INTEGER,
|
|
@@ -143544,6 +143600,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143544
143600
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
143545
143601
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
143546
143602
|
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
143603
|
+
ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
|
|
143547
143604
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
143548
143605
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
143549
143606
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -143597,6 +143654,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143597
143654
|
ensureColumn(db, "memories", "importance", "INTEGER");
|
|
143598
143655
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
143599
143656
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
143657
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
143600
143658
|
ensureColumn(db, "session_meta", "cached_m0_project_user_profile_version", "INTEGER");
|
|
143601
143659
|
ensureColumn(db, "session_meta", "cached_m0_max_compartment_seq", "INTEGER");
|
|
143602
143660
|
ensureColumn(db, "session_meta", "cached_m0_max_memory_id", "INTEGER");
|
|
@@ -143628,6 +143686,15 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143628
143686
|
project_user_profile_version INTEGER NOT NULL DEFAULT 0,
|
|
143629
143687
|
updated_at INTEGER NOT NULL DEFAULT 0
|
|
143630
143688
|
);
|
|
143689
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
143690
|
+
session_id TEXT NOT NULL,
|
|
143691
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
143692
|
+
project_path TEXT NOT NULL,
|
|
143693
|
+
updated_at INTEGER NOT NULL,
|
|
143694
|
+
PRIMARY KEY(session_id, harness)
|
|
143695
|
+
);
|
|
143696
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
143697
|
+
ON session_projects(project_path);
|
|
143631
143698
|
CREATE TABLE IF NOT EXISTS m0_mutation_log (
|
|
143632
143699
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143633
143700
|
session_id TEXT NOT NULL,
|
|
@@ -143655,6 +143722,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143655
143722
|
new_project_path TEXT NOT NULL,
|
|
143656
143723
|
rekeyed_at INTEGER NOT NULL
|
|
143657
143724
|
);
|
|
143725
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
143726
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143727
|
+
name TEXT NOT NULL UNIQUE,
|
|
143728
|
+
created_at INTEGER NOT NULL,
|
|
143729
|
+
updated_at INTEGER NOT NULL,
|
|
143730
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
143731
|
+
);
|
|
143732
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
143733
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
143734
|
+
project_path TEXT NOT NULL,
|
|
143735
|
+
display_name TEXT NOT NULL,
|
|
143736
|
+
display_path TEXT NOT NULL,
|
|
143737
|
+
added_at INTEGER NOT NULL,
|
|
143738
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
143739
|
+
);
|
|
143740
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
143741
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
143658
143742
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
143659
143743
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143660
143744
|
table_name TEXT NOT NULL,
|
|
@@ -143676,6 +143760,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143676
143760
|
ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
143677
143761
|
ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
143678
143762
|
ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
143763
|
+
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
143679
143764
|
}
|
|
143680
143765
|
function healAllNullColumns(db) {
|
|
143681
143766
|
healNullTextColumns(db);
|
|
@@ -143714,6 +143799,7 @@ function healNullTextColumns(db) {
|
|
|
143714
143799
|
["system_prompt_hash", ""],
|
|
143715
143800
|
["stripped_placeholder_ids", ""],
|
|
143716
143801
|
["stale_reduce_stripped_ids", ""],
|
|
143802
|
+
["processed_image_stripped_ids", ""],
|
|
143717
143803
|
["memory_block_cache", ""],
|
|
143718
143804
|
["memory_block_ids", ""],
|
|
143719
143805
|
["compaction_marker_state", ""],
|
|
@@ -143758,7 +143844,7 @@ function healNullIntegerColumns(db) {
|
|
|
143758
143844
|
}
|
|
143759
143845
|
}
|
|
143760
143846
|
function ensureColumn(db, table, column, definition) {
|
|
143761
|
-
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_'(),[\]\s]+$/i.test(definition)) {
|
|
143847
|
+
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_"'(),[\]\s]+$/i.test(definition)) {
|
|
143762
143848
|
throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
|
|
143763
143849
|
}
|
|
143764
143850
|
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
@@ -143835,10 +143921,291 @@ function openDatabase(dbPathOrOptions) {
|
|
|
143835
143921
|
}
|
|
143836
143922
|
}
|
|
143837
143923
|
|
|
143924
|
+
// ../plugin/src/features/magic-context/workspaces.ts
|
|
143925
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
143926
|
+
|
|
143927
|
+
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
143928
|
+
var V2_MEMORY_CATEGORIES = [
|
|
143929
|
+
"PROJECT_RULES",
|
|
143930
|
+
"ARCHITECTURE",
|
|
143931
|
+
"CONSTRAINTS",
|
|
143932
|
+
"CONFIG_VALUES",
|
|
143933
|
+
"NAMING"
|
|
143934
|
+
];
|
|
143935
|
+
var PROMOTABLE_CATEGORIES = [
|
|
143936
|
+
"PROJECT_RULES",
|
|
143937
|
+
"ARCHITECTURE",
|
|
143938
|
+
"CONSTRAINTS",
|
|
143939
|
+
"CONFIG_VALUES",
|
|
143940
|
+
"NAMING",
|
|
143941
|
+
"ARCHITECTURE_DECISIONS",
|
|
143942
|
+
"CONFIG_DEFAULTS",
|
|
143943
|
+
"USER_PREFERENCES",
|
|
143944
|
+
"USER_DIRECTIVES",
|
|
143945
|
+
"ENVIRONMENT",
|
|
143946
|
+
"WORKFLOW_RULES",
|
|
143947
|
+
"KNOWN_ISSUES"
|
|
143948
|
+
];
|
|
143949
|
+
var CATEGORY_PRIORITY = [
|
|
143950
|
+
"PROJECT_RULES",
|
|
143951
|
+
"ARCHITECTURE",
|
|
143952
|
+
"CONSTRAINTS",
|
|
143953
|
+
"CONFIG_VALUES",
|
|
143954
|
+
"NAMING",
|
|
143955
|
+
"USER_DIRECTIVES",
|
|
143956
|
+
"USER_PREFERENCES",
|
|
143957
|
+
"CONFIG_DEFAULTS",
|
|
143958
|
+
"ARCHITECTURE_DECISIONS",
|
|
143959
|
+
"ENVIRONMENT",
|
|
143960
|
+
"WORKFLOW_RULES",
|
|
143961
|
+
"KNOWN_ISSUES"
|
|
143962
|
+
];
|
|
143963
|
+
var MEMORY_CATEGORY_ORDER_UNKNOWN = 99;
|
|
143964
|
+
var MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
143965
|
+
acc[category] = index;
|
|
143966
|
+
return acc;
|
|
143967
|
+
}, {});
|
|
143968
|
+
var MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
143969
|
+
var CATEGORY_DEFAULT_TTL = {
|
|
143970
|
+
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
143971
|
+
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
143972
|
+
};
|
|
143973
|
+
// ../plugin/src/features/magic-context/workspaces.ts
|
|
143974
|
+
var VALID_SHARE_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
143975
|
+
function tableExists(db, tableName) {
|
|
143976
|
+
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ? LIMIT 1").get(tableName);
|
|
143977
|
+
return Boolean(row);
|
|
143978
|
+
}
|
|
143979
|
+
function columnExists(db, tableName, columnName) {
|
|
143980
|
+
const rows = db.prepare(`PRAGMA table_info(${tableName})`).all();
|
|
143981
|
+
return rows.some((row) => row.name === columnName);
|
|
143982
|
+
}
|
|
143983
|
+
function uniqueSorted(values) {
|
|
143984
|
+
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
143985
|
+
}
|
|
143986
|
+
function placeholders(values) {
|
|
143987
|
+
return values.map(() => "?").join(", ");
|
|
143988
|
+
}
|
|
143989
|
+
function normalizeShareCategories(raw) {
|
|
143990
|
+
if (raw === null || raw === undefined)
|
|
143991
|
+
return null;
|
|
143992
|
+
if (typeof raw !== "string")
|
|
143993
|
+
return null;
|
|
143994
|
+
let parsed;
|
|
143995
|
+
try {
|
|
143996
|
+
parsed = JSON.parse(raw);
|
|
143997
|
+
} catch {
|
|
143998
|
+
return null;
|
|
143999
|
+
}
|
|
144000
|
+
if (!Array.isArray(parsed))
|
|
144001
|
+
return null;
|
|
144002
|
+
const categories = [];
|
|
144003
|
+
for (const value of parsed) {
|
|
144004
|
+
if (typeof value !== "string" || !VALID_SHARE_CATEGORIES.has(value)) {
|
|
144005
|
+
return null;
|
|
144006
|
+
}
|
|
144007
|
+
if (!categories.includes(value))
|
|
144008
|
+
categories.push(value);
|
|
144009
|
+
}
|
|
144010
|
+
return categories.sort((left, right) => left.localeCompare(right));
|
|
144011
|
+
}
|
|
144012
|
+
function selectWorkspaceShareCategories(db, identities) {
|
|
144013
|
+
const candidates = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
144014
|
+
if (candidates.length === 0 || !tableExists(db, "workspace_members") || !tableExists(db, "workspaces") || !columnExists(db, "workspaces", "share_categories")) {
|
|
144015
|
+
return null;
|
|
144016
|
+
}
|
|
144017
|
+
const row = db.prepare(`SELECT workspace.share_categories AS shareCategories
|
|
144018
|
+
FROM workspace_members AS member
|
|
144019
|
+
JOIN workspaces AS workspace ON workspace.id = member.workspace_id
|
|
144020
|
+
WHERE member.project_path IN (${placeholders(candidates)})
|
|
144021
|
+
ORDER BY workspace.id ASC
|
|
144022
|
+
LIMIT 1`).get(...candidates);
|
|
144023
|
+
return normalizeShareCategories(row?.shareCategories ?? null);
|
|
144024
|
+
}
|
|
144025
|
+
function resolveWorkspaceShareCategories(db, projectIdentity) {
|
|
144026
|
+
return selectWorkspaceShareCategories(db, [projectIdentity]);
|
|
144027
|
+
}
|
|
144028
|
+
function resolveWorkspaceIdentitySet(db, projectIdentity) {
|
|
144029
|
+
if (!tableExists(db, "workspace_members")) {
|
|
144030
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
144031
|
+
}
|
|
144032
|
+
const rows = db.prepare(`SELECT member.project_path AS identity, member.display_name AS displayName
|
|
144033
|
+
FROM workspace_members AS anchor
|
|
144034
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
144035
|
+
WHERE anchor.project_path = ?
|
|
144036
|
+
ORDER BY member.display_name ASC, member.project_path ASC`).all(projectIdentity);
|
|
144037
|
+
if (rows.length === 0) {
|
|
144038
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
144039
|
+
}
|
|
144040
|
+
const namesByIdentity = new Map;
|
|
144041
|
+
const identities = [];
|
|
144042
|
+
for (const row of rows) {
|
|
144043
|
+
if (typeof row.identity !== "string" || row.identity.length === 0)
|
|
144044
|
+
continue;
|
|
144045
|
+
if (identities.includes(row.identity))
|
|
144046
|
+
continue;
|
|
144047
|
+
identities.push(row.identity);
|
|
144048
|
+
if (typeof row.displayName === "string" && row.displayName.length > 0) {
|
|
144049
|
+
namesByIdentity.set(row.identity, row.displayName);
|
|
144050
|
+
}
|
|
144051
|
+
}
|
|
144052
|
+
return identities.length > 0 ? { identities, namesByIdentity } : { identities: [projectIdentity], namesByIdentity: new Map };
|
|
144053
|
+
}
|
|
144054
|
+
function expandWorkspaceIdentitySetWithAliases(db, identities) {
|
|
144055
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
144056
|
+
const expanded = new Set(canonical);
|
|
144057
|
+
const canonicalIdentityByStoredPath = new Map;
|
|
144058
|
+
for (const identity of canonical) {
|
|
144059
|
+
canonicalIdentityByStoredPath.set(identity, identity);
|
|
144060
|
+
}
|
|
144061
|
+
if (canonical.length === 0 || !tableExists(db, "v22_identity_rekey_map")) {
|
|
144062
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
144063
|
+
}
|
|
144064
|
+
const rows = db.prepare(`SELECT old_project_path AS oldProjectPath, new_project_path AS newProjectPath
|
|
144065
|
+
FROM v22_identity_rekey_map
|
|
144066
|
+
WHERE new_project_path IN (${placeholders(canonical)})
|
|
144067
|
+
ORDER BY old_project_path ASC`).all(...canonical);
|
|
144068
|
+
for (const row of rows) {
|
|
144069
|
+
if (typeof row.oldProjectPath !== "string" || typeof row.newProjectPath !== "string") {
|
|
144070
|
+
continue;
|
|
144071
|
+
}
|
|
144072
|
+
if (!canonicalIdentityByStoredPath.has(row.newProjectPath))
|
|
144073
|
+
continue;
|
|
144074
|
+
expanded.add(row.oldProjectPath);
|
|
144075
|
+
canonicalIdentityByStoredPath.set(row.oldProjectPath, row.newProjectPath);
|
|
144076
|
+
}
|
|
144077
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
144078
|
+
}
|
|
144079
|
+
function resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) {
|
|
144080
|
+
const direct = canonicalIdentityByStoredPath.get(storedProjectPath);
|
|
144081
|
+
if (direct)
|
|
144082
|
+
return direct;
|
|
144083
|
+
const normalized = normalizeStoredProjectPath(storedProjectPath);
|
|
144084
|
+
const normalizedDirect = canonicalIdentityByStoredPath.get(normalized);
|
|
144085
|
+
if (normalizedDirect)
|
|
144086
|
+
return normalizedDirect;
|
|
144087
|
+
if (memberIdentities.includes(normalized))
|
|
144088
|
+
return normalized;
|
|
144089
|
+
for (const identity of memberIdentities) {
|
|
144090
|
+
if (storedPathBelongsToIdentity(storedProjectPath, identity)) {
|
|
144091
|
+
return identity;
|
|
144092
|
+
}
|
|
144093
|
+
}
|
|
144094
|
+
return null;
|
|
144095
|
+
}
|
|
144096
|
+
function storedPathBelongsToWorkspace(storedProjectPath, memberIdentities, expandedIdentities, canonicalIdentityByStoredPath) {
|
|
144097
|
+
if (expandedIdentities.includes(storedProjectPath))
|
|
144098
|
+
return true;
|
|
144099
|
+
return resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) !== null;
|
|
144100
|
+
}
|
|
144101
|
+
function sourceNameForMemory(storedProjectPath, ownIdentity, memberIdentities, namesByIdentity, canonicalIdentityByStoredPath) {
|
|
144102
|
+
const canonicalIdentity = resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath);
|
|
144103
|
+
if (!canonicalIdentity || canonicalIdentity === ownIdentity)
|
|
144104
|
+
return;
|
|
144105
|
+
return namesByIdentity.get(canonicalIdentity);
|
|
144106
|
+
}
|
|
144107
|
+
function getEpochMap(db, identities) {
|
|
144108
|
+
if (identities.length === 0)
|
|
144109
|
+
return new Map;
|
|
144110
|
+
const rows = db.prepare(`SELECT project_path AS projectPath, project_memory_epoch AS epoch
|
|
144111
|
+
FROM project_state
|
|
144112
|
+
WHERE project_path IN (${placeholders(identities)})`).all(...identities);
|
|
144113
|
+
const epochs = new Map;
|
|
144114
|
+
for (const row of rows) {
|
|
144115
|
+
if (typeof row.projectPath !== "string" || typeof row.epoch !== "number")
|
|
144116
|
+
continue;
|
|
144117
|
+
epochs.set(row.projectPath, row.epoch);
|
|
144118
|
+
}
|
|
144119
|
+
return epochs;
|
|
144120
|
+
}
|
|
144121
|
+
function computeWorkspaceEpochFingerprint(db, identities) {
|
|
144122
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
144123
|
+
const epochs = getEpochMap(db, canonical);
|
|
144124
|
+
const shareCategories = selectWorkspaceShareCategories(db, canonical);
|
|
144125
|
+
const hash = createHash3("sha256");
|
|
144126
|
+
hash.update("share_categories", "utf8");
|
|
144127
|
+
hash.update("\x00");
|
|
144128
|
+
hash.update(shareCategories === null ? "ALL" : JSON.stringify(shareCategories), "utf8");
|
|
144129
|
+
hash.update(`
|
|
144130
|
+
`);
|
|
144131
|
+
for (const identity of canonical) {
|
|
144132
|
+
hash.update(identity, "utf8");
|
|
144133
|
+
hash.update("\x00");
|
|
144134
|
+
hash.update(String(epochs.get(identity) ?? 0), "utf8");
|
|
144135
|
+
hash.update(`
|
|
144136
|
+
`);
|
|
144137
|
+
}
|
|
144138
|
+
return hash.digest("hex");
|
|
144139
|
+
}
|
|
144140
|
+
function isInTransaction(db) {
|
|
144141
|
+
const candidate = db;
|
|
144142
|
+
return candidate.inTransaction === true || candidate.isTransaction === true;
|
|
144143
|
+
}
|
|
144144
|
+
function workspaceMembersForIdentity(db, identity) {
|
|
144145
|
+
if (!tableExists(db, "workspace_members"))
|
|
144146
|
+
return [identity];
|
|
144147
|
+
const rows = db.prepare(`SELECT member.project_path AS identity
|
|
144148
|
+
FROM workspace_members AS anchor
|
|
144149
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
144150
|
+
WHERE anchor.project_path = ?
|
|
144151
|
+
ORDER BY member.project_path ASC`).all(identity);
|
|
144152
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((value) => value.length > 0);
|
|
144153
|
+
return identities.length > 0 ? uniqueSorted(identities) : [identity];
|
|
144154
|
+
}
|
|
144155
|
+
function bumpEpochRows(db, identities, now) {
|
|
144156
|
+
const stmt = db.prepare(`INSERT INTO project_state
|
|
144157
|
+
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
144158
|
+
VALUES (?, 1, 0, ?)
|
|
144159
|
+
ON CONFLICT(project_path) DO UPDATE SET
|
|
144160
|
+
project_memory_epoch = project_memory_epoch + 1,
|
|
144161
|
+
updated_at = excluded.updated_at`);
|
|
144162
|
+
for (const identity of uniqueSorted(identities)) {
|
|
144163
|
+
stmt.run(identity, now);
|
|
144164
|
+
}
|
|
144165
|
+
}
|
|
144166
|
+
function bumpEpochsForWorkspaceMembers(db, identity, now = Date.now()) {
|
|
144167
|
+
const run = () => bumpEpochRows(db, workspaceMembersForIdentity(db, identity), now);
|
|
144168
|
+
if (isInTransaction(db)) {
|
|
144169
|
+
run();
|
|
144170
|
+
return;
|
|
144171
|
+
}
|
|
144172
|
+
db.exec("BEGIN IMMEDIATE");
|
|
144173
|
+
try {
|
|
144174
|
+
run();
|
|
144175
|
+
db.exec("COMMIT");
|
|
144176
|
+
} catch (error) {
|
|
144177
|
+
try {
|
|
144178
|
+
db.exec("ROLLBACK");
|
|
144179
|
+
} catch {}
|
|
144180
|
+
throw error;
|
|
144181
|
+
}
|
|
144182
|
+
}
|
|
144183
|
+
function bumpEpochsForWorkspaceMemberSet(db, identities, now = Date.now()) {
|
|
144184
|
+
const run = () => bumpEpochRows(db, identities, now);
|
|
144185
|
+
if (isInTransaction(db)) {
|
|
144186
|
+
run();
|
|
144187
|
+
return;
|
|
144188
|
+
}
|
|
144189
|
+
db.exec("BEGIN IMMEDIATE");
|
|
144190
|
+
try {
|
|
144191
|
+
run();
|
|
144192
|
+
db.exec("COMMIT");
|
|
144193
|
+
} catch (error) {
|
|
144194
|
+
try {
|
|
144195
|
+
db.exec("ROLLBACK");
|
|
144196
|
+
} catch {}
|
|
144197
|
+
throw error;
|
|
144198
|
+
}
|
|
144199
|
+
}
|
|
144200
|
+
|
|
143838
144201
|
// ../plugin/src/features/magic-context/migrations.ts
|
|
143839
|
-
function
|
|
144202
|
+
function tableExists2(db, name2) {
|
|
143840
144203
|
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name2));
|
|
143841
144204
|
}
|
|
144205
|
+
function columnExists2(db, table, column) {
|
|
144206
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
144207
|
+
return rows.some((row) => row.name === column);
|
|
144208
|
+
}
|
|
143842
144209
|
var MIGRATIONS = [
|
|
143843
144210
|
{
|
|
143844
144211
|
version: 1,
|
|
@@ -144297,9 +144664,9 @@ var MIGRATIONS = [
|
|
|
144297
144664
|
version: 22,
|
|
144298
144665
|
description: "v2.0 cache architecture schema foundation",
|
|
144299
144666
|
up: (db) => {
|
|
144300
|
-
const hasSessionMetaTable =
|
|
144301
|
-
const hasCompartmentsTable =
|
|
144302
|
-
const hasMemoriesTable =
|
|
144667
|
+
const hasSessionMetaTable = tableExists2(db, "session_meta");
|
|
144668
|
+
const hasCompartmentsTable = tableExists2(db, "compartments");
|
|
144669
|
+
const hasMemoriesTable = tableExists2(db, "memories");
|
|
144303
144670
|
if (hasSessionMetaTable) {
|
|
144304
144671
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
144305
144672
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
@@ -144324,7 +144691,7 @@ var MIGRATIONS = [
|
|
|
144324
144691
|
ensureColumn(db, "compartments", "p1_embedding_model_id", "TEXT");
|
|
144325
144692
|
ensureColumn(db, "compartments", "legacy", "INTEGER NOT NULL DEFAULT 0");
|
|
144326
144693
|
}
|
|
144327
|
-
const hasRecompCompartmentsTable =
|
|
144694
|
+
const hasRecompCompartmentsTable = tableExists2(db, "recomp_compartments");
|
|
144328
144695
|
if (hasRecompCompartmentsTable) {
|
|
144329
144696
|
ensureColumn(db, "recomp_compartments", "p1", "TEXT");
|
|
144330
144697
|
ensureColumn(db, "recomp_compartments", "p2", "TEXT");
|
|
@@ -144635,6 +145002,156 @@ var MIGRATIONS = [
|
|
|
144635
145002
|
db.prepare("UPDATE session_meta SET force_emergency_bypass_used = 0 WHERE force_emergency_bypass_used IS NULL").run();
|
|
144636
145003
|
db.prepare("UPDATE session_meta SET last_usage_context_limit = 0 WHERE last_usage_context_limit IS NULL").run();
|
|
144637
145004
|
}
|
|
145005
|
+
},
|
|
145006
|
+
{
|
|
145007
|
+
version: 33,
|
|
145008
|
+
description: "Compartment chunk embeddings for semantic message-history search",
|
|
145009
|
+
up: (db) => {
|
|
145010
|
+
db.exec(`
|
|
145011
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
145012
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
145013
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
145014
|
+
session_id TEXT NOT NULL,
|
|
145015
|
+
project_path TEXT NOT NULL,
|
|
145016
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
145017
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
145018
|
+
start_ordinal INTEGER NOT NULL,
|
|
145019
|
+
end_ordinal INTEGER NOT NULL,
|
|
145020
|
+
chunk_hash TEXT NOT NULL,
|
|
145021
|
+
model_id TEXT NOT NULL,
|
|
145022
|
+
dims INTEGER NOT NULL,
|
|
145023
|
+
vector BLOB NOT NULL,
|
|
145024
|
+
created_at INTEGER NOT NULL,
|
|
145025
|
+
UNIQUE(compartment_id, window_index)
|
|
145026
|
+
);
|
|
145027
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session
|
|
145028
|
+
ON compartment_chunk_embeddings(session_id);
|
|
145029
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model
|
|
145030
|
+
ON compartment_chunk_embeddings(project_path, model_id);
|
|
145031
|
+
`);
|
|
145032
|
+
}
|
|
145033
|
+
},
|
|
145034
|
+
{
|
|
145035
|
+
version: 34,
|
|
145036
|
+
description: "workspace tables and m[0] workspace fingerprint cache reset",
|
|
145037
|
+
up: (db) => {
|
|
145038
|
+
db.exec(`
|
|
145039
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
145040
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
145041
|
+
name TEXT NOT NULL UNIQUE,
|
|
145042
|
+
created_at INTEGER NOT NULL,
|
|
145043
|
+
updated_at INTEGER NOT NULL
|
|
145044
|
+
);
|
|
145045
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
145046
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
145047
|
+
project_path TEXT NOT NULL,
|
|
145048
|
+
display_name TEXT NOT NULL,
|
|
145049
|
+
display_path TEXT NOT NULL,
|
|
145050
|
+
added_at INTEGER NOT NULL,
|
|
145051
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
145052
|
+
);
|
|
145053
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique
|
|
145054
|
+
ON workspace_members(project_path);
|
|
145055
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name
|
|
145056
|
+
ON workspace_members(workspace_id, display_name);
|
|
145057
|
+
`);
|
|
145058
|
+
const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
|
|
145059
|
+
if (!hasSessionMeta)
|
|
145060
|
+
return;
|
|
145061
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
145062
|
+
const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
|
|
145063
|
+
const clears = [
|
|
145064
|
+
["cached_m0_bytes", null],
|
|
145065
|
+
["cached_m1_bytes", null],
|
|
145066
|
+
["cached_m0_project_memory_epoch", null],
|
|
145067
|
+
["cached_m0_workspace_fingerprint", null],
|
|
145068
|
+
["cached_m0_project_user_profile_version", null],
|
|
145069
|
+
["cached_m0_max_compartment_seq", null],
|
|
145070
|
+
["cached_m0_max_memory_id", null],
|
|
145071
|
+
["cached_m0_max_mutation_id", null],
|
|
145072
|
+
["cached_m0_max_memory_mutation_id", null],
|
|
145073
|
+
["cached_m0_project_docs_hash", null],
|
|
145074
|
+
["cached_m0_materialized_at", null],
|
|
145075
|
+
["cached_m0_session_facts_version", null],
|
|
145076
|
+
["cached_m0_upgrade_state", null],
|
|
145077
|
+
["cached_m0_system_hash", null],
|
|
145078
|
+
["cached_m0_tool_set_hash", null],
|
|
145079
|
+
["cached_m0_model_key", null],
|
|
145080
|
+
["cached_m0_last_baseline_end_message_id", null],
|
|
145081
|
+
["memory_block_cache", ""],
|
|
145082
|
+
["memory_block_ids", ""],
|
|
145083
|
+
["memory_block_count", 0]
|
|
145084
|
+
];
|
|
145085
|
+
const setClauses = [];
|
|
145086
|
+
const values = [];
|
|
145087
|
+
for (const [column, value] of clears) {
|
|
145088
|
+
if (!columns.has(column))
|
|
145089
|
+
continue;
|
|
145090
|
+
setClauses.push(`${column} = ?`);
|
|
145091
|
+
values.push(value);
|
|
145092
|
+
}
|
|
145093
|
+
if (setClauses.length > 0) {
|
|
145094
|
+
db.prepare(`UPDATE session_meta SET ${setClauses.join(", ")}`).run(...values);
|
|
145095
|
+
}
|
|
145096
|
+
}
|
|
145097
|
+
},
|
|
145098
|
+
{
|
|
145099
|
+
version: 35,
|
|
145100
|
+
description: "workspace per-category share defaults and epoch refresh",
|
|
145101
|
+
up: (db) => {
|
|
145102
|
+
db.exec(`
|
|
145103
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
145104
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
145105
|
+
name TEXT NOT NULL UNIQUE,
|
|
145106
|
+
created_at INTEGER NOT NULL,
|
|
145107
|
+
updated_at INTEGER NOT NULL,
|
|
145108
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
145109
|
+
);
|
|
145110
|
+
`);
|
|
145111
|
+
if (!columnExists2(db, "workspaces", "share_categories")) {
|
|
145112
|
+
db.exec(`ALTER TABLE workspaces ADD COLUMN share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
145113
|
+
}
|
|
145114
|
+
db.prepare(`UPDATE workspaces
|
|
145115
|
+
SET share_categories = '["CONSTRAINTS"]'
|
|
145116
|
+
WHERE share_categories IS NULL OR share_categories = ''`).run();
|
|
145117
|
+
if (!tableExists2(db, "workspace_members"))
|
|
145118
|
+
return;
|
|
145119
|
+
const rows = db.prepare(`SELECT DISTINCT project_path AS identity
|
|
145120
|
+
FROM workspace_members
|
|
145121
|
+
WHERE project_path IS NOT NULL AND project_path <> ''
|
|
145122
|
+
ORDER BY project_path ASC`).all();
|
|
145123
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((identity) => identity.length > 0);
|
|
145124
|
+
if (identities.length > 0) {
|
|
145125
|
+
bumpEpochsForWorkspaceMemberSet(db, identities, Date.now());
|
|
145126
|
+
}
|
|
145127
|
+
}
|
|
145128
|
+
},
|
|
145129
|
+
{
|
|
145130
|
+
version: 36,
|
|
145131
|
+
description: "session project ownership map for compartment chunk backfill scoping",
|
|
145132
|
+
up: (db) => {
|
|
145133
|
+
db.exec(`
|
|
145134
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
145135
|
+
session_id TEXT NOT NULL,
|
|
145136
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
145137
|
+
project_path TEXT NOT NULL,
|
|
145138
|
+
updated_at INTEGER NOT NULL,
|
|
145139
|
+
PRIMARY KEY(session_id, harness)
|
|
145140
|
+
);
|
|
145141
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
145142
|
+
ON session_projects(project_path);
|
|
145143
|
+
`);
|
|
145144
|
+
const hasChunkTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='compartment_chunk_embeddings'").get();
|
|
145145
|
+
if (hasChunkTable) {
|
|
145146
|
+
db.exec(`
|
|
145147
|
+
INSERT OR IGNORE INTO session_projects (session_id, harness, project_path, updated_at)
|
|
145148
|
+
SELECT session_id, harness, MIN(project_path), 0
|
|
145149
|
+
FROM compartment_chunk_embeddings
|
|
145150
|
+
GROUP BY session_id, harness
|
|
145151
|
+
HAVING COUNT(DISTINCT project_path) = 1;
|
|
145152
|
+
`);
|
|
145153
|
+
}
|
|
145154
|
+
}
|
|
144638
145155
|
}
|
|
144639
145156
|
];
|
|
144640
145157
|
var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -144704,7 +145221,7 @@ function runMigrations(db) {
|
|
|
144704
145221
|
log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
|
|
144705
145222
|
}
|
|
144706
145223
|
// ../plugin/src/features/magic-context/project-docs-hash.ts
|
|
144707
|
-
import { createHash as
|
|
145224
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
144708
145225
|
import { lstatSync, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
144709
145226
|
import path4 from "node:path";
|
|
144710
145227
|
var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
|
|
@@ -144802,7 +145319,7 @@ function hashCanonicalPieces(hashPieces) {
|
|
|
144802
145319
|
if (hashPieces.length === 0) {
|
|
144803
145320
|
return "";
|
|
144804
145321
|
}
|
|
144805
|
-
return
|
|
145322
|
+
return createHash4("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
|
|
144806
145323
|
}
|
|
144807
145324
|
function readProjectDocsCanonical(projectDirectory) {
|
|
144808
145325
|
const canonicalDirectory = path4.resolve(projectDirectory);
|
|
@@ -144908,18 +145425,13 @@ function getMemoryMutation(db, id) {
|
|
|
144908
145425
|
WHERE id = ?`).get(id);
|
|
144909
145426
|
return row ? toMemoryMutation(row) : null;
|
|
144910
145427
|
}
|
|
144911
|
-
function
|
|
144912
|
-
|
|
144913
|
-
|
|
144914
|
-
|
|
144915
|
-
|
|
144916
|
-
|
|
144917
|
-
|
|
144918
|
-
FROM memory_mutation_log
|
|
144919
|
-
WHERE project_path = ?
|
|
144920
|
-
AND id > ?
|
|
144921
|
-
AND target_memory_id IN (${placeholders})
|
|
144922
|
-
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
145428
|
+
function uniqueProjectPaths(projectPaths) {
|
|
145429
|
+
return [...new Set(projectPaths.filter((path5) => path5.length > 0))];
|
|
145430
|
+
}
|
|
145431
|
+
function placeholders2(values) {
|
|
145432
|
+
return values.map(() => "?").join(", ");
|
|
145433
|
+
}
|
|
145434
|
+
function coalesceMutations(rows) {
|
|
144923
145435
|
const chosenByTarget = new Map;
|
|
144924
145436
|
for (const dbRow of rows) {
|
|
144925
145437
|
const candidate = toMemoryMutation(dbRow);
|
|
@@ -144940,10 +145452,54 @@ function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds
|
|
|
144940
145452
|
}
|
|
144941
145453
|
return [...chosenByTarget.values()].sort((left, right) => left.id - right.id);
|
|
144942
145454
|
}
|
|
145455
|
+
function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds) {
|
|
145456
|
+
if (renderedMemoryIds.length === 0)
|
|
145457
|
+
return [];
|
|
145458
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
145459
|
+
const placeholders3 = uniqueIds.map(() => "?").join(", ");
|
|
145460
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
145461
|
+
superseded_by_id, category, new_content, queued_at
|
|
145462
|
+
FROM memory_mutation_log
|
|
145463
|
+
WHERE project_path = ?
|
|
145464
|
+
AND id > ?
|
|
145465
|
+
AND target_memory_id IN (${placeholders3})
|
|
145466
|
+
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
145467
|
+
return coalesceMutations(rows);
|
|
145468
|
+
}
|
|
145469
|
+
function getMemoryMutationsForRenderByProjects(db, projectPaths, afterId, renderedMemoryIds) {
|
|
145470
|
+
if (renderedMemoryIds.length === 0)
|
|
145471
|
+
return [];
|
|
145472
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
145473
|
+
if (identities.length === 0)
|
|
145474
|
+
return [];
|
|
145475
|
+
if (identities.length === 1) {
|
|
145476
|
+
return getMemoryMutationsForRender(db, identities[0], afterId, renderedMemoryIds);
|
|
145477
|
+
}
|
|
145478
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
145479
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
145480
|
+
superseded_by_id, category, new_content, queued_at
|
|
145481
|
+
FROM memory_mutation_log
|
|
145482
|
+
WHERE project_path IN (${placeholders2(identities)})
|
|
145483
|
+
AND id > ?
|
|
145484
|
+
AND target_memory_id IN (${placeholders2(uniqueIds)})
|
|
145485
|
+
ORDER BY id ASC`).all(...identities, afterId ?? 0, ...uniqueIds);
|
|
145486
|
+
return coalesceMutations(rows);
|
|
145487
|
+
}
|
|
144943
145488
|
function getMaxMemoryMutationId(db, projectPath) {
|
|
144944
145489
|
const row = db.prepare("SELECT MAX(id) AS max_id FROM memory_mutation_log WHERE project_path = ?").get(projectPath);
|
|
144945
145490
|
return row?.max_id ?? null;
|
|
144946
145491
|
}
|
|
145492
|
+
function getMaxMemoryMutationIdForProjects(db, projectPaths) {
|
|
145493
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
145494
|
+
if (identities.length === 0)
|
|
145495
|
+
return null;
|
|
145496
|
+
if (identities.length === 1)
|
|
145497
|
+
return getMaxMemoryMutationId(db, identities[0]);
|
|
145498
|
+
const row = db.prepare(`SELECT MAX(id) AS max_id
|
|
145499
|
+
FROM memory_mutation_log
|
|
145500
|
+
WHERE project_path IN (${placeholders2(identities)})`).get(...identities);
|
|
145501
|
+
return row?.max_id ?? null;
|
|
145502
|
+
}
|
|
144947
145503
|
// ../plugin/src/features/magic-context/storage-meta-persisted.ts
|
|
144948
145504
|
init_logger();
|
|
144949
145505
|
var CAS_RETRY_LIMIT = 5;
|
|
@@ -145789,9 +146345,9 @@ function buildStatusClause(status) {
|
|
|
145789
146345
|
if (statuses.length === 0) {
|
|
145790
146346
|
return null;
|
|
145791
146347
|
}
|
|
145792
|
-
const
|
|
146348
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
145793
146349
|
return {
|
|
145794
|
-
sql: `status IN (${
|
|
146350
|
+
sql: `status IN (${placeholders3})`,
|
|
145795
146351
|
params: statuses
|
|
145796
146352
|
};
|
|
145797
146353
|
}
|
|
@@ -145987,19 +146543,6 @@ function getProjectState(db, projectPath) {
|
|
|
145987
146543
|
WHERE project_path = ?`).get(projectPath);
|
|
145988
146544
|
return row ? toProjectState(row) : null;
|
|
145989
146545
|
}
|
|
145990
|
-
function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
|
|
145991
|
-
db.prepare(`INSERT INTO project_state
|
|
145992
|
-
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
145993
|
-
VALUES (?, 1, 0, ?)
|
|
145994
|
-
ON CONFLICT(project_path) DO UPDATE SET
|
|
145995
|
-
project_memory_epoch = project_memory_epoch + 1,
|
|
145996
|
-
updated_at = excluded.updated_at`).run(projectPath, now);
|
|
145997
|
-
const state = getProjectState(db, projectPath);
|
|
145998
|
-
if (!state) {
|
|
145999
|
-
throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
|
|
146000
|
-
}
|
|
146001
|
-
return state;
|
|
146002
|
-
}
|
|
146003
146546
|
function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PROJECT_PATH, now = Date.now()) {
|
|
146004
146547
|
db.prepare(`INSERT INTO project_state
|
|
146005
146548
|
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
@@ -146033,8 +146576,8 @@ function getSourceContents(db, sessionId, tagIds) {
|
|
|
146033
146576
|
if (tagIds.length === 0) {
|
|
146034
146577
|
return new Map;
|
|
146035
146578
|
}
|
|
146036
|
-
const
|
|
146037
|
-
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${
|
|
146579
|
+
const placeholders3 = tagIds.map(() => "?").join(", ");
|
|
146580
|
+
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${placeholders3})`).all(sessionId, ...tagIds).filter(isSourceContentRow);
|
|
146038
146581
|
const sources = new Map;
|
|
146039
146582
|
for (const row of rows) {
|
|
146040
146583
|
sources.set(row.tag_id, row.content);
|
|
@@ -146324,8 +146867,8 @@ function getTagsByNumbers(db, sessionId, tagNumbers) {
|
|
|
146324
146867
|
}
|
|
146325
146868
|
return all;
|
|
146326
146869
|
}
|
|
146327
|
-
const
|
|
146328
|
-
const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${
|
|
146870
|
+
const placeholders3 = tagNumbers.map(() => "?").join(",");
|
|
146871
|
+
const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${placeholders3}) ORDER BY tag_number ASC, id ASC`).all(sessionId, ...tagNumbers).filter(isTagRow);
|
|
146329
146872
|
return rows.map(toTagEntry);
|
|
146330
146873
|
}
|
|
146331
146874
|
var getToolTagNumberByOwnerStatements = new WeakMap;
|
|
@@ -146395,7 +146938,7 @@ var ERROR_CLASSES = new Set([
|
|
|
146395
146938
|
]);
|
|
146396
146939
|
// ../plugin/src/features/magic-context/v22-deferred-backfill.ts
|
|
146397
146940
|
init_logger();
|
|
146398
|
-
import { createHash as
|
|
146941
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
146399
146942
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
146400
146943
|
import path5 from "node:path";
|
|
146401
146944
|
var BATCH_SIZE = 25;
|
|
@@ -146449,7 +146992,7 @@ function computeLegacyRustDirIdentity(rawProjectPath) {
|
|
|
146449
146992
|
} catch {
|
|
146450
146993
|
canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
|
|
146451
146994
|
}
|
|
146452
|
-
return `dir:${
|
|
146995
|
+
return `dir:${createHash5("sha256").update(canonical, "utf8").digest("hex")}`;
|
|
146453
146996
|
}
|
|
146454
146997
|
function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
|
|
146455
146998
|
db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
|
|
@@ -147007,7 +147550,7 @@ function clearNoteNudgeTriggerOnly(db, sessionId) {
|
|
|
147007
147550
|
}
|
|
147008
147551
|
|
|
147009
147552
|
// ../plugin/src/hooks/magic-context/todo-view.ts
|
|
147010
|
-
import { createHash as
|
|
147553
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
147011
147554
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
147012
147555
|
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
147013
147556
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
@@ -147052,7 +147595,7 @@ function buildSyntheticTodoPart(stateJson) {
|
|
|
147052
147595
|
};
|
|
147053
147596
|
}
|
|
147054
147597
|
function computeSyntheticCallId(stateJson) {
|
|
147055
|
-
const hash =
|
|
147598
|
+
const hash = createHash6("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
147056
147599
|
return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
|
|
147057
147600
|
}
|
|
147058
147601
|
function parseTodoState(stateJson) {
|
|
@@ -147193,13 +147736,13 @@ async function maybeSendUpgradeReminder(deps, sessionId) {
|
|
|
147193
147736
|
init_data_path();
|
|
147194
147737
|
import * as fs2 from "node:fs";
|
|
147195
147738
|
import * as path6 from "node:path";
|
|
147196
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
147739
|
+
var ANNOUNCEMENT_VERSION = "0.24.0";
|
|
147197
147740
|
var ANNOUNCEMENT_FEATURES = [
|
|
147198
|
-
"
|
|
147199
|
-
"
|
|
147200
|
-
"
|
|
147201
|
-
"
|
|
147202
|
-
"
|
|
147741
|
+
"Searchable session history: ctx_search can now find older discussion by meaning, not just keywords. New history is embedded automatically — to backfill an EXISTING session's older history, run /ctx-embed-history once (it works in the background).",
|
|
147742
|
+
"Cross-project workspaces: group related repos and share project memories across them, with per-category control over what's shared. Set them up in the dashboard's Workspaces panel.",
|
|
147743
|
+
"Pi: fixed sessions overflowing the model context while still showing moderate usage — Pi now sheds context before a tool-heavy turn overflows.",
|
|
147744
|
+
"Fewer prompt-cache busts: doc edits, processed screenshots, and a rebuild-then-bust-again case no longer re-bill large prompt prefixes.",
|
|
147745
|
+
"Setup wizard now lists your actual models with type-ahead instead of fixed recommendations, and explains the historian/dreamer roles (issue #144). Plus a GitHub Copilot tool-pairing fix (#135)."
|
|
147203
147746
|
];
|
|
147204
147747
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
|
|
147205
147748
|
var STATE_FILENAME = "last_announced_version";
|
|
@@ -149082,7 +149625,7 @@ function isEmbeddingRow(row) {
|
|
|
149082
149625
|
if (row === null || typeof row !== "object")
|
|
149083
149626
|
return false;
|
|
149084
149627
|
const candidate = row;
|
|
149085
|
-
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding);
|
|
149628
|
+
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding) && (candidate.modelId === null || typeof candidate.modelId === "string");
|
|
149086
149629
|
}
|
|
149087
149630
|
function toFloat32Array(blob) {
|
|
149088
149631
|
if (blob instanceof Uint8Array) {
|
|
@@ -149102,7 +149645,7 @@ function getSaveEmbeddingStatement(db) {
|
|
|
149102
149645
|
function getLoadAllEmbeddingsStatement(db) {
|
|
149103
149646
|
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
149104
149647
|
if (!stmt) {
|
|
149105
|
-
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");
|
|
149648
|
+
stmt = db.prepare("SELECT memory_embeddings.memory_id AS memoryId, memory_embeddings.embedding AS embedding, memory_embeddings.model_id AS modelId FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? ORDER BY memory_embeddings.memory_id ASC");
|
|
149106
149649
|
loadAllEmbeddingsStatements.set(db, stmt);
|
|
149107
149650
|
}
|
|
149108
149651
|
return stmt;
|
|
@@ -149131,7 +149674,10 @@ function loadAllEmbeddings(db, projectPath) {
|
|
|
149131
149674
|
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath).filter(isEmbeddingRow);
|
|
149132
149675
|
const embeddings = new Map;
|
|
149133
149676
|
for (const row of rows) {
|
|
149134
|
-
embeddings.set(row.memoryId,
|
|
149677
|
+
embeddings.set(row.memoryId, {
|
|
149678
|
+
embedding: toFloat32Array(row.embedding),
|
|
149679
|
+
modelId: row.modelId
|
|
149680
|
+
});
|
|
149135
149681
|
}
|
|
149136
149682
|
return embeddings;
|
|
149137
149683
|
}
|
|
@@ -149182,13 +149728,13 @@ function invalidateMemory(projectPath, memoryId) {
|
|
|
149182
149728
|
}
|
|
149183
149729
|
|
|
149184
149730
|
// ../plugin/src/features/magic-context/memory/normalize-hash.ts
|
|
149185
|
-
import { createHash as
|
|
149731
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
149186
149732
|
function normalizeMemoryContent(content) {
|
|
149187
149733
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
149188
149734
|
}
|
|
149189
149735
|
function computeNormalizedHash(content) {
|
|
149190
149736
|
const normalized = normalizeMemoryContent(content);
|
|
149191
|
-
return
|
|
149737
|
+
return createHash7("md5").update(normalized).digest("hex");
|
|
149192
149738
|
}
|
|
149193
149739
|
|
|
149194
149740
|
// ../plugin/src/features/magic-context/memory/storage-memory.ts
|
|
@@ -149376,8 +149922,8 @@ function getMemoriesByProjectStatement(db, statuses) {
|
|
|
149376
149922
|
}
|
|
149377
149923
|
let stmt = statements.get(db);
|
|
149378
149924
|
if (!stmt) {
|
|
149379
|
-
const
|
|
149380
|
-
stmt = db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories WHERE project_path = ? AND status IN (${
|
|
149925
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
149926
|
+
stmt = db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories WHERE project_path = ? AND status IN (${placeholders3}) AND (expires_at IS NULL OR expires_at > ?) ORDER BY category ASC, updated_at DESC, id ASC`);
|
|
149381
149927
|
statements.set(db, stmt);
|
|
149382
149928
|
}
|
|
149383
149929
|
return stmt;
|
|
@@ -149522,6 +150068,97 @@ function getMemoriesByProject(db, projectPath, statuses = ["active", "permanent"
|
|
|
149522
150068
|
const rows = getMemoriesByProjectStatement(db, statuses).all(projectPath, ...statuses, expiryCutoff).filter(isMemoryRow);
|
|
149523
150069
|
return rows.map(toMemory);
|
|
149524
150070
|
}
|
|
150071
|
+
function sqlPlaceholders(values) {
|
|
150072
|
+
return values.map(() => "?").join(", ");
|
|
150073
|
+
}
|
|
150074
|
+
function uniqueValues(values) {
|
|
150075
|
+
return [...new Set(values.filter((value) => value.length > 0))];
|
|
150076
|
+
}
|
|
150077
|
+
function buildWorkspaceMemorySqlFilter(args) {
|
|
150078
|
+
if (args.shareCategories === null || args.shareCategories === undefined) {
|
|
150079
|
+
return { clause: "", params: [], active: false };
|
|
150080
|
+
}
|
|
150081
|
+
const identities = uniqueValues(args.identities);
|
|
150082
|
+
const identitySet = new Set(identities);
|
|
150083
|
+
const ownSet = new Set(uniqueValues(args.ownIdentities ?? []).filter((identity) => identitySet.has(identity)));
|
|
150084
|
+
const foreignIdentities = identities.filter((identity) => !ownSet.has(identity));
|
|
150085
|
+
if (foreignIdentities.length === 0) {
|
|
150086
|
+
return { clause: "", params: [], active: false };
|
|
150087
|
+
}
|
|
150088
|
+
const ownIdentities = identities.filter((identity) => ownSet.has(identity));
|
|
150089
|
+
const shareCategories = uniqueValues([...args.shareCategories]);
|
|
150090
|
+
const qualifier = args.tableName ? `${args.tableName}.` : "";
|
|
150091
|
+
const predicates = [];
|
|
150092
|
+
const params = [];
|
|
150093
|
+
if (ownIdentities.length > 0) {
|
|
150094
|
+
predicates.push(`${qualifier}project_path IN (${sqlPlaceholders(ownIdentities)})`);
|
|
150095
|
+
params.push(...ownIdentities);
|
|
150096
|
+
}
|
|
150097
|
+
if (foreignIdentities.length > 0 && shareCategories.length > 0) {
|
|
150098
|
+
predicates.push(`(${qualifier}project_path IN (${sqlPlaceholders(foreignIdentities)}) AND ${qualifier}category IN (${sqlPlaceholders(shareCategories)}))`);
|
|
150099
|
+
params.push(...foreignIdentities, ...shareCategories);
|
|
150100
|
+
}
|
|
150101
|
+
if (predicates.length === 0) {
|
|
150102
|
+
return { clause: " AND 0 = 1", params: [], active: true };
|
|
150103
|
+
}
|
|
150104
|
+
return { clause: ` AND (${predicates.join(" OR ")})`, params, active: true };
|
|
150105
|
+
}
|
|
150106
|
+
function getMemoriesByProjects(db, projectPaths, statuses = ["active", "permanent"], expiryCutoff = Date.now(), ownIdentities, shareCategories) {
|
|
150107
|
+
const identities = uniqueValues(projectPaths);
|
|
150108
|
+
if (identities.length === 0 || statuses.length === 0)
|
|
150109
|
+
return [];
|
|
150110
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
150111
|
+
identities,
|
|
150112
|
+
ownIdentities,
|
|
150113
|
+
shareCategories
|
|
150114
|
+
});
|
|
150115
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
150116
|
+
return getMemoriesByProject(db, identities[0], statuses, expiryCutoff);
|
|
150117
|
+
}
|
|
150118
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
150119
|
+
FROM memories
|
|
150120
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
150121
|
+
AND status IN (${sqlPlaceholders(statuses)})
|
|
150122
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
150123
|
+
ORDER BY category ASC, updated_at DESC, id ASC`).all(...identities, ...statuses, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
150124
|
+
return rows.map(toMemory);
|
|
150125
|
+
}
|
|
150126
|
+
function getMaxMemoryIdForProjects(db, projectPaths, ownIdentities, shareCategories) {
|
|
150127
|
+
const identities = uniqueValues(projectPaths);
|
|
150128
|
+
if (identities.length === 0)
|
|
150129
|
+
return 0;
|
|
150130
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
150131
|
+
identities,
|
|
150132
|
+
ownIdentities,
|
|
150133
|
+
shareCategories
|
|
150134
|
+
});
|
|
150135
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
150136
|
+
const row2 = db.prepare("SELECT COALESCE(MAX(id), 0) AS max_id FROM memories WHERE project_path = ?").get(identities[0]);
|
|
150137
|
+
return typeof row2?.max_id === "number" ? row2.max_id : 0;
|
|
150138
|
+
}
|
|
150139
|
+
const row = db.prepare(`SELECT COALESCE(MAX(id), 0) AS max_id
|
|
150140
|
+
FROM memories
|
|
150141
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})${sharingFilter.clause}`).get(...identities, ...sharingFilter.params);
|
|
150142
|
+
return typeof row?.max_id === "number" ? row.max_id : 0;
|
|
150143
|
+
}
|
|
150144
|
+
function readNewMemoriesForM1Union(db, projectPaths, afterId, expiryCutoff, ownIdentities, shareCategories) {
|
|
150145
|
+
const identities = uniqueValues(projectPaths);
|
|
150146
|
+
if (identities.length === 0)
|
|
150147
|
+
return [];
|
|
150148
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
150149
|
+
identities,
|
|
150150
|
+
ownIdentities,
|
|
150151
|
+
shareCategories
|
|
150152
|
+
});
|
|
150153
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
150154
|
+
FROM memories
|
|
150155
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
150156
|
+
AND id > ?
|
|
150157
|
+
AND status IN ('active', 'permanent')
|
|
150158
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
150159
|
+
ORDER BY ${MEMORY_CATEGORY_ORDER_SQL}, id ASC`).all(...identities, afterId, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
150160
|
+
return rows.map(toMemory);
|
|
150161
|
+
}
|
|
149525
150162
|
function getAllActiveMemoriesForMigration(db, projectPath) {
|
|
149526
150163
|
const rows = getActiveMemoriesNoExpiryStatement(db).all(projectPath).filter(isMemoryRow);
|
|
149527
150164
|
return rows.map(toMemory);
|
|
@@ -150043,8 +150680,8 @@ function getUserMemoryCandidates(db) {
|
|
|
150043
150680
|
function deleteUserMemoryCandidates(db, ids) {
|
|
150044
150681
|
if (ids.length === 0)
|
|
150045
150682
|
return;
|
|
150046
|
-
const
|
|
150047
|
-
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${
|
|
150683
|
+
const placeholders3 = ids.map(() => "?").join(",");
|
|
150684
|
+
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${placeholders3})`).run(...ids);
|
|
150048
150685
|
}
|
|
150049
150686
|
function insertUserMemory(db, content, sourceCandidateIds) {
|
|
150050
150687
|
const now = Date.now();
|
|
@@ -165534,7 +166171,8 @@ var BaseEmbeddingConfigSchema = exports_external.object({
|
|
|
165534
166171
|
endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
|
|
165535
166172
|
api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
|
|
165536
166173
|
input_type: exports_external.string().optional().describe("Optional input_type sent in the embedding request body. Required by some openai-compatible providers (e.g. NVIDIA NIM expects 'query' or 'passage'). Omitted from the request when unset."),
|
|
165537
|
-
truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset.")
|
|
166174
|
+
truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset."),
|
|
166175
|
+
max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
|
|
165538
166176
|
}).superRefine((data, ctx) => {
|
|
165539
166177
|
if (data.provider === "openai-compatible" && !data.endpoint?.trim()) {
|
|
165540
166178
|
ctx.addIssue({
|
|
@@ -165555,7 +166193,8 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
|
|
|
165555
166193
|
if (data.provider === "local") {
|
|
165556
166194
|
return {
|
|
165557
166195
|
provider: "local",
|
|
165558
|
-
model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
166196
|
+
model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
166197
|
+
...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
|
|
165559
166198
|
};
|
|
165560
166199
|
}
|
|
165561
166200
|
if (data.provider === "openai-compatible") {
|
|
@@ -165568,7 +166207,8 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
|
|
|
165568
166207
|
endpoint: data.endpoint?.trim() ?? "",
|
|
165569
166208
|
...apiKey ? { api_key: apiKey } : {},
|
|
165570
166209
|
...inputType ? { input_type: inputType } : {},
|
|
165571
|
-
...truncate ? { truncate } : {}
|
|
166210
|
+
...truncate ? { truncate } : {},
|
|
166211
|
+
...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
|
|
165572
166212
|
};
|
|
165573
166213
|
}
|
|
165574
166214
|
return { provider: "off" };
|
|
@@ -165650,6 +166290,441 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
165650
166290
|
// ../plugin/src/features/magic-context/memory/embedding.ts
|
|
165651
166291
|
init_logger();
|
|
165652
166292
|
|
|
166293
|
+
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
166294
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
166295
|
+
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512;
|
|
166296
|
+
var loadFtsRowsStatements = new WeakMap;
|
|
166297
|
+
var existingHashStatements = new WeakMap;
|
|
166298
|
+
var existingHashByProjectStatements = new WeakMap;
|
|
166299
|
+
var deleteByCompartmentStatements = new WeakMap;
|
|
166300
|
+
var insertEmbeddingStatements = new WeakMap;
|
|
166301
|
+
var distinctModelStatements = new WeakMap;
|
|
166302
|
+
var clearProjectStatements = new WeakMap;
|
|
166303
|
+
var clearProjectModelStatements = new WeakMap;
|
|
166304
|
+
var searchRowsStatements = new WeakMap;
|
|
166305
|
+
var searchRowsByModelStatements = new WeakMap;
|
|
166306
|
+
var backfillCandidateStatements = new WeakMap;
|
|
166307
|
+
function getLoadFtsRowsStatement(db) {
|
|
166308
|
+
let stmt = loadFtsRowsStatements.get(db);
|
|
166309
|
+
if (!stmt) {
|
|
166310
|
+
stmt = db.prepare(`SELECT message_ordinal AS messageOrdinal, role, content
|
|
166311
|
+
FROM message_history_fts
|
|
166312
|
+
WHERE session_id = ?
|
|
166313
|
+
AND message_ordinal >= ?
|
|
166314
|
+
AND message_ordinal <= ?
|
|
166315
|
+
AND role IN ('user', 'assistant')
|
|
166316
|
+
ORDER BY message_ordinal ASC`);
|
|
166317
|
+
loadFtsRowsStatements.set(db, stmt);
|
|
166318
|
+
}
|
|
166319
|
+
return stmt;
|
|
166320
|
+
}
|
|
166321
|
+
function getExistingHashStatement(db, scopedToProject) {
|
|
166322
|
+
const map2 = scopedToProject ? existingHashByProjectStatements : existingHashStatements;
|
|
166323
|
+
let stmt = map2.get(db);
|
|
166324
|
+
if (!stmt) {
|
|
166325
|
+
stmt = db.prepare(`SELECT window_index AS windowIndex, chunk_hash AS chunkHash
|
|
166326
|
+
FROM compartment_chunk_embeddings
|
|
166327
|
+
WHERE compartment_id = ?
|
|
166328
|
+
AND model_id = ?
|
|
166329
|
+
${scopedToProject ? "AND project_path = ?" : ""}
|
|
166330
|
+
ORDER BY window_index ASC`);
|
|
166331
|
+
map2.set(db, stmt);
|
|
166332
|
+
}
|
|
166333
|
+
return stmt;
|
|
166334
|
+
}
|
|
166335
|
+
function getDeleteByCompartmentStatement(db) {
|
|
166336
|
+
let stmt = deleteByCompartmentStatements.get(db);
|
|
166337
|
+
if (!stmt) {
|
|
166338
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE compartment_id = ?");
|
|
166339
|
+
deleteByCompartmentStatements.set(db, stmt);
|
|
166340
|
+
}
|
|
166341
|
+
return stmt;
|
|
166342
|
+
}
|
|
166343
|
+
function getInsertEmbeddingStatement(db) {
|
|
166344
|
+
let stmt = insertEmbeddingStatements.get(db);
|
|
166345
|
+
if (!stmt) {
|
|
166346
|
+
stmt = db.prepare(`INSERT INTO compartment_chunk_embeddings (
|
|
166347
|
+
compartment_id, session_id, project_path, harness, window_index,
|
|
166348
|
+
start_ordinal, end_ordinal, chunk_hash, model_id, dims, vector, created_at
|
|
166349
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
166350
|
+
insertEmbeddingStatements.set(db, stmt);
|
|
166351
|
+
}
|
|
166352
|
+
return stmt;
|
|
166353
|
+
}
|
|
166354
|
+
function getDistinctModelStatement(db) {
|
|
166355
|
+
let stmt = distinctModelStatements.get(db);
|
|
166356
|
+
if (!stmt) {
|
|
166357
|
+
stmt = db.prepare(`SELECT DISTINCT model_id AS modelId
|
|
166358
|
+
FROM compartment_chunk_embeddings
|
|
166359
|
+
WHERE project_path = ?`);
|
|
166360
|
+
distinctModelStatements.set(db, stmt);
|
|
166361
|
+
}
|
|
166362
|
+
return stmt;
|
|
166363
|
+
}
|
|
166364
|
+
function getClearProjectStatement(db) {
|
|
166365
|
+
let stmt = clearProjectStatements.get(db);
|
|
166366
|
+
if (!stmt) {
|
|
166367
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ?");
|
|
166368
|
+
clearProjectStatements.set(db, stmt);
|
|
166369
|
+
}
|
|
166370
|
+
return stmt;
|
|
166371
|
+
}
|
|
166372
|
+
function getClearProjectModelStatement(db) {
|
|
166373
|
+
let stmt = clearProjectModelStatements.get(db);
|
|
166374
|
+
if (!stmt) {
|
|
166375
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ? AND model_id = ?");
|
|
166376
|
+
clearProjectModelStatements.set(db, stmt);
|
|
166377
|
+
}
|
|
166378
|
+
return stmt;
|
|
166379
|
+
}
|
|
166380
|
+
function getSearchRowsStatement(db, withModel) {
|
|
166381
|
+
const map2 = withModel ? searchRowsByModelStatements : searchRowsStatements;
|
|
166382
|
+
let stmt = map2.get(db);
|
|
166383
|
+
if (!stmt) {
|
|
166384
|
+
stmt = db.prepare(`SELECT e.compartment_id AS compartmentId,
|
|
166385
|
+
e.session_id AS sessionId,
|
|
166386
|
+
c.title AS title,
|
|
166387
|
+
c.start_message AS compartmentStart,
|
|
166388
|
+
c.end_message AS compartmentEnd,
|
|
166389
|
+
e.window_index AS windowIndex,
|
|
166390
|
+
e.start_ordinal AS windowStart,
|
|
166391
|
+
e.end_ordinal AS windowEnd,
|
|
166392
|
+
e.chunk_hash AS chunkHash,
|
|
166393
|
+
e.model_id AS modelId,
|
|
166394
|
+
e.dims AS dims,
|
|
166395
|
+
e.vector AS vector
|
|
166396
|
+
FROM compartment_chunk_embeddings e
|
|
166397
|
+
JOIN compartments c ON c.id = e.compartment_id
|
|
166398
|
+
WHERE e.session_id = ?
|
|
166399
|
+
AND e.project_path = ?
|
|
166400
|
+
${withModel ? "AND e.model_id = ?" : ""}
|
|
166401
|
+
ORDER BY e.compartment_id ASC, e.window_index ASC`);
|
|
166402
|
+
map2.set(db, stmt);
|
|
166403
|
+
}
|
|
166404
|
+
return stmt;
|
|
166405
|
+
}
|
|
166406
|
+
function isFinitePositiveInteger(value) {
|
|
166407
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
166408
|
+
}
|
|
166409
|
+
function normalizeCompartmentChunkMaxInputTokens(value) {
|
|
166410
|
+
if (!isFinitePositiveInteger(value)) {
|
|
166411
|
+
return DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS;
|
|
166412
|
+
}
|
|
166413
|
+
return Math.max(1, Math.floor(value));
|
|
166414
|
+
}
|
|
166415
|
+
function normalizeContent(text) {
|
|
166416
|
+
return text.replace(/\s+/g, " ").trim();
|
|
166417
|
+
}
|
|
166418
|
+
function formatOrdinalRange(start, end) {
|
|
166419
|
+
return start === end ? `[${start}]` : `[${start}-${end}]`;
|
|
166420
|
+
}
|
|
166421
|
+
function rolePrefix(role) {
|
|
166422
|
+
if (role === "user")
|
|
166423
|
+
return "U";
|
|
166424
|
+
if (role === "assistant")
|
|
166425
|
+
return "A";
|
|
166426
|
+
return null;
|
|
166427
|
+
}
|
|
166428
|
+
function parseOrdinal(value) {
|
|
166429
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
166430
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
166431
|
+
}
|
|
166432
|
+
function parseCanonicalLineRange(line) {
|
|
166433
|
+
const match = /^\[(\d+)(?:-(\d+))?\]\s+[UA]:/.exec(line.trim());
|
|
166434
|
+
if (!match)
|
|
166435
|
+
return null;
|
|
166436
|
+
const start = Number.parseInt(match[1], 10);
|
|
166437
|
+
const end = match[2] ? Number.parseInt(match[2], 10) : start;
|
|
166438
|
+
if (!Number.isFinite(start) || !Number.isFinite(end))
|
|
166439
|
+
return null;
|
|
166440
|
+
return { start, end };
|
|
166441
|
+
}
|
|
166442
|
+
function hashChunkText(text) {
|
|
166443
|
+
return createHash8("sha256").update(text).digest("hex");
|
|
166444
|
+
}
|
|
166445
|
+
function vectorBlob(vector) {
|
|
166446
|
+
return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
|
|
166447
|
+
}
|
|
166448
|
+
function toFloat32Array2(blob) {
|
|
166449
|
+
if (blob instanceof Uint8Array) {
|
|
166450
|
+
const buffer2 = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
166451
|
+
return new Float32Array(buffer2);
|
|
166452
|
+
}
|
|
166453
|
+
return new Float32Array(blob.slice(0));
|
|
166454
|
+
}
|
|
166455
|
+
function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal) {
|
|
166456
|
+
if (endOrdinal < startOrdinal)
|
|
166457
|
+
return "";
|
|
166458
|
+
const rows = getLoadFtsRowsStatement(db).all(sessionId, startOrdinal, endOrdinal).map((row) => row);
|
|
166459
|
+
const lines = [];
|
|
166460
|
+
let current = null;
|
|
166461
|
+
const flush2 = () => {
|
|
166462
|
+
if (!current || current.parts.length === 0)
|
|
166463
|
+
return;
|
|
166464
|
+
lines.push(`${formatOrdinalRange(current.start, current.end)} ${current.role}: ${current.parts.join(" / ")}`);
|
|
166465
|
+
current = null;
|
|
166466
|
+
};
|
|
166467
|
+
for (const row of rows) {
|
|
166468
|
+
const ordinal = parseOrdinal(row.messageOrdinal);
|
|
166469
|
+
const prefix = rolePrefix(row.role);
|
|
166470
|
+
const content = typeof row.content === "string" ? normalizeContent(row.content) : "";
|
|
166471
|
+
if (ordinal === null || prefix === null || content.length === 0)
|
|
166472
|
+
continue;
|
|
166473
|
+
if (current && current.role === prefix) {
|
|
166474
|
+
current.end = ordinal;
|
|
166475
|
+
current.parts.push(content);
|
|
166476
|
+
continue;
|
|
166477
|
+
}
|
|
166478
|
+
flush2();
|
|
166479
|
+
current = { role: prefix, start: ordinal, end: ordinal, parts: [content] };
|
|
166480
|
+
}
|
|
166481
|
+
flush2();
|
|
166482
|
+
return lines.join(`
|
|
166483
|
+
`);
|
|
166484
|
+
}
|
|
166485
|
+
function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
|
|
166486
|
+
const lines = [];
|
|
166487
|
+
for (const rawLine of chunkText.split(/\r?\n/)) {
|
|
166488
|
+
const line = rawLine.trim();
|
|
166489
|
+
const match = /^(\[(\d+)(?:-(\d+))?\]\s+[UA]:)\s*(.*)$/.exec(line);
|
|
166490
|
+
if (!match)
|
|
166491
|
+
continue;
|
|
166492
|
+
const lineStart = Number.parseInt(match[2], 10);
|
|
166493
|
+
const lineEnd = match[3] ? Number.parseInt(match[3], 10) : lineStart;
|
|
166494
|
+
if (startOrdinal != null && lineEnd < startOrdinal)
|
|
166495
|
+
continue;
|
|
166496
|
+
if (endOrdinal != null && lineStart > endOrdinal)
|
|
166497
|
+
continue;
|
|
166498
|
+
const rawParts = match[4].split(" / ").map((part) => normalizeContent(part)).filter((part) => part.length > 0);
|
|
166499
|
+
const ordinalSpan = lineEnd - lineStart + 1;
|
|
166500
|
+
const roleLabel = match[1].slice(match[1].indexOf("]") + 2);
|
|
166501
|
+
if (ordinalSpan === rawParts.length) {
|
|
166502
|
+
const retained = rawParts.map((part, index) => ({ ordinal: lineStart + index, part })).filter(({ ordinal, part }) => {
|
|
166503
|
+
if (part.startsWith("TC:"))
|
|
166504
|
+
return false;
|
|
166505
|
+
if (startOrdinal != null && ordinal < startOrdinal)
|
|
166506
|
+
return false;
|
|
166507
|
+
if (endOrdinal != null && ordinal > endOrdinal)
|
|
166508
|
+
return false;
|
|
166509
|
+
return true;
|
|
166510
|
+
});
|
|
166511
|
+
if (retained.length === 0)
|
|
166512
|
+
continue;
|
|
166513
|
+
const retainedStart = retained[0].ordinal;
|
|
166514
|
+
const retainedEnd = retained[retained.length - 1].ordinal;
|
|
166515
|
+
lines.push(`${formatOrdinalRange(retainedStart, retainedEnd)} ${roleLabel} ${retained.map(({ part }) => part).join(" / ")}`);
|
|
166516
|
+
continue;
|
|
166517
|
+
}
|
|
166518
|
+
const parts = rawParts.filter((part) => !part.startsWith("TC:"));
|
|
166519
|
+
if (parts.length === 0)
|
|
166520
|
+
continue;
|
|
166521
|
+
lines.push(`${match[1]} ${parts.join(" / ")}`);
|
|
166522
|
+
}
|
|
166523
|
+
return lines.join(`
|
|
166524
|
+
`);
|
|
166525
|
+
}
|
|
166526
|
+
function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTokens) {
|
|
166527
|
+
const lines = canonicalText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
166528
|
+
if (lines.length === 0 || endOrdinal < startOrdinal)
|
|
166529
|
+
return [];
|
|
166530
|
+
const normalizedMax = normalizeCompartmentChunkMaxInputTokens(maxInputTokens);
|
|
166531
|
+
const fullText = lines.join(`
|
|
166532
|
+
`);
|
|
166533
|
+
if (estimateTokens(fullText) <= normalizedMax) {
|
|
166534
|
+
return [
|
|
166535
|
+
{
|
|
166536
|
+
windowIndex: 0,
|
|
166537
|
+
startOrdinal,
|
|
166538
|
+
endOrdinal,
|
|
166539
|
+
text: fullText,
|
|
166540
|
+
chunkHash: hashChunkText(fullText)
|
|
166541
|
+
}
|
|
166542
|
+
];
|
|
166543
|
+
}
|
|
166544
|
+
const windows = [];
|
|
166545
|
+
let currentLines = [];
|
|
166546
|
+
let currentStart = null;
|
|
166547
|
+
let currentEnd = null;
|
|
166548
|
+
let currentTokens = 0;
|
|
166549
|
+
const flush2 = () => {
|
|
166550
|
+
if (currentLines.length === 0 || currentStart === null || currentEnd === null)
|
|
166551
|
+
return;
|
|
166552
|
+
const text = currentLines.join(`
|
|
166553
|
+
`);
|
|
166554
|
+
windows.push({
|
|
166555
|
+
windowIndex: windows.length + 1,
|
|
166556
|
+
startOrdinal: currentStart,
|
|
166557
|
+
endOrdinal: currentEnd,
|
|
166558
|
+
text,
|
|
166559
|
+
chunkHash: hashChunkText(text)
|
|
166560
|
+
});
|
|
166561
|
+
currentLines = [];
|
|
166562
|
+
currentStart = null;
|
|
166563
|
+
currentEnd = null;
|
|
166564
|
+
currentTokens = 0;
|
|
166565
|
+
};
|
|
166566
|
+
for (const line of lines) {
|
|
166567
|
+
const range = parseCanonicalLineRange(line);
|
|
166568
|
+
const lineStart = range?.start ?? startOrdinal;
|
|
166569
|
+
const lineEnd = range?.end ?? lineStart;
|
|
166570
|
+
const lineTokens = estimateTokens(line);
|
|
166571
|
+
if (currentLines.length > 0 && currentTokens + lineTokens > normalizedMax) {
|
|
166572
|
+
flush2();
|
|
166573
|
+
}
|
|
166574
|
+
if (currentLines.length === 0) {
|
|
166575
|
+
currentStart = lineStart;
|
|
166576
|
+
}
|
|
166577
|
+
currentLines.push(line);
|
|
166578
|
+
currentEnd = lineEnd;
|
|
166579
|
+
currentTokens += lineTokens;
|
|
166580
|
+
}
|
|
166581
|
+
flush2();
|
|
166582
|
+
return windows;
|
|
166583
|
+
}
|
|
166584
|
+
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
166585
|
+
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
166586
|
+
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
166587
|
+
return new Map(rows.filter((row) => typeof row.windowIndex === "number" && typeof row.chunkHash === "string").map((row) => [row.windowIndex, row.chunkHash]));
|
|
166588
|
+
}
|
|
166589
|
+
function chunkEmbeddingWindowsAreCurrent(db, compartmentId, modelId, windows, projectPath) {
|
|
166590
|
+
const existing = getExistingChunkHashes(db, compartmentId, modelId, projectPath);
|
|
166591
|
+
if (existing.size !== windows.length)
|
|
166592
|
+
return false;
|
|
166593
|
+
return windows.every((window) => existing.get(window.windowIndex) === window.chunkHash);
|
|
166594
|
+
}
|
|
166595
|
+
function replaceCompartmentChunkEmbeddings(db, rows) {
|
|
166596
|
+
if (rows.length === 0)
|
|
166597
|
+
return;
|
|
166598
|
+
const compartmentId = rows[0].compartmentId;
|
|
166599
|
+
const now = Date.now();
|
|
166600
|
+
db.transaction(() => {
|
|
166601
|
+
getDeleteByCompartmentStatement(db).run(compartmentId);
|
|
166602
|
+
const insert = getInsertEmbeddingStatement(db);
|
|
166603
|
+
for (const row of rows) {
|
|
166604
|
+
insert.run(row.compartmentId, row.sessionId, row.projectPath, getHarness(), row.window.windowIndex, row.window.startOrdinal, row.window.endOrdinal, row.window.chunkHash, row.modelId, row.vector.length, vectorBlob(row.vector), row.createdAt ?? now);
|
|
166605
|
+
}
|
|
166606
|
+
})();
|
|
166607
|
+
}
|
|
166608
|
+
function getDistinctChunkEmbeddingModelIds(db, projectPath) {
|
|
166609
|
+
const rows = getDistinctModelStatement(db).all(projectPath);
|
|
166610
|
+
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
166611
|
+
}
|
|
166612
|
+
function clearChunkEmbeddingsForProject(db, projectPath, modelId) {
|
|
166613
|
+
if (modelId) {
|
|
166614
|
+
return getClearProjectModelStatement(db).run(projectPath, modelId).changes;
|
|
166615
|
+
}
|
|
166616
|
+
return getClearProjectStatement(db).run(projectPath).changes;
|
|
166617
|
+
}
|
|
166618
|
+
function loadCompartmentChunkEmbeddingsForSearch(db, sessionId, projectPath, modelId) {
|
|
166619
|
+
const rows = modelId ? getSearchRowsStatement(db, true).all(sessionId, projectPath, modelId) : getSearchRowsStatement(db, false).all(sessionId, projectPath);
|
|
166620
|
+
return rows.filter((row) => typeof row.compartmentId === "number" && typeof row.sessionId === "string" && typeof row.title === "string" && typeof row.compartmentStart === "number" && typeof row.compartmentEnd === "number" && typeof row.windowIndex === "number" && typeof row.windowStart === "number" && typeof row.windowEnd === "number" && typeof row.chunkHash === "string" && typeof row.modelId === "string" && typeof row.dims === "number" && (row.vector instanceof Uint8Array || row.vector instanceof ArrayBuffer)).map((row) => ({
|
|
166621
|
+
compartmentId: row.compartmentId,
|
|
166622
|
+
sessionId: row.sessionId,
|
|
166623
|
+
title: row.title,
|
|
166624
|
+
startOrdinal: row.compartmentStart,
|
|
166625
|
+
endOrdinal: row.compartmentEnd,
|
|
166626
|
+
windowIndex: row.windowIndex,
|
|
166627
|
+
windowStartOrdinal: row.windowStart,
|
|
166628
|
+
windowEndOrdinal: row.windowEnd,
|
|
166629
|
+
chunkHash: row.chunkHash,
|
|
166630
|
+
modelId: row.modelId,
|
|
166631
|
+
dims: row.dims,
|
|
166632
|
+
vector: toFloat32Array2(row.vector)
|
|
166633
|
+
}));
|
|
166634
|
+
}
|
|
166635
|
+
function mapBackfillCandidateRows(rows) {
|
|
166636
|
+
return rows.filter((row) => {
|
|
166637
|
+
if (row === null || typeof row !== "object")
|
|
166638
|
+
return false;
|
|
166639
|
+
const candidate = row;
|
|
166640
|
+
return typeof candidate.id === "number" && typeof candidate.sessionId === "string" && typeof candidate.startMessage === "number" && typeof candidate.endMessage === "number" && typeof candidate.title === "string";
|
|
166641
|
+
}).map((row) => ({
|
|
166642
|
+
id: row.id,
|
|
166643
|
+
sessionId: row.sessionId,
|
|
166644
|
+
startMessage: row.startMessage,
|
|
166645
|
+
endMessage: row.endMessage,
|
|
166646
|
+
title: row.title
|
|
166647
|
+
}));
|
|
166648
|
+
}
|
|
166649
|
+
var sessionBackfillCandidateStatements = new WeakMap;
|
|
166650
|
+
function loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelId, limit, excludeIds) {
|
|
166651
|
+
if (excludeIds && excludeIds.length > 0) {
|
|
166652
|
+
const placeholders3 = excludeIds.map(() => "?").join(", ");
|
|
166653
|
+
const stmt2 = db.prepare(`SELECT c.id AS id,
|
|
166654
|
+
c.session_id AS sessionId,
|
|
166655
|
+
c.start_message AS startMessage,
|
|
166656
|
+
c.end_message AS endMessage,
|
|
166657
|
+
c.title AS title
|
|
166658
|
+
FROM compartments c
|
|
166659
|
+
JOIN session_projects sp
|
|
166660
|
+
ON sp.session_id = c.session_id
|
|
166661
|
+
AND sp.harness = c.harness
|
|
166662
|
+
AND sp.project_path = ?
|
|
166663
|
+
WHERE c.session_id = ?
|
|
166664
|
+
AND c.start_message IS NOT NULL
|
|
166665
|
+
AND c.end_message IS NOT NULL
|
|
166666
|
+
AND c.id NOT IN (${placeholders3})
|
|
166667
|
+
AND NOT EXISTS (
|
|
166668
|
+
SELECT 1
|
|
166669
|
+
FROM compartment_chunk_embeddings current
|
|
166670
|
+
WHERE current.compartment_id = c.id
|
|
166671
|
+
AND current.project_path = ?
|
|
166672
|
+
AND current.model_id = ?
|
|
166673
|
+
)
|
|
166674
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
166675
|
+
LIMIT ?`);
|
|
166676
|
+
const rows2 = stmt2.all(projectPath, sessionId, ...excludeIds, projectPath, modelId, Math.max(1, limit));
|
|
166677
|
+
return mapBackfillCandidateRows(rows2);
|
|
166678
|
+
}
|
|
166679
|
+
let stmt = sessionBackfillCandidateStatements.get(db);
|
|
166680
|
+
if (!stmt) {
|
|
166681
|
+
stmt = db.prepare(`SELECT c.id AS id,
|
|
166682
|
+
c.session_id AS sessionId,
|
|
166683
|
+
c.start_message AS startMessage,
|
|
166684
|
+
c.end_message AS endMessage,
|
|
166685
|
+
c.title AS title
|
|
166686
|
+
FROM compartments c
|
|
166687
|
+
JOIN session_projects sp
|
|
166688
|
+
ON sp.session_id = c.session_id
|
|
166689
|
+
AND sp.harness = c.harness
|
|
166690
|
+
AND sp.project_path = ?
|
|
166691
|
+
WHERE c.session_id = ?
|
|
166692
|
+
AND c.start_message IS NOT NULL
|
|
166693
|
+
AND c.end_message IS NOT NULL
|
|
166694
|
+
AND NOT EXISTS (
|
|
166695
|
+
SELECT 1
|
|
166696
|
+
FROM compartment_chunk_embeddings current
|
|
166697
|
+
WHERE current.compartment_id = c.id
|
|
166698
|
+
AND current.project_path = ?
|
|
166699
|
+
AND current.model_id = ?
|
|
166700
|
+
)
|
|
166701
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
166702
|
+
LIMIT ?`);
|
|
166703
|
+
sessionBackfillCandidateStatements.set(db, stmt);
|
|
166704
|
+
}
|
|
166705
|
+
const rows = stmt.all(projectPath, sessionId, projectPath, modelId, Math.max(1, limit));
|
|
166706
|
+
return mapBackfillCandidateRows(rows);
|
|
166707
|
+
}
|
|
166708
|
+
function countUnembeddedSessionCompartments(db, projectPath, sessionId, modelId) {
|
|
166709
|
+
const row = db.prepare(`SELECT COUNT(*) AS n
|
|
166710
|
+
FROM compartments c
|
|
166711
|
+
JOIN session_projects sp
|
|
166712
|
+
ON sp.session_id = c.session_id
|
|
166713
|
+
AND sp.harness = c.harness
|
|
166714
|
+
AND sp.project_path = ?
|
|
166715
|
+
WHERE c.session_id = ?
|
|
166716
|
+
AND c.start_message IS NOT NULL
|
|
166717
|
+
AND c.end_message IS NOT NULL
|
|
166718
|
+
AND NOT EXISTS (
|
|
166719
|
+
SELECT 1
|
|
166720
|
+
FROM compartment_chunk_embeddings current
|
|
166721
|
+
WHERE current.compartment_id = c.id
|
|
166722
|
+
AND current.project_path = ?
|
|
166723
|
+
AND current.model_id = ?
|
|
166724
|
+
)`).get(projectPath, sessionId, projectPath, modelId);
|
|
166725
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
166726
|
+
}
|
|
166727
|
+
|
|
165653
166728
|
// ../plugin/src/features/magic-context/memory/cosine-similarity.ts
|
|
165654
166729
|
function cosineSimilarity(a, b) {
|
|
165655
166730
|
if (a.length !== b.length) {
|
|
@@ -165808,19 +166883,19 @@ function isArrayLikeNumber(value) {
|
|
|
165808
166883
|
}
|
|
165809
166884
|
return arr.length === 0 || typeof arr[0] === "number";
|
|
165810
166885
|
}
|
|
165811
|
-
function
|
|
166886
|
+
function toFloat32Array3(values) {
|
|
165812
166887
|
return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
|
|
165813
166888
|
}
|
|
165814
166889
|
function extractBatchEmbeddings(result, expectedCount) {
|
|
165815
166890
|
const { data } = result;
|
|
165816
166891
|
if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
|
|
165817
|
-
return data.map((entry) =>
|
|
166892
|
+
return data.map((entry) => toFloat32Array3(entry));
|
|
165818
166893
|
}
|
|
165819
166894
|
if (!isArrayLikeNumber(data)) {
|
|
165820
166895
|
log("[magic-context] embedding batch returned unexpected data shape");
|
|
165821
166896
|
return Array.from({ length: expectedCount }, () => null);
|
|
165822
166897
|
}
|
|
165823
|
-
const flatData =
|
|
166898
|
+
const flatData = toFloat32Array3(data);
|
|
165824
166899
|
const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
|
|
165825
166900
|
if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
|
|
165826
166901
|
log("[magic-context] embedding batch returned invalid dimensions");
|
|
@@ -165835,6 +166910,7 @@ function extractBatchEmbeddings(result, expectedCount) {
|
|
|
165835
166910
|
|
|
165836
166911
|
class LocalEmbeddingProvider {
|
|
165837
166912
|
modelId;
|
|
166913
|
+
maxInputTokens;
|
|
165838
166914
|
model;
|
|
165839
166915
|
pipeline = null;
|
|
165840
166916
|
initPromise = null;
|
|
@@ -165842,8 +166918,9 @@ class LocalEmbeddingProvider {
|
|
|
165842
166918
|
disposing = false;
|
|
165843
166919
|
disposePromise = null;
|
|
165844
166920
|
inFlightWaiters = [];
|
|
165845
|
-
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
166921
|
+
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
|
|
165846
166922
|
this.model = model;
|
|
166923
|
+
this.maxInputTokens = maxInputTokens;
|
|
165847
166924
|
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
165848
166925
|
}
|
|
165849
166926
|
async initialize() {
|
|
@@ -166098,6 +167175,7 @@ var FETCH_TIMEOUT_MS = 30000;
|
|
|
166098
167175
|
|
|
166099
167176
|
class OpenAICompatibleEmbeddingProvider {
|
|
166100
167177
|
modelId;
|
|
167178
|
+
maxInputTokens;
|
|
166101
167179
|
endpoint;
|
|
166102
167180
|
model;
|
|
166103
167181
|
apiKey;
|
|
@@ -166114,11 +167192,13 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166114
167192
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
166115
167193
|
this.inputType = options.inputType?.trim() ?? "";
|
|
166116
167194
|
this.truncate = options.truncate?.trim() ?? "";
|
|
167195
|
+
this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
|
|
166117
167196
|
this.modelId = getEmbeddingProviderIdentity({
|
|
166118
167197
|
provider: "openai-compatible",
|
|
166119
167198
|
endpoint: this.endpoint,
|
|
166120
167199
|
model: this.model,
|
|
166121
|
-
...this.apiKey ? { api_key: this.apiKey } : {}
|
|
167200
|
+
...this.apiKey ? { api_key: this.apiKey } : {},
|
|
167201
|
+
...this.inputType ? { input_type: this.inputType } : {}
|
|
166122
167202
|
});
|
|
166123
167203
|
}
|
|
166124
167204
|
async initialize() {
|
|
@@ -166309,7 +167389,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166309
167389
|
}
|
|
166310
167390
|
|
|
166311
167391
|
// ../plugin/src/features/magic-context/project-embedding-registry.ts
|
|
166312
|
-
import { createHash as
|
|
167392
|
+
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
166313
167393
|
init_logger();
|
|
166314
167394
|
|
|
166315
167395
|
// ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
|
|
@@ -166317,7 +167397,7 @@ var saveStatements = new WeakMap;
|
|
|
166317
167397
|
var loadProjectStatements = new WeakMap;
|
|
166318
167398
|
var loadUnembeddedStatements = new WeakMap;
|
|
166319
167399
|
var countEmbeddedStatements = new WeakMap;
|
|
166320
|
-
var
|
|
167400
|
+
var clearProjectStatements2 = new WeakMap;
|
|
166321
167401
|
var distinctModelIdStatements = new WeakMap;
|
|
166322
167402
|
function getSaveStatement(db) {
|
|
166323
167403
|
let stmt = saveStatements.get(db);
|
|
@@ -166365,12 +167445,12 @@ function getCountEmbeddedStatement(db) {
|
|
|
166365
167445
|
}
|
|
166366
167446
|
return stmt;
|
|
166367
167447
|
}
|
|
166368
|
-
function
|
|
166369
|
-
let stmt =
|
|
167448
|
+
function getClearProjectStatement2(db) {
|
|
167449
|
+
let stmt = clearProjectStatements2.get(db);
|
|
166370
167450
|
if (!stmt) {
|
|
166371
167451
|
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
166372
167452
|
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
166373
|
-
|
|
167453
|
+
clearProjectStatements2.set(db, stmt);
|
|
166374
167454
|
}
|
|
166375
167455
|
return stmt;
|
|
166376
167456
|
}
|
|
@@ -166406,7 +167486,7 @@ function countEmbeddedCommits(db, projectPath) {
|
|
|
166406
167486
|
return row?.count ?? 0;
|
|
166407
167487
|
}
|
|
166408
167488
|
function clearProjectCommitEmbeddings(db, projectPath) {
|
|
166409
|
-
return
|
|
167489
|
+
return getClearProjectStatement2(db).run(projectPath).changes;
|
|
166410
167490
|
}
|
|
166411
167491
|
function getDistinctCommitEmbeddingModelIds(db, projectPath) {
|
|
166412
167492
|
const rows = getDistinctModelIdStatement(db).all(projectPath);
|
|
@@ -166532,9 +167612,83 @@ function releaseGitSweepLease(db, projectPath, holderId) {
|
|
|
166532
167612
|
});
|
|
166533
167613
|
}
|
|
166534
167614
|
|
|
167615
|
+
// ../plugin/src/features/magic-context/session-project-storage.ts
|
|
167616
|
+
var upsertSessionProjectStatements = new WeakMap;
|
|
167617
|
+
var repairSessionChunkProjectStatements = new WeakMap;
|
|
167618
|
+
var repairProjectChunkProjectStatements = new WeakMap;
|
|
167619
|
+
function getUpsertSessionProjectStatement(db) {
|
|
167620
|
+
let stmt = upsertSessionProjectStatements.get(db);
|
|
167621
|
+
if (!stmt) {
|
|
167622
|
+
stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
|
|
167623
|
+
VALUES (?, ?, ?, ?)
|
|
167624
|
+
ON CONFLICT(session_id, harness) DO UPDATE SET
|
|
167625
|
+
project_path = excluded.project_path,
|
|
167626
|
+
updated_at = excluded.updated_at
|
|
167627
|
+
WHERE session_projects.project_path <> excluded.project_path`);
|
|
167628
|
+
upsertSessionProjectStatements.set(db, stmt);
|
|
167629
|
+
}
|
|
167630
|
+
return stmt;
|
|
167631
|
+
}
|
|
167632
|
+
function getRepairSessionChunkProjectStatement(db) {
|
|
167633
|
+
let stmt = repairSessionChunkProjectStatements.get(db);
|
|
167634
|
+
if (!stmt) {
|
|
167635
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
167636
|
+
SET project_path = ?
|
|
167637
|
+
WHERE session_id = ?
|
|
167638
|
+
AND harness = ?
|
|
167639
|
+
AND project_path <> ?`);
|
|
167640
|
+
repairSessionChunkProjectStatements.set(db, stmt);
|
|
167641
|
+
}
|
|
167642
|
+
return stmt;
|
|
167643
|
+
}
|
|
167644
|
+
function getRepairProjectChunkProjectStatement(db) {
|
|
167645
|
+
let stmt = repairProjectChunkProjectStatements.get(db);
|
|
167646
|
+
if (!stmt) {
|
|
167647
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
167648
|
+
SET project_path = (
|
|
167649
|
+
SELECT sp.project_path
|
|
167650
|
+
FROM session_projects sp
|
|
167651
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
167652
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
167653
|
+
LIMIT 1
|
|
167654
|
+
)
|
|
167655
|
+
WHERE EXISTS (
|
|
167656
|
+
SELECT 1
|
|
167657
|
+
FROM session_projects sp
|
|
167658
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
167659
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
167660
|
+
AND sp.project_path <> compartment_chunk_embeddings.project_path
|
|
167661
|
+
AND (
|
|
167662
|
+
sp.project_path = ?
|
|
167663
|
+
OR compartment_chunk_embeddings.project_path = ?
|
|
167664
|
+
)
|
|
167665
|
+
)`);
|
|
167666
|
+
repairProjectChunkProjectStatements.set(db, stmt);
|
|
167667
|
+
}
|
|
167668
|
+
return stmt;
|
|
167669
|
+
}
|
|
167670
|
+
function recordSessionProjectIdentity(db, sessionId, projectPath) {
|
|
167671
|
+
if (!sessionId || !projectPath)
|
|
167672
|
+
return;
|
|
167673
|
+
const harness = getHarness();
|
|
167674
|
+
const now = Date.now();
|
|
167675
|
+
db.transaction(() => {
|
|
167676
|
+
getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
|
|
167677
|
+
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
|
|
167678
|
+
})();
|
|
167679
|
+
}
|
|
167680
|
+
function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
167681
|
+
if (!projectPath)
|
|
167682
|
+
return 0;
|
|
167683
|
+
return getRepairProjectChunkProjectStatement(db).run(projectPath, projectPath).changes;
|
|
167684
|
+
}
|
|
167685
|
+
|
|
166535
167686
|
// ../plugin/src/features/magic-context/project-embedding-registry.ts
|
|
166536
167687
|
var OFF_PROVIDER_IDENTITY = "embedding-provider:off";
|
|
166537
167688
|
var SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
167689
|
+
var CHUNK_DRAIN_BATCH_SIZE = 8;
|
|
167690
|
+
var MAX_WINDOWS_PER_EMBED_CALL = 16;
|
|
167691
|
+
var SESSION_EMBED_LEASE_RENEWAL_MS = 60 * 1000;
|
|
166538
167692
|
var projectRegistrations = new Map;
|
|
166539
167693
|
var loadUnembeddedMemoriesStatements = new WeakMap;
|
|
166540
167694
|
var globalRegistrationGeneration = 0;
|
|
@@ -166543,7 +167697,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
166543
167697
|
if (!config2 || config2.provider === "local") {
|
|
166544
167698
|
return {
|
|
166545
167699
|
provider: "local",
|
|
166546
|
-
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
167700
|
+
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
167701
|
+
...config2?.max_input_tokens ? {
|
|
167702
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
167703
|
+
} : {}
|
|
166547
167704
|
};
|
|
166548
167705
|
}
|
|
166549
167706
|
if (config2.provider === "openai-compatible") {
|
|
@@ -166556,7 +167713,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
166556
167713
|
endpoint: config2.endpoint.trim(),
|
|
166557
167714
|
...apiKey ? { api_key: apiKey } : {},
|
|
166558
167715
|
...inputType ? { input_type: inputType } : {},
|
|
166559
|
-
...truncate ? { truncate } : {}
|
|
167716
|
+
...truncate ? { truncate } : {},
|
|
167717
|
+
...config2.max_input_tokens ? {
|
|
167718
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
167719
|
+
} : {}
|
|
166560
167720
|
};
|
|
166561
167721
|
}
|
|
166562
167722
|
return { provider: "off" };
|
|
@@ -166574,10 +167734,11 @@ function createProvider(config2) {
|
|
|
166574
167734
|
model: config2.model,
|
|
166575
167735
|
apiKey: config2.api_key,
|
|
166576
167736
|
inputType: config2.input_type,
|
|
166577
|
-
truncate: config2.truncate
|
|
167737
|
+
truncate: config2.truncate,
|
|
167738
|
+
maxInputTokens: config2.max_input_tokens
|
|
166578
167739
|
});
|
|
166579
167740
|
}
|
|
166580
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
167741
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
166581
167742
|
}
|
|
166582
167743
|
function stableStringify2(value) {
|
|
166583
167744
|
if (Array.isArray(value)) {
|
|
@@ -166590,7 +167751,7 @@ function stableStringify2(value) {
|
|
|
166590
167751
|
return JSON.stringify(value);
|
|
166591
167752
|
}
|
|
166592
167753
|
function sha256Prefix(value, length = 16) {
|
|
166593
|
-
return
|
|
167754
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, length);
|
|
166594
167755
|
}
|
|
166595
167756
|
function getRuntimeFingerprint(config2) {
|
|
166596
167757
|
if (config2.provider === "off") {
|
|
@@ -166598,6 +167759,18 @@ function getRuntimeFingerprint(config2) {
|
|
|
166598
167759
|
}
|
|
166599
167760
|
return `${getEmbeddingProviderIdentity(config2)}:${sha256Prefix(stableStringify2(config2))}`;
|
|
166600
167761
|
}
|
|
167762
|
+
function getChunkEmbeddingModelId(config2, providerIdentity) {
|
|
167763
|
+
if (config2.provider === "off") {
|
|
167764
|
+
return OFF_PROVIDER_IDENTITY;
|
|
167765
|
+
}
|
|
167766
|
+
const chunkIdentity = {
|
|
167767
|
+
providerIdentity,
|
|
167768
|
+
chunkerVersion: 1,
|
|
167769
|
+
maxInputTokens: normalizeCompartmentChunkMaxInputTokens("max_input_tokens" in config2 ? config2.max_input_tokens : undefined),
|
|
167770
|
+
truncate: config2.provider === "openai-compatible" ? config2.truncate ?? "" : ""
|
|
167771
|
+
};
|
|
167772
|
+
return `${providerIdentity}:chunk:${sha256Prefix(stableStringify2(chunkIdentity))}`;
|
|
167773
|
+
}
|
|
166601
167774
|
function sameFeatures(a, b) {
|
|
166602
167775
|
return a.memoryEnabled === b.memoryEnabled && a.gitCommitEnabled === b.gitCommitEnabled;
|
|
166603
167776
|
}
|
|
@@ -166614,7 +167787,8 @@ function snapshotFor(registration) {
|
|
|
166614
167787
|
features: { ...registration.features },
|
|
166615
167788
|
enabled,
|
|
166616
167789
|
gitCommitEnabled,
|
|
166617
|
-
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId
|
|
167790
|
+
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
|
|
167791
|
+
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId
|
|
166618
167792
|
};
|
|
166619
167793
|
}
|
|
166620
167794
|
function disposeProvider(provider) {
|
|
@@ -166634,7 +167808,7 @@ function anyStoredModelIdIsStale(storedIds, currentId) {
|
|
|
166634
167808
|
}
|
|
166635
167809
|
return false;
|
|
166636
167810
|
}
|
|
166637
|
-
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, features) {
|
|
167811
|
+
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, currentChunkIdentity, features) {
|
|
166638
167812
|
if (currentProviderIdentity === OFF_PROVIDER_IDENTITY) {
|
|
166639
167813
|
return false;
|
|
166640
167814
|
}
|
|
@@ -166655,6 +167829,14 @@ function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity,
|
|
|
166655
167829
|
wiped = true;
|
|
166656
167830
|
}
|
|
166657
167831
|
}
|
|
167832
|
+
if (features.memoryEnabled) {
|
|
167833
|
+
repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectIdentity);
|
|
167834
|
+
const chunkIds = getDistinctChunkEmbeddingModelIds(db, projectIdentity);
|
|
167835
|
+
if (anyStoredModelIdIsStale(chunkIds, currentChunkIdentity)) {
|
|
167836
|
+
clearChunkEmbeddingsForProject(db, projectIdentity);
|
|
167837
|
+
wiped = true;
|
|
167838
|
+
}
|
|
167839
|
+
}
|
|
166658
167840
|
})();
|
|
166659
167841
|
return wiped;
|
|
166660
167842
|
}
|
|
@@ -166662,10 +167844,11 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
166662
167844
|
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
166663
167845
|
const providerIdentity = getEmbeddingProviderIdentity(resolvedConfig);
|
|
166664
167846
|
const runtimeFingerprint = getRuntimeFingerprint(resolvedConfig);
|
|
167847
|
+
const chunkModelId = getChunkEmbeddingModelId(resolvedConfig, providerIdentity);
|
|
166665
167848
|
const prior = projectRegistrations.get(projectIdentity);
|
|
166666
167849
|
const canReuseProvider = prior !== undefined && !prior.observationMode && prior.runtimeFingerprint === runtimeFingerprint && prior.providerIdentity === providerIdentity;
|
|
166667
|
-
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, features);
|
|
166668
|
-
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || !sameFeatures(prior.features, features) || wiped;
|
|
167850
|
+
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, chunkModelId, features);
|
|
167851
|
+
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || prior.chunkModelId !== chunkModelId || !sameFeatures(prior.features, features) || wiped;
|
|
166669
167852
|
const generation = generationChanged ? ++globalRegistrationGeneration : prior.generation;
|
|
166670
167853
|
const registration = {
|
|
166671
167854
|
projectIdentity,
|
|
@@ -166677,6 +167860,7 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
166677
167860
|
generation,
|
|
166678
167861
|
features: { ...features },
|
|
166679
167862
|
modelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : providerIdentity,
|
|
167863
|
+
chunkModelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : chunkModelId,
|
|
166680
167864
|
observationMode: false
|
|
166681
167865
|
};
|
|
166682
167866
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -166699,6 +167883,7 @@ function registerProjectInObservationMode(db, projectIdentity, sourceDirectory,
|
|
|
166699
167883
|
generation,
|
|
166700
167884
|
features: { memoryEnabled: false, gitCommitEnabled: false },
|
|
166701
167885
|
modelId: "off",
|
|
167886
|
+
chunkModelId: "off",
|
|
166702
167887
|
observationMode: true
|
|
166703
167888
|
};
|
|
166704
167889
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -166709,6 +167894,15 @@ function getProjectEmbeddingSnapshot(projectIdentity) {
|
|
|
166709
167894
|
const registration = projectRegistrations.get(projectIdentity);
|
|
166710
167895
|
return registration ? snapshotFor(registration) : null;
|
|
166711
167896
|
}
|
|
167897
|
+
function getProjectChunkEmbeddingModelId(projectIdentity) {
|
|
167898
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
167899
|
+
return registration && !registration.observationMode ? registration.chunkModelId : "off";
|
|
167900
|
+
}
|
|
167901
|
+
function getProjectEmbeddingMaxInputTokens(projectIdentity) {
|
|
167902
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
167903
|
+
const configMax = registration?.config && "max_input_tokens" in registration.config ? registration.config.max_input_tokens : undefined;
|
|
167904
|
+
return normalizeCompartmentChunkMaxInputTokens(registration?.provider?.maxInputTokens ?? configMax);
|
|
167905
|
+
}
|
|
166712
167906
|
function getOrCreateProjectProvider(registration) {
|
|
166713
167907
|
if (registration.providerIdentity === OFF_PROVIDER_IDENTITY || registration.observationMode) {
|
|
166714
167908
|
return null;
|
|
@@ -166803,6 +167997,131 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
166803
167997
|
return 0;
|
|
166804
167998
|
}
|
|
166805
167999
|
}
|
|
168000
|
+
async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal) {
|
|
168001
|
+
const noWork = [];
|
|
168002
|
+
if (candidates.length === 0)
|
|
168003
|
+
return { embedded: 0, noWork };
|
|
168004
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
|
|
168005
|
+
const prepared = [];
|
|
168006
|
+
for (const candidate of candidates) {
|
|
168007
|
+
const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
|
|
168008
|
+
if (canonicalText.length === 0) {
|
|
168009
|
+
noWork.push(candidate.id);
|
|
168010
|
+
continue;
|
|
168011
|
+
}
|
|
168012
|
+
const windows = chunkCanonicalText(canonicalText, candidate.startMessage, candidate.endMessage, maxInputTokens);
|
|
168013
|
+
if (windows.length === 0 || chunkEmbeddingWindowsAreCurrent(db, candidate.id, modelId, windows, projectIdentity)) {
|
|
168014
|
+
noWork.push(candidate.id);
|
|
168015
|
+
continue;
|
|
168016
|
+
}
|
|
168017
|
+
prepared.push({ candidate, windows });
|
|
168018
|
+
}
|
|
168019
|
+
if (prepared.length === 0)
|
|
168020
|
+
return { embedded: 0, noWork };
|
|
168021
|
+
let embedded = 0;
|
|
168022
|
+
let i = 0;
|
|
168023
|
+
while (i < prepared.length) {
|
|
168024
|
+
if (signal?.aborted)
|
|
168025
|
+
break;
|
|
168026
|
+
const slice = [];
|
|
168027
|
+
let windowCount = 0;
|
|
168028
|
+
do {
|
|
168029
|
+
const item = prepared[i];
|
|
168030
|
+
slice.push(item);
|
|
168031
|
+
windowCount += item.windows.length;
|
|
168032
|
+
i += 1;
|
|
168033
|
+
} while (i < prepared.length && windowCount + prepared[i].windows.length <= MAX_WINDOWS_PER_EMBED_CALL);
|
|
168034
|
+
const texts = [];
|
|
168035
|
+
for (const item of slice)
|
|
168036
|
+
texts.push(...item.windows.map((w) => w.text));
|
|
168037
|
+
try {
|
|
168038
|
+
const result = await embedBatchForProject(projectIdentity, texts, signal);
|
|
168039
|
+
if (!result)
|
|
168040
|
+
continue;
|
|
168041
|
+
if (signal?.aborted)
|
|
168042
|
+
break;
|
|
168043
|
+
let offset = 0;
|
|
168044
|
+
for (const item of slice) {
|
|
168045
|
+
const vectors = result.vectors.slice(offset, offset + item.windows.length);
|
|
168046
|
+
offset += item.windows.length;
|
|
168047
|
+
if (vectors.length !== item.windows.length || vectors.some((v) => !v)) {
|
|
168048
|
+
continue;
|
|
168049
|
+
}
|
|
168050
|
+
const rows = item.windows.map((window, index) => ({
|
|
168051
|
+
compartmentId: item.candidate.id,
|
|
168052
|
+
sessionId: item.candidate.sessionId,
|
|
168053
|
+
projectPath: projectIdentity,
|
|
168054
|
+
window,
|
|
168055
|
+
modelId,
|
|
168056
|
+
vector: vectors[index]
|
|
168057
|
+
}));
|
|
168058
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
168059
|
+
embedded += 1;
|
|
168060
|
+
}
|
|
168061
|
+
} catch (error51) {
|
|
168062
|
+
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
168063
|
+
}
|
|
168064
|
+
}
|
|
168065
|
+
return { embedded, noWork };
|
|
168066
|
+
}
|
|
168067
|
+
async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, options) {
|
|
168068
|
+
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
168069
|
+
if (!snapshot?.enabled || snapshot.chunkModelId === "off") {
|
|
168070
|
+
return { status: "disabled", embedded: 0, total: 0 };
|
|
168071
|
+
}
|
|
168072
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
168073
|
+
const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId);
|
|
168074
|
+
if (total === 0)
|
|
168075
|
+
return { status: "nothing", embedded: 0, total: 0 };
|
|
168076
|
+
const holderId = `session-embed-${randomUUID()}`;
|
|
168077
|
+
const lease2 = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
|
|
168078
|
+
if (!lease2.acquired)
|
|
168079
|
+
return { status: "busy", embedded: 0, total };
|
|
168080
|
+
const renewal = setInterval(() => {
|
|
168081
|
+
try {
|
|
168082
|
+
renewGitSweepLease(db, projectIdentity, holderId);
|
|
168083
|
+
} catch {}
|
|
168084
|
+
}, SESSION_EMBED_LEASE_RENEWAL_MS);
|
|
168085
|
+
renewal.unref?.();
|
|
168086
|
+
const batchSize = Math.max(1, options?.batchSize ?? CHUNK_DRAIN_BATCH_SIZE);
|
|
168087
|
+
const skipIds = [];
|
|
168088
|
+
let embedded = 0;
|
|
168089
|
+
let aborted2 = false;
|
|
168090
|
+
let providerStalled = false;
|
|
168091
|
+
try {
|
|
168092
|
+
options?.onProgress?.({ embedded, total });
|
|
168093
|
+
for (;; ) {
|
|
168094
|
+
if (options?.signal?.aborted) {
|
|
168095
|
+
aborted2 = true;
|
|
168096
|
+
break;
|
|
168097
|
+
}
|
|
168098
|
+
const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, skipIds);
|
|
168099
|
+
if (candidates.length === 0)
|
|
168100
|
+
break;
|
|
168101
|
+
const { embedded: n, noWork } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, options?.signal);
|
|
168102
|
+
for (const id of noWork)
|
|
168103
|
+
skipIds.push(id);
|
|
168104
|
+
if (n === 0 && noWork.length === 0) {
|
|
168105
|
+
providerStalled = true;
|
|
168106
|
+
break;
|
|
168107
|
+
}
|
|
168108
|
+
embedded += n;
|
|
168109
|
+
options?.onProgress?.({ embedded: Math.min(embedded, total), total });
|
|
168110
|
+
await new Promise((resolve4) => setTimeout(resolve4, 0));
|
|
168111
|
+
}
|
|
168112
|
+
} finally {
|
|
168113
|
+
clearInterval(renewal);
|
|
168114
|
+
releaseGitSweepLease(db, projectIdentity, holderId);
|
|
168115
|
+
}
|
|
168116
|
+
if (aborted2)
|
|
168117
|
+
return { status: "aborted", embedded, total };
|
|
168118
|
+
if (providerStalled) {
|
|
168119
|
+
const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId) - skipIds.length);
|
|
168120
|
+
if (remaining > 0)
|
|
168121
|
+
return { status: "stalled", embedded, total, remaining };
|
|
168122
|
+
}
|
|
168123
|
+
return { status: "done", embedded, total };
|
|
168124
|
+
}
|
|
166806
168125
|
|
|
166807
168126
|
// ../plugin/src/features/magic-context/memory/embedding.ts
|
|
166808
168127
|
var DEFAULT_EMBEDDING_CONFIG = {
|
|
@@ -166822,10 +168141,11 @@ function createProvider2(config2) {
|
|
|
166822
168141
|
model: config2.model,
|
|
166823
168142
|
apiKey: config2.api_key,
|
|
166824
168143
|
inputType: config2.input_type,
|
|
166825
|
-
truncate: config2.truncate
|
|
168144
|
+
truncate: config2.truncate,
|
|
168145
|
+
maxInputTokens: config2.max_input_tokens
|
|
166826
168146
|
});
|
|
166827
168147
|
}
|
|
166828
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
168148
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
166829
168149
|
}
|
|
166830
168150
|
function getOrCreateProvider() {
|
|
166831
168151
|
if (provider) {
|
|
@@ -167068,6 +168388,7 @@ init_logger();
|
|
|
167068
168388
|
// ../plugin/src/features/magic-context/memory/storage-memory-fts.ts
|
|
167069
168389
|
var DEFAULT_SEARCH_LIMIT = 10;
|
|
167070
168390
|
var searchStatements = new WeakMap;
|
|
168391
|
+
var unionSearchStatements = new Map;
|
|
167071
168392
|
function getSearchStatement(db) {
|
|
167072
168393
|
let stmt = searchStatements.get(db);
|
|
167073
168394
|
if (!stmt) {
|
|
@@ -167076,6 +168397,23 @@ function getSearchStatement(db) {
|
|
|
167076
168397
|
}
|
|
167077
168398
|
return stmt;
|
|
167078
168399
|
}
|
|
168400
|
+
function getUnionSearchStatement(db, arity) {
|
|
168401
|
+
let statements = unionSearchStatements.get(arity);
|
|
168402
|
+
if (!statements) {
|
|
168403
|
+
statements = new WeakMap;
|
|
168404
|
+
unionSearchStatements.set(arity, statements);
|
|
168405
|
+
}
|
|
168406
|
+
let stmt = statements.get(db);
|
|
168407
|
+
if (!stmt) {
|
|
168408
|
+
const placeholders3 = Array.from({ length: arity }, () => "?").join(", ");
|
|
168409
|
+
stmt = db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories_fts INNER JOIN memories ON memories.id = memories_fts.rowid WHERE memories.project_path IN (${placeholders3}) 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 ?`);
|
|
168410
|
+
statements.set(db, stmt);
|
|
168411
|
+
}
|
|
168412
|
+
return stmt;
|
|
168413
|
+
}
|
|
168414
|
+
function uniqueProjectPaths2(projectPaths) {
|
|
168415
|
+
return [...new Set(projectPaths.filter((path7) => path7.length > 0))];
|
|
168416
|
+
}
|
|
167079
168417
|
function sanitizeFtsQuery(query) {
|
|
167080
168418
|
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
167081
168419
|
if (tokens.length === 0)
|
|
@@ -167094,6 +168432,28 @@ function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT)
|
|
|
167094
168432
|
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
167095
168433
|
return rows.map(toMemory);
|
|
167096
168434
|
}
|
|
168435
|
+
function searchMemoriesFTSUnion(db, projectPaths, query, limit = DEFAULT_SEARCH_LIMIT, ownIdentities, shareCategories) {
|
|
168436
|
+
const identities = uniqueProjectPaths2(projectPaths);
|
|
168437
|
+
if (identities.length === 0)
|
|
168438
|
+
return [];
|
|
168439
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
168440
|
+
identities,
|
|
168441
|
+
ownIdentities,
|
|
168442
|
+
shareCategories,
|
|
168443
|
+
tableName: "memories"
|
|
168444
|
+
});
|
|
168445
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
168446
|
+
return searchMemoriesFTS(db, identities[0], query, limit);
|
|
168447
|
+
}
|
|
168448
|
+
const trimmedQuery = query.trim();
|
|
168449
|
+
if (trimmedQuery.length === 0 || limit <= 0)
|
|
168450
|
+
return [];
|
|
168451
|
+
const sanitized = sanitizeFtsQuery(trimmedQuery);
|
|
168452
|
+
if (sanitized.length === 0)
|
|
168453
|
+
return [];
|
|
168454
|
+
const rows = sharingFilter.active ? db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories_fts INNER JOIN memories ON memories.id = memories_fts.rowid WHERE memories.project_path IN (${identities.map(() => "?").join(", ")}) AND memories.status IN ('active', 'permanent') AND (memories.expires_at IS NULL OR memories.expires_at > ?) AND memories_fts MATCH ?${sharingFilter.clause} ORDER BY bm25(memories_fts), memories.updated_at DESC, memories.id ASC LIMIT ?`).all(...identities, Date.now(), sanitized, ...sharingFilter.params, limit).filter(isMemoryRow) : getUnionSearchStatement(db, identities.length).all(...identities, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
168455
|
+
return rows.map(toMemory);
|
|
168456
|
+
}
|
|
167097
168457
|
|
|
167098
168458
|
// ../plugin/src/features/magic-context/git-commits/search-git-commits.ts
|
|
167099
168459
|
var ftsStatements = new WeakMap;
|
|
@@ -167386,7 +168746,7 @@ async function sweepGitCommits(args) {
|
|
|
167386
168746
|
}
|
|
167387
168747
|
|
|
167388
168748
|
// ../plugin/src/plugin/embedding-bootstrap-helpers.ts
|
|
167389
|
-
import { createHash as
|
|
168749
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
167390
168750
|
init_logger();
|
|
167391
168751
|
var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
167392
168752
|
"embedding.api_key",
|
|
@@ -167408,7 +168768,7 @@ var EMBEDDING_WARNING_TERMS = [
|
|
|
167408
168768
|
];
|
|
167409
168769
|
var loggedFailureSignatures = new Map;
|
|
167410
168770
|
function sha256Prefix2(value, length = 16) {
|
|
167411
|
-
return
|
|
168771
|
+
return createHash10("sha256").update(value).digest("hex").slice(0, length);
|
|
167412
168772
|
}
|
|
167413
168773
|
function warningLooksEmbeddingRelated(message) {
|
|
167414
168774
|
const lower = message.toLowerCase();
|
|
@@ -168450,6 +169810,88 @@ function registerCtxDreamCommand(pi, deps) {
|
|
|
168450
169810
|
});
|
|
168451
169811
|
}
|
|
168452
169812
|
|
|
169813
|
+
// src/commands/ctx-embed-history.ts
|
|
169814
|
+
function registerCtxEmbedHistoryCommand(pi, deps) {
|
|
169815
|
+
pi.registerCommand("ctx-embed-history", {
|
|
169816
|
+
description: "Embed all of this session's history compartments for semantic search, in one pass",
|
|
169817
|
+
handler: async (_args, ctx) => {
|
|
169818
|
+
const sessionId = resolveSessionId(ctx);
|
|
169819
|
+
if (!sessionId) {
|
|
169820
|
+
sendCtxStatusMessage(pi, {
|
|
169821
|
+
title: "/ctx-embed-history",
|
|
169822
|
+
text: `## /ctx-embed-history
|
|
169823
|
+
|
|
169824
|
+
No active Pi session is available.`,
|
|
169825
|
+
level: "error"
|
|
169826
|
+
});
|
|
169827
|
+
return;
|
|
169828
|
+
}
|
|
169829
|
+
if (deps.memoryEnabled === false) {
|
|
169830
|
+
sendCtxStatusMessage(pi, {
|
|
169831
|
+
title: "/ctx-embed-history",
|
|
169832
|
+
text: `## /ctx-embed-history
|
|
169833
|
+
|
|
169834
|
+
Memory is disabled for this project, so there is no semantic embedding to backfill.`,
|
|
169835
|
+
level: "info"
|
|
169836
|
+
});
|
|
169837
|
+
return;
|
|
169838
|
+
}
|
|
169839
|
+
const project = deps.resolveProject?.(ctx) ?? {
|
|
169840
|
+
projectDir: deps.projectDir,
|
|
169841
|
+
projectIdentity: deps.projectIdentity
|
|
169842
|
+
};
|
|
169843
|
+
await ensureProjectRegisteredFromPiDirectory(project.projectDir, deps.db);
|
|
169844
|
+
const outcome = await embedSessionCompartmentChunks(deps.db, project.projectIdentity, sessionId);
|
|
169845
|
+
const { text, level } = (() => {
|
|
169846
|
+
switch (outcome.status) {
|
|
169847
|
+
case "nothing":
|
|
169848
|
+
return {
|
|
169849
|
+
text: `## /ctx-embed-history
|
|
169850
|
+
|
|
169851
|
+
All of this session's history is already embedded.`,
|
|
169852
|
+
level: "info"
|
|
169853
|
+
};
|
|
169854
|
+
case "disabled":
|
|
169855
|
+
return {
|
|
169856
|
+
text: `## /ctx-embed-history
|
|
169857
|
+
|
|
169858
|
+
No embedding provider is configured, so there is nothing to embed.`,
|
|
169859
|
+
level: "info"
|
|
169860
|
+
};
|
|
169861
|
+
case "busy":
|
|
169862
|
+
return {
|
|
169863
|
+
text: `## /ctx-embed-history
|
|
169864
|
+
|
|
169865
|
+
Embedding is already running for this project — ${outcome.total} compartment${outcome.total === 1 ? "" : "s"} still pending. Try again shortly.`,
|
|
169866
|
+
level: "info"
|
|
169867
|
+
};
|
|
169868
|
+
case "stalled":
|
|
169869
|
+
return {
|
|
169870
|
+
text: `## /ctx-embed-history
|
|
169871
|
+
|
|
169872
|
+
Embedded ${outcome.embedded} compartment${outcome.embedded === 1 ? "" : "s"}; ${outcome.remaining} could not be embedded (the provider returned no result). Run /ctx-embed-history again to retry them.`,
|
|
169873
|
+
level: "info"
|
|
169874
|
+
};
|
|
169875
|
+
default:
|
|
169876
|
+
return {
|
|
169877
|
+
text: `## /ctx-embed-history
|
|
169878
|
+
|
|
169879
|
+
Embedded ${outcome.embedded} compartment${outcome.embedded === 1 ? "" : "s"} of history for semantic search.`,
|
|
169880
|
+
level: "success"
|
|
169881
|
+
};
|
|
169882
|
+
}
|
|
169883
|
+
})();
|
|
169884
|
+
sendCtxStatusMessage(pi, { title: "/ctx-embed-history", text, level }, {
|
|
169885
|
+
sessionId,
|
|
169886
|
+
projectIdentity: project.projectIdentity,
|
|
169887
|
+
status: outcome.status,
|
|
169888
|
+
embedded: outcome.embedded,
|
|
169889
|
+
total: outcome.total
|
|
169890
|
+
});
|
|
169891
|
+
}
|
|
169892
|
+
});
|
|
169893
|
+
}
|
|
169894
|
+
|
|
168453
169895
|
// ../plugin/src/hooks/magic-context/execute-flush.ts
|
|
168454
169896
|
init_logger();
|
|
168455
169897
|
function executeFlush(db, sessionId) {
|
|
@@ -170585,53 +172027,6 @@ ${body}
|
|
|
170585
172027
|
</system-reminder>`;
|
|
170586
172028
|
}
|
|
170587
172029
|
|
|
170588
|
-
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
170589
|
-
var V2_MEMORY_CATEGORIES = [
|
|
170590
|
-
"PROJECT_RULES",
|
|
170591
|
-
"ARCHITECTURE",
|
|
170592
|
-
"CONSTRAINTS",
|
|
170593
|
-
"CONFIG_VALUES",
|
|
170594
|
-
"NAMING"
|
|
170595
|
-
];
|
|
170596
|
-
var PROMOTABLE_CATEGORIES = [
|
|
170597
|
-
"PROJECT_RULES",
|
|
170598
|
-
"ARCHITECTURE",
|
|
170599
|
-
"CONSTRAINTS",
|
|
170600
|
-
"CONFIG_VALUES",
|
|
170601
|
-
"NAMING",
|
|
170602
|
-
"ARCHITECTURE_DECISIONS",
|
|
170603
|
-
"CONFIG_DEFAULTS",
|
|
170604
|
-
"USER_PREFERENCES",
|
|
170605
|
-
"USER_DIRECTIVES",
|
|
170606
|
-
"ENVIRONMENT",
|
|
170607
|
-
"WORKFLOW_RULES",
|
|
170608
|
-
"KNOWN_ISSUES"
|
|
170609
|
-
];
|
|
170610
|
-
var CATEGORY_PRIORITY = [
|
|
170611
|
-
"PROJECT_RULES",
|
|
170612
|
-
"ARCHITECTURE",
|
|
170613
|
-
"CONSTRAINTS",
|
|
170614
|
-
"CONFIG_VALUES",
|
|
170615
|
-
"NAMING",
|
|
170616
|
-
"USER_DIRECTIVES",
|
|
170617
|
-
"USER_PREFERENCES",
|
|
170618
|
-
"CONFIG_DEFAULTS",
|
|
170619
|
-
"ARCHITECTURE_DECISIONS",
|
|
170620
|
-
"ENVIRONMENT",
|
|
170621
|
-
"WORKFLOW_RULES",
|
|
170622
|
-
"KNOWN_ISSUES"
|
|
170623
|
-
];
|
|
170624
|
-
var MEMORY_CATEGORY_ORDER_UNKNOWN = 99;
|
|
170625
|
-
var MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
170626
|
-
acc[category] = index;
|
|
170627
|
-
return acc;
|
|
170628
|
-
}, {});
|
|
170629
|
-
var MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
170630
|
-
var CATEGORY_DEFAULT_TTL = {
|
|
170631
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
170632
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
170633
|
-
};
|
|
170634
|
-
|
|
170635
172030
|
// ../plugin/src/shared/bounded-session-map.ts
|
|
170636
172031
|
class BoundedSessionMap {
|
|
170637
172032
|
maxEntries;
|
|
@@ -171042,26 +172437,40 @@ ${sections.join(`
|
|
|
171042
172437
|
var DEFAULT_MEMORY_BUDGET_TOKENS = 8000;
|
|
171043
172438
|
var MEMORY_BLOCK_WRAPPER_TOKENS = 6;
|
|
171044
172439
|
var DEFAULT_USER_PROFILE_BUDGET_TOKENS = 4000;
|
|
172440
|
+
function memoryCanonicalIdentity(memory, workspace) {
|
|
172441
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
172442
|
+
}
|
|
172443
|
+
function memorySelectionOrder(left, right) {
|
|
172444
|
+
if (left.status === "permanent" && right.status !== "permanent")
|
|
172445
|
+
return -1;
|
|
172446
|
+
if (right.status === "permanent" && left.status !== "permanent")
|
|
172447
|
+
return 1;
|
|
172448
|
+
const leftImportance = left.importance ?? Number.NEGATIVE_INFINITY;
|
|
172449
|
+
const rightImportance = right.importance ?? Number.NEGATIVE_INFINITY;
|
|
172450
|
+
const importanceDiff = rightImportance - leftImportance;
|
|
172451
|
+
if (importanceDiff !== 0)
|
|
172452
|
+
return importanceDiff;
|
|
172453
|
+
return left.id - right.id;
|
|
172454
|
+
}
|
|
172455
|
+
function memoryRenderOrder(left, right) {
|
|
172456
|
+
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[left.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
172457
|
+
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[right.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
172458
|
+
const categoryDiff = aPriority - bPriority;
|
|
172459
|
+
if (categoryDiff !== 0)
|
|
172460
|
+
return categoryDiff;
|
|
172461
|
+
return left.id - right.id;
|
|
172462
|
+
}
|
|
171045
172463
|
var maxCompartmentSeqStatements = new WeakMap;
|
|
171046
172464
|
var maxMemoryIdStatements = new WeakMap;
|
|
171047
172465
|
var legacyCompartmentCountStatements = new WeakMap;
|
|
171048
172466
|
var m0CompartmentStatements = new WeakMap;
|
|
171049
172467
|
var newCompartmentStatements = new WeakMap;
|
|
171050
|
-
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
171051
|
-
const selectionOrder = [...memories].sort(
|
|
171052
|
-
if (a.status === "permanent" && b.status !== "permanent")
|
|
171053
|
-
return -1;
|
|
171054
|
-
if (b.status === "permanent" && a.status !== "permanent")
|
|
171055
|
-
return 1;
|
|
171056
|
-
const importanceDiff = (b.importance ?? 50) - (a.importance ?? 50);
|
|
171057
|
-
if (importanceDiff !== 0)
|
|
171058
|
-
return importanceDiff;
|
|
171059
|
-
return a.id - b.id;
|
|
171060
|
-
});
|
|
172468
|
+
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions = {}) {
|
|
172469
|
+
const selectionOrder = [...memories].sort(memorySelectionOrder);
|
|
171061
172470
|
const selected = [];
|
|
171062
172471
|
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
171063
172472
|
for (const memory of selectionOrder) {
|
|
171064
|
-
const memoryTokens = estimateTokens(renderMemoryLineV2(memory));
|
|
172473
|
+
const memoryTokens = estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
171065
172474
|
if (usedTokens + memoryTokens > budgetTokens)
|
|
171066
172475
|
continue;
|
|
171067
172476
|
selected.push(memory);
|
|
@@ -171070,16 +172479,70 @@ function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
|
171070
172479
|
if (selected.length < memories.length) {
|
|
171071
172480
|
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
171072
172481
|
}
|
|
171073
|
-
const renderOrder = [...selected].sort(
|
|
171074
|
-
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[a.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
171075
|
-
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[b.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
171076
|
-
const categoryDiff = aPriority - bPriority;
|
|
171077
|
-
if (categoryDiff !== 0)
|
|
171078
|
-
return categoryDiff;
|
|
171079
|
-
return a.id - b.id;
|
|
171080
|
-
});
|
|
172482
|
+
const renderOrder = [...selected].sort(memoryRenderOrder);
|
|
171081
172483
|
return { selected, renderOrder };
|
|
171082
172484
|
}
|
|
172485
|
+
function trimWorkspaceMemoriesToBudgetV2(sessionId, memories, budgetTokens, workspace, renderOptions = {}) {
|
|
172486
|
+
if (!workspace.isWorkspaced) {
|
|
172487
|
+
return trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions);
|
|
172488
|
+
}
|
|
172489
|
+
const selected = [];
|
|
172490
|
+
const selectedIds = new Set;
|
|
172491
|
+
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
172492
|
+
const tokenCost = (memory) => estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
172493
|
+
const trySelect = (memory) => {
|
|
172494
|
+
if (selectedIds.has(memory.id))
|
|
172495
|
+
return false;
|
|
172496
|
+
const tokens = tokenCost(memory);
|
|
172497
|
+
if (usedTokens + tokens > budgetTokens)
|
|
172498
|
+
return false;
|
|
172499
|
+
selected.push(memory);
|
|
172500
|
+
selectedIds.add(memory.id);
|
|
172501
|
+
usedTokens += tokens;
|
|
172502
|
+
return true;
|
|
172503
|
+
};
|
|
172504
|
+
for (const memory of memories.filter((candidate) => candidate.status === "permanent").sort(memorySelectionOrder)) {
|
|
172505
|
+
trySelect(memory);
|
|
172506
|
+
}
|
|
172507
|
+
const remainingAfterPermanent = Math.max(0, budgetTokens - usedTokens);
|
|
172508
|
+
const floorTokens = remainingAfterPermanent / Math.max(1, workspace.identities.length);
|
|
172509
|
+
const byIdentity = new Map;
|
|
172510
|
+
for (const memory of memories) {
|
|
172511
|
+
if (memory.status === "permanent")
|
|
172512
|
+
continue;
|
|
172513
|
+
const identity = memoryCanonicalIdentity(memory, workspace);
|
|
172514
|
+
if (!identity)
|
|
172515
|
+
continue;
|
|
172516
|
+
const list = byIdentity.get(identity) ?? [];
|
|
172517
|
+
list.push(memory);
|
|
172518
|
+
byIdentity.set(identity, list);
|
|
172519
|
+
}
|
|
172520
|
+
for (const identity of workspace.identities) {
|
|
172521
|
+
let memberTokens = 0;
|
|
172522
|
+
const candidates = (byIdentity.get(identity) ?? []).sort(memorySelectionOrder);
|
|
172523
|
+
for (const memory of candidates) {
|
|
172524
|
+
if (selectedIds.has(memory.id))
|
|
172525
|
+
continue;
|
|
172526
|
+
const tokens = tokenCost(memory);
|
|
172527
|
+
if (memberTokens + tokens > floorTokens)
|
|
172528
|
+
continue;
|
|
172529
|
+
if (usedTokens + tokens > budgetTokens)
|
|
172530
|
+
continue;
|
|
172531
|
+
selected.push(memory);
|
|
172532
|
+
selectedIds.add(memory.id);
|
|
172533
|
+
usedTokens += tokens;
|
|
172534
|
+
memberTokens += tokens;
|
|
172535
|
+
}
|
|
172536
|
+
}
|
|
172537
|
+
const remaining = memories.filter((memory) => !selectedIds.has(memory.id)).sort(memorySelectionOrder);
|
|
172538
|
+
for (const memory of remaining) {
|
|
172539
|
+
trySelect(memory);
|
|
172540
|
+
}
|
|
172541
|
+
if (selected.length < memories.length) {
|
|
172542
|
+
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
172543
|
+
}
|
|
172544
|
+
return { selected, renderOrder: [...selected].sort(memoryRenderOrder) };
|
|
172545
|
+
}
|
|
171083
172546
|
function trimUserMemoriesToBudget(memories, budgetTokens) {
|
|
171084
172547
|
const selected = [];
|
|
171085
172548
|
let usedTokens = 0;
|
|
@@ -171092,15 +172555,16 @@ function trimUserMemoriesToBudget(memories, budgetTokens) {
|
|
|
171092
172555
|
}
|
|
171093
172556
|
return selected;
|
|
171094
172557
|
}
|
|
171095
|
-
function renderMemoryLineV2(memory) {
|
|
171096
|
-
|
|
172558
|
+
function renderMemoryLineV2(memory, sourceName) {
|
|
172559
|
+
const sourceAttr = sourceName ? ` source="${escapeXmlAttr(sourceName)}"` : "";
|
|
172560
|
+
return ` <memory id="${memory.id}" category="${escapeXmlAttr(memory.category)}"${sourceAttr} importance="${memory.importance ?? 50}">${escapeXmlContent(memory.content)}</memory>`;
|
|
171097
172561
|
}
|
|
171098
|
-
function renderMemoryBlockV2(memories, wrapper = "project-memory") {
|
|
172562
|
+
function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions = {}) {
|
|
171099
172563
|
if (memories.length === 0)
|
|
171100
172564
|
return "";
|
|
171101
172565
|
const lines = [`<${wrapper}>`];
|
|
171102
172566
|
for (const memory of memories) {
|
|
171103
|
-
lines.push(renderMemoryLineV2(memory));
|
|
172567
|
+
lines.push(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
171104
172568
|
}
|
|
171105
172569
|
lines.push(`</${wrapper}>`);
|
|
171106
172570
|
return lines.join(`
|
|
@@ -171694,7 +173158,7 @@ async function ensureMemoryEmbeddings(args) {
|
|
|
171694
173158
|
continue;
|
|
171695
173159
|
}
|
|
171696
173160
|
saveEmbedding(args.db, memory.id, embedding, result.modelId);
|
|
171697
|
-
staged.set(memory.id, embedding);
|
|
173161
|
+
staged.set(memory.id, { embedding, modelId: result.modelId });
|
|
171698
173162
|
}
|
|
171699
173163
|
})();
|
|
171700
173164
|
const currentSnapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -171785,6 +173249,37 @@ function previewText(text) {
|
|
|
171785
173249
|
}
|
|
171786
173250
|
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}…`;
|
|
171787
173251
|
}
|
|
173252
|
+
function resolveSearchWorkspaceContext(db, projectPath, identitySet) {
|
|
173253
|
+
const resolved = identitySet ?? resolveWorkspaceIdentitySet(db, projectPath);
|
|
173254
|
+
const isWorkspaced = resolved.identities.length > 1;
|
|
173255
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(db, resolved.identities);
|
|
173256
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : resolved.identities;
|
|
173257
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(resolved.identities.map((identity) => [identity, identity]));
|
|
173258
|
+
const ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === projectPath);
|
|
173259
|
+
return {
|
|
173260
|
+
identities: resolved.identities,
|
|
173261
|
+
expandedIdentities,
|
|
173262
|
+
ownIdentities,
|
|
173263
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(db, projectPath) : null,
|
|
173264
|
+
namesByIdentity: resolved.namesByIdentity,
|
|
173265
|
+
canonicalIdentityByStoredPath,
|
|
173266
|
+
isWorkspaced
|
|
173267
|
+
};
|
|
173268
|
+
}
|
|
173269
|
+
function memoryWorkspaceIdentity(memory, workspace) {
|
|
173270
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
173271
|
+
}
|
|
173272
|
+
function sourceNamesForSearchMemories(args) {
|
|
173273
|
+
if (!args.workspace.isWorkspaced)
|
|
173274
|
+
return;
|
|
173275
|
+
const sourceNames = new Map;
|
|
173276
|
+
for (const memory of args.memories) {
|
|
173277
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
173278
|
+
if (source)
|
|
173279
|
+
sourceNames.set(memory.id, source);
|
|
173280
|
+
}
|
|
173281
|
+
return sourceNames.size > 0 ? sourceNames : undefined;
|
|
173282
|
+
}
|
|
171788
173283
|
function getMessageSearchStatement(db) {
|
|
171789
173284
|
let stmt = messageSearchStatements.get(db);
|
|
171790
173285
|
if (!stmt) {
|
|
@@ -171793,6 +173288,30 @@ function getMessageSearchStatement(db) {
|
|
|
171793
173288
|
}
|
|
171794
173289
|
return stmt;
|
|
171795
173290
|
}
|
|
173291
|
+
var ftsRowCountStatements = new WeakMap;
|
|
173292
|
+
var ftsMatchCountStatements = new WeakMap;
|
|
173293
|
+
function getSessionFtsRowCount(db, sessionId) {
|
|
173294
|
+
let stmt = ftsRowCountStatements.get(db);
|
|
173295
|
+
if (!stmt) {
|
|
173296
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ?");
|
|
173297
|
+
ftsRowCountStatements.set(db, stmt);
|
|
173298
|
+
}
|
|
173299
|
+
const row = stmt.get(sessionId);
|
|
173300
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
173301
|
+
}
|
|
173302
|
+
function countSessionFtsMatches(db, sessionId, ftsQuery) {
|
|
173303
|
+
let stmt = ftsMatchCountStatements.get(db);
|
|
173304
|
+
if (!stmt) {
|
|
173305
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ?");
|
|
173306
|
+
ftsMatchCountStatements.set(db, stmt);
|
|
173307
|
+
}
|
|
173308
|
+
try {
|
|
173309
|
+
const row = stmt.get(sessionId, ftsQuery);
|
|
173310
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
173311
|
+
} catch {
|
|
173312
|
+
return 0;
|
|
173313
|
+
}
|
|
173314
|
+
}
|
|
171796
173315
|
function getMessageOrdinal(value) {
|
|
171797
173316
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
171798
173317
|
return value;
|
|
@@ -171808,25 +173327,63 @@ async function getSemanticScores(args) {
|
|
|
171808
173327
|
if (!args.queryEmbedding || args.memories.length === 0) {
|
|
171809
173328
|
return semanticScores;
|
|
171810
173329
|
}
|
|
171811
|
-
|
|
171812
|
-
|
|
171813
|
-
|
|
171814
|
-
|
|
171815
|
-
|
|
171816
|
-
|
|
171817
|
-
|
|
173330
|
+
if (!args.workspace?.isWorkspaced) {
|
|
173331
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
173332
|
+
const embeddings = await ensureMemoryEmbeddings({
|
|
173333
|
+
db: args.db,
|
|
173334
|
+
projectIdentity: args.projectPath,
|
|
173335
|
+
memories: args.memories,
|
|
173336
|
+
existingEmbeddings: cachedEmbeddings
|
|
173337
|
+
});
|
|
173338
|
+
for (const memory of args.memories) {
|
|
173339
|
+
const memoryEmbedding = embeddings.get(memory.id);
|
|
173340
|
+
if (!memoryEmbedding) {
|
|
173341
|
+
continue;
|
|
173342
|
+
}
|
|
173343
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
173344
|
+
}
|
|
173345
|
+
return semanticScores;
|
|
173346
|
+
}
|
|
173347
|
+
if (!args.queryModelId || args.queryModelId === "off") {
|
|
173348
|
+
return semanticScores;
|
|
173349
|
+
}
|
|
173350
|
+
const workspace = args.workspace;
|
|
173351
|
+
const memoriesByIdentity = new Map;
|
|
171818
173352
|
for (const memory of args.memories) {
|
|
171819
|
-
const
|
|
171820
|
-
if (!
|
|
173353
|
+
const identity = memoryWorkspaceIdentity(memory, workspace);
|
|
173354
|
+
if (!identity)
|
|
171821
173355
|
continue;
|
|
173356
|
+
const list = memoriesByIdentity.get(identity) ?? [];
|
|
173357
|
+
list.push(memory);
|
|
173358
|
+
memoriesByIdentity.set(identity, list);
|
|
173359
|
+
}
|
|
173360
|
+
const ownMemories = memoriesByIdentity.get(args.projectPath) ?? [];
|
|
173361
|
+
if (ownMemories.length > 0) {
|
|
173362
|
+
const ownEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
173363
|
+
await ensureMemoryEmbeddings({
|
|
173364
|
+
db: args.db,
|
|
173365
|
+
projectIdentity: args.projectPath,
|
|
173366
|
+
memories: ownMemories,
|
|
173367
|
+
existingEmbeddings: ownEmbeddings
|
|
173368
|
+
});
|
|
173369
|
+
}
|
|
173370
|
+
for (const identity of workspace.identities) {
|
|
173371
|
+
const memberMemories = memoriesByIdentity.get(identity) ?? [];
|
|
173372
|
+
if (memberMemories.length === 0)
|
|
173373
|
+
continue;
|
|
173374
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, identity);
|
|
173375
|
+
for (const memory of memberMemories) {
|
|
173376
|
+
const memoryEmbedding = cachedEmbeddings.get(memory.id);
|
|
173377
|
+
if (!memoryEmbedding || memoryEmbedding.modelId !== args.queryModelId)
|
|
173378
|
+
continue;
|
|
173379
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
171822
173380
|
}
|
|
171823
|
-
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
|
|
171824
173381
|
}
|
|
171825
173382
|
return semanticScores;
|
|
171826
173383
|
}
|
|
171827
173384
|
function getFtsMatches(args) {
|
|
171828
173385
|
try {
|
|
171829
|
-
return searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
173386
|
+
return args.workspace?.isWorkspaced ? searchMemoriesFTSUnion(args.db, args.workspace.expandedIdentities, args.query, args.limit, args.workspace.ownIdentities, args.workspace.shareCategories) : searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
171830
173387
|
} catch (error51) {
|
|
171831
173388
|
log(`[search] FTS query failed for "${args.query}": ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
171832
173389
|
return [];
|
|
@@ -171840,8 +173397,11 @@ function selectSemanticCandidates(args) {
|
|
|
171840
173397
|
return args.memories;
|
|
171841
173398
|
}
|
|
171842
173399
|
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
171843
|
-
const
|
|
171844
|
-
|
|
173400
|
+
const embeddingProjects = args.workspace?.isWorkspaced ? args.workspace.identities : [args.projectPath];
|
|
173401
|
+
for (const projectPath of embeddingProjects) {
|
|
173402
|
+
const cachedEmbeddings = peekProjectEmbeddings(projectPath);
|
|
173403
|
+
if (!cachedEmbeddings)
|
|
173404
|
+
continue;
|
|
171845
173405
|
for (const memoryId of cachedEmbeddings.keys()) {
|
|
171846
173406
|
candidateIds.add(memoryId);
|
|
171847
173407
|
}
|
|
@@ -171883,7 +173443,8 @@ function mergeMemoryResults(args) {
|
|
|
171883
173443
|
score,
|
|
171884
173444
|
memoryId: memory.id,
|
|
171885
173445
|
category: memory.category,
|
|
171886
|
-
matchType
|
|
173446
|
+
matchType,
|
|
173447
|
+
sourceName: args.sourceNameByMemoryId?.get(memory.id)
|
|
171887
173448
|
});
|
|
171888
173449
|
}
|
|
171889
173450
|
return results.sort((left, right) => {
|
|
@@ -171897,7 +173458,7 @@ async function searchMemories(args) {
|
|
|
171897
173458
|
if (!args.memoryEnabled) {
|
|
171898
173459
|
return [];
|
|
171899
173460
|
}
|
|
171900
|
-
const memories = getMemoriesByProject(args.db, args.projectPath);
|
|
173461
|
+
const memories = args.workspace?.isWorkspaced ? getMemoriesByProjects(args.db, args.workspace.expandedIdentities, ["active", "permanent"], Date.now(), args.workspace.ownIdentities, args.workspace.shareCategories) : getMemoriesByProject(args.db, args.projectPath);
|
|
171901
173462
|
if (memories.length === 0) {
|
|
171902
173463
|
return [];
|
|
171903
173464
|
}
|
|
@@ -171905,26 +173466,43 @@ async function searchMemories(args) {
|
|
|
171905
173466
|
db: args.db,
|
|
171906
173467
|
projectPath: args.projectPath,
|
|
171907
173468
|
query: args.query,
|
|
171908
|
-
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
173469
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT,
|
|
173470
|
+
workspace: args.workspace
|
|
171909
173471
|
});
|
|
171910
173472
|
const ftsScores = getFtsScores(ftsMatches);
|
|
171911
173473
|
const semanticCandidates = selectSemanticCandidates({
|
|
171912
173474
|
memories,
|
|
171913
173475
|
projectPath: args.projectPath,
|
|
171914
|
-
ftsMatches
|
|
173476
|
+
ftsMatches,
|
|
173477
|
+
workspace: args.workspace
|
|
171915
173478
|
});
|
|
171916
173479
|
const semanticScores = await getSemanticScores({
|
|
171917
173480
|
db: args.db,
|
|
171918
173481
|
projectPath: args.projectPath,
|
|
171919
173482
|
memories: semanticCandidates,
|
|
171920
|
-
queryEmbedding: args.queryEmbedding
|
|
173483
|
+
queryEmbedding: args.queryEmbedding,
|
|
173484
|
+
queryModelId: args.queryModelId,
|
|
173485
|
+
workspace: args.workspace
|
|
171921
173486
|
});
|
|
171922
173487
|
return mergeMemoryResults({
|
|
171923
173488
|
memories,
|
|
171924
173489
|
semanticScores,
|
|
171925
173490
|
ftsScores,
|
|
171926
173491
|
limit: args.limit,
|
|
171927
|
-
visibleMemoryIds: args.visibleMemoryIds
|
|
173492
|
+
visibleMemoryIds: args.visibleMemoryIds,
|
|
173493
|
+
sourceNameByMemoryId: sourceNamesForSearchMemories({
|
|
173494
|
+
memories,
|
|
173495
|
+
projectPath: args.projectPath,
|
|
173496
|
+
workspace: args.workspace ?? {
|
|
173497
|
+
identities: [args.projectPath],
|
|
173498
|
+
expandedIdentities: [args.projectPath],
|
|
173499
|
+
namesByIdentity: new Map,
|
|
173500
|
+
canonicalIdentityByStoredPath: new Map([[args.projectPath, args.projectPath]]),
|
|
173501
|
+
ownIdentities: [args.projectPath],
|
|
173502
|
+
shareCategories: null,
|
|
173503
|
+
isWorkspaced: false
|
|
173504
|
+
}
|
|
173505
|
+
})
|
|
171928
173506
|
});
|
|
171929
173507
|
}
|
|
171930
173508
|
function linearDecayScore(rank, total) {
|
|
@@ -171955,7 +173533,13 @@ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
|
|
|
171955
173533
|
return result;
|
|
171956
173534
|
}
|
|
171957
173535
|
var RRF_K = 60;
|
|
171958
|
-
var
|
|
173536
|
+
var VERBATIM_RANK_BONUS = 1 / RRF_K;
|
|
173537
|
+
var IDF_FALLOFF = 100;
|
|
173538
|
+
function probeDiscriminationWeight(df, corpusSize) {
|
|
173539
|
+
if (corpusSize <= 0 || df <= 0)
|
|
173540
|
+
return 1;
|
|
173541
|
+
return 1 / (1 + IDF_FALLOFF * df / corpusSize);
|
|
173542
|
+
}
|
|
171959
173543
|
function searchMessages(args) {
|
|
171960
173544
|
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
171961
173545
|
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
@@ -171972,20 +173556,31 @@ function searchMessages(args) {
|
|
|
171972
173556
|
role: row.role
|
|
171973
173557
|
}));
|
|
171974
173558
|
}
|
|
173559
|
+
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId);
|
|
171975
173560
|
const queryLists = [];
|
|
171976
173561
|
if (baseQuery.length > 0) {
|
|
171977
|
-
queryLists.push(
|
|
173562
|
+
queryLists.push({
|
|
173563
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff),
|
|
173564
|
+
weight: 1
|
|
173565
|
+
});
|
|
171978
173566
|
}
|
|
173567
|
+
const probeWeights = new Map;
|
|
171979
173568
|
for (const probe of probes) {
|
|
171980
173569
|
const probeQuery = sanitizeFtsQuery(probe);
|
|
171981
173570
|
if (probeQuery.length === 0)
|
|
171982
173571
|
continue;
|
|
171983
|
-
|
|
173572
|
+
const df = countSessionFtsMatches(args.db, args.sessionId, probeQuery);
|
|
173573
|
+
const weight = probeDiscriminationWeight(df, corpusSize);
|
|
173574
|
+
probeWeights.set(probe, weight);
|
|
173575
|
+
queryLists.push({
|
|
173576
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff),
|
|
173577
|
+
weight
|
|
173578
|
+
});
|
|
171984
173579
|
}
|
|
171985
173580
|
const fused = new Map;
|
|
171986
173581
|
for (const list of queryLists) {
|
|
171987
|
-
list.forEach((row, rank) => {
|
|
171988
|
-
const rrf =
|
|
173582
|
+
list.rows.forEach((row, rank) => {
|
|
173583
|
+
const rrf = list.weight / (RRF_K + rank);
|
|
171989
173584
|
const existing = fused.get(row.messageId);
|
|
171990
173585
|
if (existing) {
|
|
171991
173586
|
existing.score += rrf;
|
|
@@ -171995,26 +173590,107 @@ function searchMessages(args) {
|
|
|
171995
173590
|
});
|
|
171996
173591
|
}
|
|
171997
173592
|
for (const entry of fused.values()) {
|
|
171998
|
-
|
|
171999
|
-
|
|
173593
|
+
let best = 0;
|
|
173594
|
+
for (const probe of probes) {
|
|
173595
|
+
const weight = probeWeights.get(probe) ?? 0;
|
|
173596
|
+
if (weight > best && containsProbeVerbatim(entry.row.content, [probe])) {
|
|
173597
|
+
best = weight;
|
|
173598
|
+
}
|
|
173599
|
+
}
|
|
173600
|
+
if (best > 0) {
|
|
173601
|
+
entry.score += best * VERBATIM_RANK_BONUS;
|
|
172000
173602
|
}
|
|
172001
173603
|
}
|
|
172002
173604
|
const ranked = [...fused.values()].sort((a, b) => b.score !== a.score ? b.score - a.score : a.row.messageOrdinal - b.row.messageOrdinal).slice(0, args.limit);
|
|
172003
|
-
|
|
172004
|
-
return ranked.map((entry) => ({
|
|
173605
|
+
return ranked.map((entry, rank) => ({
|
|
172005
173606
|
source: "message",
|
|
172006
173607
|
content: previewText(entry.row.content),
|
|
172007
|
-
score:
|
|
173608
|
+
score: linearDecayScore(rank, ranked.length),
|
|
172008
173609
|
messageOrdinal: entry.row.messageOrdinal,
|
|
172009
173610
|
messageId: entry.row.messageId,
|
|
172010
173611
|
role: entry.row.role
|
|
172011
173612
|
}));
|
|
172012
173613
|
}
|
|
173614
|
+
function searchCompartmentChunks(args) {
|
|
173615
|
+
if (!args.queryEmbedding || args.limit <= 0)
|
|
173616
|
+
return [];
|
|
173617
|
+
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
173618
|
+
const rows = loadCompartmentChunkEmbeddingsForSearch(args.db, args.sessionId, args.projectPath, args.modelId);
|
|
173619
|
+
if (rows.length === 0)
|
|
173620
|
+
return [];
|
|
173621
|
+
const byCompartment = new Map;
|
|
173622
|
+
for (const row of rows) {
|
|
173623
|
+
if (cutoff !== null && row.endOrdinal > cutoff) {
|
|
173624
|
+
continue;
|
|
173625
|
+
}
|
|
173626
|
+
const score = normalizeCosineScore(cosineSimilarity(args.queryEmbedding, row.vector));
|
|
173627
|
+
if (score <= 0)
|
|
173628
|
+
continue;
|
|
173629
|
+
const existing = byCompartment.get(row.compartmentId);
|
|
173630
|
+
if (!existing || score > existing.score) {
|
|
173631
|
+
byCompartment.set(row.compartmentId, { row, score });
|
|
173632
|
+
}
|
|
173633
|
+
}
|
|
173634
|
+
return [...byCompartment.values()].sort((left, right) => right.score !== left.score ? right.score - left.score : left.row.startOrdinal - right.row.startOrdinal).slice(0, args.limit).map(({ row, score }) => ({
|
|
173635
|
+
source: "compartment",
|
|
173636
|
+
content: previewText(row.title),
|
|
173637
|
+
score: score * SINGLE_SOURCE_PENALTY,
|
|
173638
|
+
compartmentId: row.compartmentId,
|
|
173639
|
+
sessionId: row.sessionId,
|
|
173640
|
+
title: row.title,
|
|
173641
|
+
startOrdinal: row.startOrdinal,
|
|
173642
|
+
endOrdinal: row.endOrdinal,
|
|
173643
|
+
matchType: "semantic"
|
|
173644
|
+
}));
|
|
173645
|
+
}
|
|
173646
|
+
function mergeMessageAndCompartmentResults(args) {
|
|
173647
|
+
if (args.compartments.length === 0)
|
|
173648
|
+
return args.messages;
|
|
173649
|
+
if (args.messages.length === 0)
|
|
173650
|
+
return args.compartments;
|
|
173651
|
+
const fused = new Map;
|
|
173652
|
+
const add = (key, result, score, tieOrdinal) => {
|
|
173653
|
+
const existing = fused.get(key);
|
|
173654
|
+
if (existing) {
|
|
173655
|
+
existing.score += score;
|
|
173656
|
+
return existing;
|
|
173657
|
+
}
|
|
173658
|
+
const entry = { result, score, tieOrdinal, snippetScore: -1 };
|
|
173659
|
+
fused.set(key, entry);
|
|
173660
|
+
return entry;
|
|
173661
|
+
};
|
|
173662
|
+
args.compartments.forEach((compartment, rank) => {
|
|
173663
|
+
add(`compartment:${compartment.compartmentId}`, compartment, 1 / (RRF_K + rank), compartment.startOrdinal);
|
|
173664
|
+
});
|
|
173665
|
+
for (const [rank, message] of args.messages.entries()) {
|
|
173666
|
+
const containing = args.compartments.find((compartment) => message.messageOrdinal >= compartment.startOrdinal && message.messageOrdinal <= compartment.endOrdinal);
|
|
173667
|
+
const contribution = 1 / (RRF_K + rank);
|
|
173668
|
+
if (!containing) {
|
|
173669
|
+
add(`message:${message.messageId}`, message, contribution, message.messageOrdinal);
|
|
173670
|
+
continue;
|
|
173671
|
+
}
|
|
173672
|
+
const entry = add(`compartment:${containing.compartmentId}`, containing, contribution, containing.startOrdinal);
|
|
173673
|
+
if (message.score > entry.snippetScore && entry.result.source === "compartment") {
|
|
173674
|
+
entry.snippetScore = message.score;
|
|
173675
|
+
entry.result = {
|
|
173676
|
+
...entry.result,
|
|
173677
|
+
matchType: "hybrid",
|
|
173678
|
+
snippet: message.content
|
|
173679
|
+
};
|
|
173680
|
+
}
|
|
173681
|
+
}
|
|
173682
|
+
const ranked = [...fused.values()].sort((left, right) => right.score !== left.score ? right.score - left.score : left.tieOrdinal - right.tieOrdinal).slice(0, args.limit);
|
|
173683
|
+
return ranked.map((entry, rank) => ({
|
|
173684
|
+
...entry.result,
|
|
173685
|
+
score: linearDecayScore(rank, ranked.length)
|
|
173686
|
+
}));
|
|
173687
|
+
}
|
|
172013
173688
|
function getSourceBoost(result) {
|
|
172014
173689
|
switch (result.source) {
|
|
172015
173690
|
case "memory":
|
|
172016
173691
|
return MEMORY_SOURCE_BOOST;
|
|
172017
173692
|
case "message":
|
|
173693
|
+
case "compartment":
|
|
172018
173694
|
return MESSAGE_SOURCE_BOOST;
|
|
172019
173695
|
case "git_commit":
|
|
172020
173696
|
return GIT_COMMIT_SOURCE_BOOST;
|
|
@@ -172032,6 +173708,9 @@ function compareUnifiedResults(left, right) {
|
|
|
172032
173708
|
if (left.source === "message" && right.source === "message") {
|
|
172033
173709
|
return left.messageOrdinal - right.messageOrdinal;
|
|
172034
173710
|
}
|
|
173711
|
+
if (left.source === "compartment" && right.source === "compartment") {
|
|
173712
|
+
return left.startOrdinal - right.startOrdinal;
|
|
173713
|
+
}
|
|
172035
173714
|
if (left.source === "git_commit" && right.source === "git_commit") {
|
|
172036
173715
|
return right.committedAtMs - left.committedAtMs;
|
|
172037
173716
|
}
|
|
@@ -172082,10 +173761,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172082
173761
|
const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
|
|
172083
173762
|
const gitCommitsEnabled = options.gitCommitsEnabled ?? false;
|
|
172084
173763
|
const activeSources = resolveSources(options.sources);
|
|
172085
|
-
const
|
|
173764
|
+
const memoryFeatureEnabled = options.memoryEnabled ?? true;
|
|
173765
|
+
const runMemory = activeSources.has("memory") && memoryFeatureEnabled;
|
|
172086
173766
|
const runMessages = activeSources.has("message");
|
|
172087
173767
|
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
172088
|
-
const
|
|
173768
|
+
const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
|
|
173769
|
+
const needsEmbedding = (runMemory || runGitCommits || runCompartmentChunks) && embeddingEnabled && isEmbeddingRuntimeEnabled();
|
|
172089
173770
|
const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error51) => {
|
|
172090
173771
|
log(`[search] query embedding failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
172091
173772
|
return null;
|
|
@@ -172101,6 +173782,24 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172101
173782
|
probes: messageProbes
|
|
172102
173783
|
}) : [];
|
|
172103
173784
|
const queryEmbedding = await queryEmbeddingPromise;
|
|
173785
|
+
const workspace = resolveSearchWorkspaceContext(db, projectPath);
|
|
173786
|
+
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
173787
|
+
const embeddingModelId = embeddingSnapshot?.modelId;
|
|
173788
|
+
const chunkModelId = embeddingSnapshot?.chunkModelId;
|
|
173789
|
+
const compartmentResults = runCompartmentChunks ? searchCompartmentChunks({
|
|
173790
|
+
db,
|
|
173791
|
+
sessionId,
|
|
173792
|
+
projectPath,
|
|
173793
|
+
queryEmbedding,
|
|
173794
|
+
limit: tierLimit,
|
|
173795
|
+
maxOrdinal: options.maxMessageOrdinal,
|
|
173796
|
+
modelId: chunkModelId && chunkModelId !== "off" ? chunkModelId : null
|
|
173797
|
+
}) : [];
|
|
173798
|
+
const messageLikeResults = mergeMessageAndCompartmentResults({
|
|
173799
|
+
messages: messageResults,
|
|
173800
|
+
compartments: compartmentResults,
|
|
173801
|
+
limit: tierLimit
|
|
173802
|
+
});
|
|
172104
173803
|
const [memoryResults, gitCommitResults] = await Promise.all([
|
|
172105
173804
|
runMemory ? searchMemories({
|
|
172106
173805
|
db,
|
|
@@ -172109,6 +173808,8 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172109
173808
|
limit: tierLimit,
|
|
172110
173809
|
memoryEnabled: true,
|
|
172111
173810
|
queryEmbedding,
|
|
173811
|
+
queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null,
|
|
173812
|
+
workspace,
|
|
172112
173813
|
visibleMemoryIds: options.visibleMemoryIds
|
|
172113
173814
|
}) : Promise.resolve([]),
|
|
172114
173815
|
runGitCommits ? Promise.resolve(searchGitCommits({
|
|
@@ -172119,7 +173820,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172119
173820
|
queryEmbedding
|
|
172120
173821
|
})) : Promise.resolve([])
|
|
172121
173822
|
]);
|
|
172122
|
-
const results = [...memoryResults, ...
|
|
173823
|
+
const results = [...memoryResults, ...messageLikeResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
|
|
172123
173824
|
const countRetrievals = options.countRetrievals ?? true;
|
|
172124
173825
|
if (countRetrievals) {
|
|
172125
173826
|
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
@@ -172179,6 +173880,11 @@ function renderFragment(result, charCap) {
|
|
|
172179
173880
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
172180
173881
|
return truncate(compressed, charCap);
|
|
172181
173882
|
}
|
|
173883
|
+
case "compartment": {
|
|
173884
|
+
const source = result.snippet ?? result.title;
|
|
173885
|
+
const compressed = cavemanCompress(source, "ultra");
|
|
173886
|
+
return truncate(compressed, charCap);
|
|
173887
|
+
}
|
|
172182
173888
|
}
|
|
172183
173889
|
}
|
|
172184
173890
|
function buildAutoSearchHint(results, options = {}) {
|
|
@@ -173602,6 +175308,49 @@ function safeGetActiveUserMemoriesPi(db) {
|
|
|
173602
175308
|
function memoryProjectPath(state) {
|
|
173603
175309
|
return state.memoryEnabled === false ? undefined : state.projectIdentity;
|
|
173604
175310
|
}
|
|
175311
|
+
function resolveWorkspaceRenderContextPi(state, db) {
|
|
175312
|
+
const memPath = memoryProjectPath(state);
|
|
175313
|
+
if (!memPath) {
|
|
175314
|
+
return {
|
|
175315
|
+
identities: [],
|
|
175316
|
+
expandedIdentities: [],
|
|
175317
|
+
ownIdentities: [],
|
|
175318
|
+
shareCategories: null,
|
|
175319
|
+
namesByIdentity: new Map,
|
|
175320
|
+
canonicalIdentityByStoredPath: new Map,
|
|
175321
|
+
isWorkspaced: false
|
|
175322
|
+
};
|
|
175323
|
+
}
|
|
175324
|
+
const identitySet = resolveWorkspaceIdentitySet(db, memPath);
|
|
175325
|
+
const isWorkspaced = identitySet.identities.length > 1;
|
|
175326
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(db, identitySet.identities);
|
|
175327
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : identitySet.identities;
|
|
175328
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(identitySet.identities.map((identity) => [identity, identity]));
|
|
175329
|
+
let ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === memPath);
|
|
175330
|
+
if (ownIdentities.length === 0 && expandedIdentities.includes(memPath)) {
|
|
175331
|
+
ownIdentities = [memPath];
|
|
175332
|
+
}
|
|
175333
|
+
return {
|
|
175334
|
+
identities: identitySet.identities,
|
|
175335
|
+
expandedIdentities,
|
|
175336
|
+
ownIdentities,
|
|
175337
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(db, memPath) : null,
|
|
175338
|
+
namesByIdentity: identitySet.namesByIdentity,
|
|
175339
|
+
canonicalIdentityByStoredPath,
|
|
175340
|
+
isWorkspaced
|
|
175341
|
+
};
|
|
175342
|
+
}
|
|
175343
|
+
function sourceNamesForPiMemories(args) {
|
|
175344
|
+
if (!args.projectPath || !args.workspace.isWorkspaced)
|
|
175345
|
+
return;
|
|
175346
|
+
const names = new Map;
|
|
175347
|
+
for (const memory of args.memories) {
|
|
175348
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
175349
|
+
if (source)
|
|
175350
|
+
names.set(memory.id, source);
|
|
175351
|
+
}
|
|
175352
|
+
return names.size > 0 ? names : undefined;
|
|
175353
|
+
}
|
|
173605
175354
|
var EMPTY_PI_HARD_SIGNALS = {
|
|
173606
175355
|
systemHash: "",
|
|
173607
175356
|
modelKey: "",
|
|
@@ -173649,6 +175398,7 @@ function getCachedMarkers(db, state, compartmentsForNormalization) {
|
|
|
173649
175398
|
maxMutationId: meta3.cachedM0MaxMutationId,
|
|
173650
175399
|
maxMemoryMutationId: meta3.cachedM0MaxMemoryMutationId,
|
|
173651
175400
|
projectMemoryEpoch: meta3.cachedM0ProjectMemoryEpoch,
|
|
175401
|
+
workspaceFingerprint: meta3.cachedM0WorkspaceFingerprint,
|
|
173652
175402
|
projectUserProfileVersion: meta3.cachedM0ProjectUserProfileVersion,
|
|
173653
175403
|
projectDocsHash: meta3.cachedM0ProjectDocsHash,
|
|
173654
175404
|
sessionFactsVersion: meta3.cachedM0SessionFactsVersion,
|
|
@@ -173668,15 +175418,17 @@ function readCurrentMarkers(db, state, projectDocsHash) {
|
|
|
173668
175418
|
}
|
|
173669
175419
|
function readCurrentMarkersFromCompartments(db, state, compartments, projectDocsHash) {
|
|
173670
175420
|
const memPath = memoryProjectPath(state);
|
|
173671
|
-
const
|
|
175421
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
175422
|
+
const maxMemoryId = memPath ? workspace.isWorkspaced ? getMaxMemoryIdForProjects(db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryIdForProjects(db, [memPath]) : 0;
|
|
173672
175423
|
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
173673
175424
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
173674
175425
|
return {
|
|
173675
175426
|
maxCompartmentSeq: compartments.length > 0 ? compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ) : EMPTY_MAX_COMPARTMENT_SEQ,
|
|
173676
|
-
maxMemoryId
|
|
175427
|
+
maxMemoryId,
|
|
173677
175428
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
173678
|
-
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
175429
|
+
maxMemoryMutationId: memPath ? workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(db, workspace.expandedIdentities) ?? 0 : getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
173679
175430
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
175431
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(db, workspace.identities) : null,
|
|
173680
175432
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
173681
175433
|
projectDocsHash: projectDocsHash ?? readProjectDocsCanonical(state.projectDirectory).canonicalHash,
|
|
173682
175434
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
@@ -173714,10 +175466,11 @@ function mustMaterializePi(state, db, currentCompartmentsOverride) {
|
|
|
173714
175466
|
if (meta3.cachedM0UpgradeState !== current.upgradeState) {
|
|
173715
175467
|
return { value: true, reason: "renderer_upgrade" };
|
|
173716
175468
|
}
|
|
173717
|
-
if (current.
|
|
173718
|
-
|
|
173719
|
-
|
|
173720
|
-
|
|
175469
|
+
if (current.workspaceFingerprint !== null || (meta3.cachedM0WorkspaceFingerprint ?? null) !== null) {
|
|
175470
|
+
if (current.workspaceFingerprint !== (meta3.cachedM0WorkspaceFingerprint ?? null)) {
|
|
175471
|
+
return { value: true, reason: "project_memory_change" };
|
|
175472
|
+
}
|
|
175473
|
+
} else if (current.projectMemoryEpoch !== (meta3.cachedM0ProjectMemoryEpoch ?? 0)) {
|
|
173721
175474
|
return { value: true, reason: "project_memory_change" };
|
|
173722
175475
|
}
|
|
173723
175476
|
if (current.maxMutationId !== (meta3.cachedM0MaxMutationId ?? 0)) {
|
|
@@ -173734,11 +175487,19 @@ ${memories.map((memory) => `- ${escapeXmlContent(memory.content)}`).join(`
|
|
|
173734
175487
|
`)}
|
|
173735
175488
|
</${wrapper}>`;
|
|
173736
175489
|
}
|
|
173737
|
-
function renderM0Pi(state, db, projectDocs = readProjectDocsCanonical(state.projectDirectory).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride) {
|
|
175490
|
+
function renderM0Pi(state, db, projectDocs = readProjectDocsCanonical(state.projectDirectory).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride, workspaceOverride) {
|
|
173738
175491
|
const memPath = memoryProjectPath(state);
|
|
173739
|
-
const
|
|
173740
|
-
const
|
|
173741
|
-
const
|
|
175492
|
+
const workspace = workspaceOverride ?? resolveWorkspaceRenderContextPi(state, db);
|
|
175493
|
+
const allMemories = memoriesOverride ?? (memPath ? workspace.isWorkspaced ? getMemoriesByProjects(db, workspace.expandedIdentities, ["active", "permanent"], Date.now(), workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(db, memPath, ["active", "permanent"]) : []);
|
|
175494
|
+
const memoryRenderOptions = {
|
|
175495
|
+
sourceNameByMemoryId: sourceNamesForPiMemories({
|
|
175496
|
+
memories: allMemories,
|
|
175497
|
+
projectPath: memPath,
|
|
175498
|
+
workspace
|
|
175499
|
+
})
|
|
175500
|
+
};
|
|
175501
|
+
const memories = allMemories.length > 0 ? workspace.isWorkspaced ? trimWorkspaceMemoriesToBudgetV2(state.sessionId, allMemories, state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS, workspace, memoryRenderOptions).renderOrder : trimMemoriesToBudgetV2(state.sessionId, allMemories, state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS).renderOrder : allMemories;
|
|
175502
|
+
const memoryBlock = memories.length > 0 ? renderMemoryBlockV2(memories, "project-memory", memoryRenderOptions) : undefined;
|
|
173742
175503
|
const baseHistoryBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173743
175504
|
const decayed = renderDecayedCompartments({
|
|
173744
175505
|
compartments: compartmentsOverride ?? getCompartments(db, state.sessionId),
|
|
@@ -173760,10 +175521,19 @@ ${decayed}
|
|
|
173760
175521
|
|
|
173761
175522
|
`).trim();
|
|
173762
175523
|
}
|
|
173763
|
-
function renderedMemoryIdsForPi(state, memories) {
|
|
175524
|
+
function renderedMemoryIdsForPi(state, memories, workspace, db) {
|
|
173764
175525
|
if (memories.length === 0)
|
|
173765
175526
|
return [];
|
|
173766
|
-
|
|
175527
|
+
const resolvedWorkspace = workspace ?? (db ? resolveWorkspaceRenderContextPi(state, db) : undefined);
|
|
175528
|
+
const renderOptions = resolvedWorkspace ? {
|
|
175529
|
+
sourceNameByMemoryId: sourceNamesForPiMemories({
|
|
175530
|
+
memories,
|
|
175531
|
+
projectPath: memoryProjectPath(state),
|
|
175532
|
+
workspace: resolvedWorkspace
|
|
175533
|
+
})
|
|
175534
|
+
} : {};
|
|
175535
|
+
const trimmed = resolvedWorkspace?.isWorkspaced ? trimWorkspaceMemoriesToBudgetV2(state.sessionId, [...memories], state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS, resolvedWorkspace, renderOptions) : trimMemoriesToBudgetV2(state.sessionId, [...memories], state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS);
|
|
175536
|
+
return trimmed.renderOrder.map((memory) => memory.id);
|
|
173767
175537
|
}
|
|
173768
175538
|
function isTransientSqliteLockError(error51) {
|
|
173769
175539
|
if (!error51 || typeof error51 !== "object")
|
|
@@ -173788,17 +175558,19 @@ class PiMaterializeContentionError extends Error {
|
|
|
173788
175558
|
function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.projectDirectory), memoryCutoff) {
|
|
173789
175559
|
const memPath = memoryProjectPath(state);
|
|
173790
175560
|
const read = db.transaction(() => {
|
|
175561
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
173791
175562
|
const compartments = getCompartments(db, state.sessionId);
|
|
173792
|
-
const memories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], memoryCutoff) : [];
|
|
175563
|
+
const memories = memPath ? workspace.isWorkspaced ? getMemoriesByProjects(db, workspace.expandedIdentities, ["active", "permanent"], memoryCutoff, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(db, memPath, ["active", "permanent"], memoryCutoff) : [];
|
|
173793
175564
|
const userProfile = safeGetActiveUserMemoriesPi(db);
|
|
173794
175565
|
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
173795
175566
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
173796
175567
|
const markers = {
|
|
173797
175568
|
maxCompartmentSeq: compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ),
|
|
173798
|
-
maxMemoryId:
|
|
175569
|
+
maxMemoryId: memPath ? workspace.isWorkspaced ? getMaxMemoryIdForProjects(db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryIdForProjects(db, [memPath]) : 0,
|
|
173799
175570
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
173800
|
-
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
175571
|
+
maxMemoryMutationId: memPath ? workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(db, workspace.expandedIdentities) ?? 0 : getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
173801
175572
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
175573
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(db, workspace.identities) : null,
|
|
173802
175574
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
173803
175575
|
projectDocsHash: docs.canonicalHash,
|
|
173804
175576
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
@@ -173808,7 +175580,7 @@ function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.p
|
|
|
173808
175580
|
systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
|
|
173809
175581
|
modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey
|
|
173810
175582
|
};
|
|
173811
|
-
return { docs, markers, compartments, memories, userProfile };
|
|
175583
|
+
return { docs, markers, compartments, memories, userProfile, workspace };
|
|
173812
175584
|
});
|
|
173813
175585
|
return read();
|
|
173814
175586
|
}
|
|
@@ -173819,17 +175591,17 @@ function renderFreshM0PiNonPersisted(state, db) {
|
|
|
173819
175591
|
frozen.markers.materializedAt = cachedMaterializedAt;
|
|
173820
175592
|
const historyBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173821
175593
|
let dpm = 1;
|
|
173822
|
-
let m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile);
|
|
175594
|
+
let m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile, frozen.workspace);
|
|
173823
175595
|
let attempts = 0;
|
|
173824
175596
|
while (historyBudget > 0 && historySliceTokensPi(m0) > historyBudget * 1.05 && attempts < 3) {
|
|
173825
175597
|
dpm *= 1.15;
|
|
173826
|
-
m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile);
|
|
175598
|
+
m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile, frozen.workspace);
|
|
173827
175599
|
attempts += 1;
|
|
173828
175600
|
}
|
|
173829
175601
|
return {
|
|
173830
175602
|
m0,
|
|
173831
175603
|
snapshotMarkers: frozen.markers,
|
|
173832
|
-
renderedMemoryIds: renderedMemoryIdsForPi(state, frozen.memories)
|
|
175604
|
+
renderedMemoryIds: renderedMemoryIdsForPi(state, frozen.memories, frozen.workspace, db)
|
|
173833
175605
|
};
|
|
173834
175606
|
}
|
|
173835
175607
|
function materializeM0Pi(state, db) {
|
|
@@ -173839,14 +175611,14 @@ function materializeM0Pi(state, db) {
|
|
|
173839
175611
|
const snapshotMemories = frozen.memories;
|
|
173840
175612
|
const snapshotCompartments = frozen.compartments;
|
|
173841
175613
|
const snapshotUserProfile = frozen.userProfile;
|
|
173842
|
-
const renderedMemoryIds = renderedMemoryIdsForPi(state, snapshotMemories);
|
|
175614
|
+
const renderedMemoryIds = renderedMemoryIdsForPi(state, snapshotMemories, frozen.workspace, db);
|
|
173843
175615
|
let decayPressureMultiplier = 1;
|
|
173844
|
-
let m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile);
|
|
175616
|
+
let m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile, frozen.workspace);
|
|
173845
175617
|
const historyBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173846
175618
|
let attempts = 0;
|
|
173847
175619
|
while (historyBudget > 0 && historySliceTokensPi(m0) > historyBudget * 1.05 && attempts < 3) {
|
|
173848
175620
|
decayPressureMultiplier *= 1.15;
|
|
173849
|
-
m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile);
|
|
175621
|
+
m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile, frozen.workspace);
|
|
173850
175622
|
attempts += 1;
|
|
173851
175623
|
}
|
|
173852
175624
|
const m0Bytes = Buffer.from(m0, "utf8");
|
|
@@ -173862,7 +175634,8 @@ function materializeM0Pi(state, db) {
|
|
|
173862
175634
|
}
|
|
173863
175635
|
try {
|
|
173864
175636
|
const current = readCurrentMarkers(db, state, phase3ProjectDocsHash);
|
|
173865
|
-
const
|
|
175637
|
+
const memoryEpochStale = current.workspaceFingerprint !== null || snapshotMarkers.workspaceFingerprint !== null ? current.workspaceFingerprint !== snapshotMarkers.workspaceFingerprint : current.projectMemoryEpoch !== snapshotMarkers.projectMemoryEpoch;
|
|
175638
|
+
const stale = memoryEpochStale || current.projectUserProfileVersion !== snapshotMarkers.projectUserProfileVersion || current.maxCompartmentSeq !== snapshotMarkers.maxCompartmentSeq || current.maxMutationId !== snapshotMarkers.maxMutationId || current.maxMemoryMutationId !== snapshotMarkers.maxMemoryMutationId || current.sessionFactsVersion !== snapshotMarkers.sessionFactsVersion || current.upgradeState !== snapshotMarkers.upgradeState;
|
|
173866
175639
|
if (stale) {
|
|
173867
175640
|
db.exec("ROLLBACK");
|
|
173868
175641
|
throw new PiMaterializeContentionError("snapshot changed before persist");
|
|
@@ -173873,6 +175646,7 @@ function materializeM0Pi(state, db) {
|
|
|
173873
175646
|
persistCachedM0(db, state.sessionId, {
|
|
173874
175647
|
m0Bytes,
|
|
173875
175648
|
projectMemoryEpoch: snapshotMarkers.projectMemoryEpoch,
|
|
175649
|
+
workspaceFingerprint: snapshotMarkers.workspaceFingerprint,
|
|
173876
175650
|
projectUserProfileVersion: snapshotMarkers.projectUserProfileVersion,
|
|
173877
175651
|
maxCompartmentSeq: snapshotMarkers.maxCompartmentSeq,
|
|
173878
175652
|
maxMemoryId: snapshotMarkers.maxMemoryId,
|
|
@@ -173937,7 +175711,7 @@ function renderMemoryUpdatesBlockPi(args) {
|
|
|
173937
175711
|
if (args.renderedMemoryIds.length === 0)
|
|
173938
175712
|
return { block: "", count: 0 };
|
|
173939
175713
|
const renderedIds = new Set(args.renderedMemoryIds);
|
|
173940
|
-
const mutations = getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
175714
|
+
const mutations = args.workspace.isWorkspaced ? getMemoryMutationsForRenderByProjects(args.db, args.workspace.expandedIdentities, args.afterId, args.renderedMemoryIds) : getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
173941
175715
|
if (mutations.length === 0)
|
|
173942
175716
|
return { block: "", count: 0 };
|
|
173943
175717
|
const lines = [
|
|
@@ -173968,6 +175742,7 @@ ${lines.join(`
|
|
|
173968
175742
|
}
|
|
173969
175743
|
function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRenderedKeyFilesBlock, compartmentsOverride) {
|
|
173970
175744
|
const sections = [];
|
|
175745
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
173971
175746
|
const keyFiles = renderedKeyFilesBlockPi(state, db, preRenderedKeyFilesBlock);
|
|
173972
175747
|
if (keyFiles)
|
|
173973
175748
|
sections.push(keyFiles);
|
|
@@ -173975,6 +175750,7 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
|
|
|
173975
175750
|
const memoryUpdates = memPath ? renderMemoryUpdatesBlockPi({
|
|
173976
175751
|
db,
|
|
173977
175752
|
projectPath: memPath,
|
|
175753
|
+
workspace,
|
|
173978
175754
|
afterId: markers.maxMemoryMutationId,
|
|
173979
175755
|
renderedMemoryIds
|
|
173980
175756
|
}) : { block: undefined, count: 0 };
|
|
@@ -173989,11 +175765,18 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
|
|
|
173989
175765
|
${body}
|
|
173990
175766
|
</new-compartments>`);
|
|
173991
175767
|
}
|
|
173992
|
-
const newMemories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], markers.materializedAt).filter((memory) => memory.id > markers.maxMemoryId) : [];
|
|
175768
|
+
const newMemories = memPath ? workspace.isWorkspaced ? readNewMemoriesForM1Union(db, workspace.expandedIdentities, markers.maxMemoryId, markers.materializedAt, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(db, memPath, ["active", "permanent"], markers.materializedAt).filter((memory) => memory.id > markers.maxMemoryId) : [];
|
|
173993
175769
|
if (newMemories.length > 0) {
|
|
173994
175770
|
const memoryBudget = state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
173995
|
-
const
|
|
173996
|
-
|
|
175771
|
+
const memoryRenderOptions = {
|
|
175772
|
+
sourceNameByMemoryId: sourceNamesForPiMemories({
|
|
175773
|
+
memories: newMemories,
|
|
175774
|
+
projectPath: memPath,
|
|
175775
|
+
workspace
|
|
175776
|
+
})
|
|
175777
|
+
};
|
|
175778
|
+
const trimmedNewMemories = trimMemoriesToBudgetV2(state.sessionId, newMemories, Math.max(1, Math.floor(memoryBudget * 0.25)), memoryRenderOptions).renderOrder;
|
|
175779
|
+
const newMemoriesBlock = renderMemoryBlockV2(trimmedNewMemories, "new-memories", memoryRenderOptions);
|
|
173997
175780
|
if (newMemoriesBlock)
|
|
173998
175781
|
sections.push(newMemoriesBlock);
|
|
173999
175782
|
}
|
|
@@ -174042,6 +175825,7 @@ function parseMemoryBlockIds(raw) {
|
|
|
174042
175825
|
function readCachedPiM0M1Row(db, sessionId) {
|
|
174043
175826
|
return db.prepare(`SELECT cached_m0_bytes, cached_m1_bytes,
|
|
174044
175827
|
cached_m0_project_memory_epoch,
|
|
175828
|
+
cached_m0_workspace_fingerprint,
|
|
174045
175829
|
cached_m0_project_user_profile_version,
|
|
174046
175830
|
cached_m0_max_compartment_seq,
|
|
174047
175831
|
cached_m0_max_memory_id,
|
|
@@ -174085,6 +175869,7 @@ function markersFromCachedPiRow(row, compartmentsForNormalization) {
|
|
|
174085
175869
|
maxMutationId: row.cached_m0_max_mutation_id,
|
|
174086
175870
|
maxMemoryMutationId: row.cached_m0_max_memory_mutation_id,
|
|
174087
175871
|
projectMemoryEpoch: row.cached_m0_project_memory_epoch,
|
|
175872
|
+
workspaceFingerprint: row.cached_m0_workspace_fingerprint,
|
|
174088
175873
|
projectUserProfileVersion: row.cached_m0_project_user_profile_version,
|
|
174089
175874
|
projectDocsHash: row.cached_m0_project_docs_hash ?? "",
|
|
174090
175875
|
materializedAt: row.cached_m0_materialized_at,
|
|
@@ -174099,7 +175884,7 @@ function cachedPiRowMatchesSnapshot(args) {
|
|
|
174099
175884
|
const rowMarkers = markersFromCachedPiRow(args.row, args.compartmentsForNormalization);
|
|
174100
175885
|
if (!rowMarkers)
|
|
174101
175886
|
return false;
|
|
174102
|
-
return bufferEqualsNullable(args.row.cached_m0_bytes, args.m0Bytes) && rowMarkers.projectMemoryEpoch === args.markers.projectMemoryEpoch && rowMarkers.projectUserProfileVersion === args.markers.projectUserProfileVersion && rowMarkers.maxCompartmentSeq === args.markers.maxCompartmentSeq && rowMarkers.maxMemoryId === args.markers.maxMemoryId && rowMarkers.maxMutationId === args.markers.maxMutationId && rowMarkers.maxMemoryMutationId === args.markers.maxMemoryMutationId &&
|
|
175887
|
+
return bufferEqualsNullable(args.row.cached_m0_bytes, args.m0Bytes) && rowMarkers.projectMemoryEpoch === args.markers.projectMemoryEpoch && rowMarkers.projectUserProfileVersion === args.markers.projectUserProfileVersion && rowMarkers.maxCompartmentSeq === args.markers.maxCompartmentSeq && rowMarkers.maxMemoryId === args.markers.maxMemoryId && rowMarkers.maxMutationId === args.markers.maxMutationId && rowMarkers.maxMemoryMutationId === args.markers.maxMemoryMutationId && rowMarkers.materializedAt === args.markers.materializedAt && rowMarkers.sessionFactsVersion === args.markers.sessionFactsVersion && (rowMarkers.upgradeState ?? null) === (args.markers.upgradeState ?? null) && (rowMarkers.systemHash ?? "") === (args.markers.systemHash ?? "") && (rowMarkers.modelKey ?? "") === (args.markers.modelKey ?? "") && (rowMarkers.workspaceFingerprint ?? null) === (args.markers.workspaceFingerprint ?? null);
|
|
174103
175888
|
}
|
|
174104
175889
|
function decodeCachedM1(row, sessionId) {
|
|
174105
175890
|
if (!row.cached_m1_bytes) {
|
|
@@ -174310,14 +176095,14 @@ function injectM0M1Pi(state, db, piMessages, entryIds, recomputeM1ThisPass = fal
|
|
|
174310
176095
|
const skippedVisibleMessages = boundaryId ? trimPiMessagesToBoundary(piMessages, entryIds, boundaryId) : 0;
|
|
174311
176096
|
prependM0M1Messages(piMessages, m0, m1);
|
|
174312
176097
|
sessionLog(state.sessionId, `injected m[0]/m[1] into Pi messages (${m0.length} + ${m1.length} bytes, materialized=${materialized}${decision.reason ? ` reason=${decision.reason}` : ""})`);
|
|
176098
|
+
const memPath = memoryProjectPath(state);
|
|
176099
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
176100
|
+
const memoryCount = memPath ? workspace.isWorkspaced ? getMemoriesByProjects(db, workspace.expandedIdentities, ["active", "permanent"], Date.now(), workspace.ownIdentities, workspace.shareCategories).length : getMemoriesByProject(db, memPath, ["active", "permanent"]).length : 0;
|
|
174313
176101
|
return {
|
|
174314
176102
|
injected: true,
|
|
174315
176103
|
compartmentCount: getCompartments(db, state.sessionId).length,
|
|
174316
176104
|
factCount: 0,
|
|
174317
|
-
memoryCount
|
|
174318
|
-
"active",
|
|
174319
|
-
"permanent"
|
|
174320
|
-
]).length : 0,
|
|
176105
|
+
memoryCount,
|
|
174321
176106
|
skippedVisibleMessages,
|
|
174322
176107
|
m0Materialized: materialized,
|
|
174323
176108
|
m0Reason: decision.reason,
|
|
@@ -174378,21 +176163,48 @@ import * as crypto2 from "node:crypto";
|
|
|
174378
176163
|
|
|
174379
176164
|
// ../plugin/src/features/magic-context/compartment-embedding.ts
|
|
174380
176165
|
init_logger();
|
|
174381
|
-
async function
|
|
176166
|
+
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
174382
176167
|
if (compartments.length === 0)
|
|
174383
176168
|
return;
|
|
174384
|
-
const
|
|
174385
|
-
for (const
|
|
174386
|
-
if (!c.p1 || c.p1.length === 0)
|
|
174387
|
-
continue;
|
|
176169
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
176170
|
+
for (const compartment of compartments) {
|
|
174388
176171
|
try {
|
|
174389
|
-
const
|
|
174390
|
-
|
|
174391
|
-
|
|
174392
|
-
|
|
176172
|
+
const fromMemory = compartment.sourceChunkText ? canonicalizeInMemoryChunkTextForEmbedding(compartment.sourceChunkText, compartment.startMessage, compartment.endMessage) : "";
|
|
176173
|
+
const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage);
|
|
176174
|
+
if (canonicalText.length === 0)
|
|
176175
|
+
continue;
|
|
176176
|
+
const windows = chunkCanonicalText(canonicalText, compartment.startMessage, compartment.endMessage, maxInputTokens);
|
|
176177
|
+
if (windows.length === 0)
|
|
176178
|
+
continue;
|
|
176179
|
+
const currentModelId = getProjectChunkEmbeddingModelId(projectPath);
|
|
176180
|
+
if (currentModelId !== "off" && chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
176181
|
+
continue;
|
|
176182
|
+
}
|
|
176183
|
+
const result = await embedBatchForProject(projectPath, windows.map((window) => window.text));
|
|
176184
|
+
if (!result)
|
|
176185
|
+
continue;
|
|
176186
|
+
if (chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
176187
|
+
continue;
|
|
176188
|
+
}
|
|
176189
|
+
const rows = [];
|
|
176190
|
+
for (const [index, window] of windows.entries()) {
|
|
176191
|
+
const vector = result.vectors[index];
|
|
176192
|
+
if (!vector)
|
|
176193
|
+
continue;
|
|
176194
|
+
rows.push({
|
|
176195
|
+
compartmentId: compartment.id,
|
|
176196
|
+
sessionId,
|
|
176197
|
+
projectPath,
|
|
176198
|
+
window,
|
|
176199
|
+
modelId: currentModelId,
|
|
176200
|
+
vector
|
|
176201
|
+
});
|
|
176202
|
+
}
|
|
176203
|
+
if (rows.length === windows.length) {
|
|
176204
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
174393
176205
|
}
|
|
174394
176206
|
} catch (error51) {
|
|
174395
|
-
sessionLog(sessionId, `compartment embedding failed for compartment ${
|
|
176207
|
+
sessionLog(sessionId, `compartment chunk embedding failed for compartment ${compartment.id}:`, error51);
|
|
174396
176208
|
}
|
|
174397
176209
|
}
|
|
174398
176210
|
}
|
|
@@ -177461,6 +179273,7 @@ async function runPiHistorian(deps) {
|
|
|
177461
179273
|
fallbackModels,
|
|
177462
179274
|
historianChunkTokens,
|
|
177463
179275
|
boundarySnapshot: providedBoundarySnapshot,
|
|
179276
|
+
refreshBoundarySnapshot,
|
|
177464
179277
|
currentContextLimit,
|
|
177465
179278
|
historianTimeoutMs = DEFAULT_HISTORIAN_TIMEOUT_MS2,
|
|
177466
179279
|
twoPass,
|
|
@@ -177514,16 +179327,29 @@ async function runPiHistorian(deps) {
|
|
|
177514
179327
|
return;
|
|
177515
179328
|
}
|
|
177516
179329
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
177517
|
-
|
|
179330
|
+
let boundarySnapshot = providedBoundarySnapshot ?? null;
|
|
177518
179331
|
if (!boundarySnapshot) {
|
|
177519
179332
|
sessionLog(sessionId, "historian no-op: missing protected-tail boundary snapshot from Pi trigger decision");
|
|
177520
179333
|
return;
|
|
177521
179334
|
}
|
|
177522
|
-
|
|
179335
|
+
let validation = boundarySnapshot.rawRangeFingerprint.length > 0 ? validateBoundarySnapshot({
|
|
177523
179336
|
db,
|
|
177524
179337
|
snapshot: boundarySnapshot,
|
|
177525
179338
|
currentContextLimit: currentContextLimit ?? boundarySnapshot.contextLimit
|
|
177526
179339
|
}) : { ok: true };
|
|
179340
|
+
if (!validation.ok && validation.reason === "stale_snapshot" && refreshBoundarySnapshot) {
|
|
179341
|
+
try {
|
|
179342
|
+
const refreshed = refreshBoundarySnapshot();
|
|
179343
|
+
if (hasRunnableCompartmentWindow(refreshed)) {
|
|
179344
|
+
sessionLog(sessionId, `historian: refreshed stale protected-tail snapshot at run time (was: ${validation.detail ?? "stale"}) — eligible head ${refreshed.offset}-${refreshed.eligibleEndOrdinal - 1}`);
|
|
179345
|
+
boundarySnapshot = refreshed;
|
|
179346
|
+
validation = { ok: true };
|
|
179347
|
+
}
|
|
179348
|
+
} catch (error51) {
|
|
179349
|
+
const desc = describeError(error51);
|
|
179350
|
+
sessionLog(sessionId, `historian: failed to refresh stale protected-tail snapshot at run time (${validation.detail ?? "stale"}): ${desc.brief}`);
|
|
179351
|
+
}
|
|
179352
|
+
}
|
|
177527
179353
|
if (!validation.ok) {
|
|
177528
179354
|
sessionLog(sessionId, `historian no-op: stale protected-tail snapshot (${validation.detail ?? validation.reason ?? "unknown"})`);
|
|
177529
179355
|
return;
|
|
@@ -177852,8 +179678,13 @@ ${chunkText}`,
|
|
|
177852
179678
|
}
|
|
177853
179679
|
}
|
|
177854
179680
|
if (embeddingActive) {
|
|
177855
|
-
const
|
|
177856
|
-
|
|
179681
|
+
const chunksToEmbed = newCompartments.map((c, i) => ({
|
|
179682
|
+
id: persistedIds[i],
|
|
179683
|
+
startMessage: c.startMessage,
|
|
179684
|
+
endMessage: c.endMessage,
|
|
179685
|
+
sourceChunkText: chunk.text
|
|
179686
|
+
})).filter((c) => typeof c.id === "number");
|
|
179687
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectPath, chunksToEmbed);
|
|
177857
179688
|
}
|
|
177858
179689
|
onPublished?.();
|
|
177859
179690
|
completedSuccessfully = true;
|
|
@@ -178401,7 +180232,7 @@ function stripPiDroppedPlaceholderMessages(args) {
|
|
|
178401
180232
|
}
|
|
178402
180233
|
|
|
178403
180234
|
// src/system-prompt.ts
|
|
178404
|
-
import { createHash as
|
|
180235
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
178405
180236
|
|
|
178406
180237
|
// ../plugin/src/agents/magic-context-prompt.ts
|
|
178407
180238
|
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
@@ -178552,7 +180383,7 @@ function processSystemPromptForCache(args) {
|
|
|
178552
180383
|
sessionLog(sessionId, `system prompt date frozen: real=${liveDate}, using=${stickyDate} (cache-stable pass)`);
|
|
178553
180384
|
}
|
|
178554
180385
|
}
|
|
178555
|
-
const currentHash =
|
|
180386
|
+
const currentHash = createHash11("md5").update(frozenPrompt).digest("hex");
|
|
178556
180387
|
const hashChanged = !isFirstHash && currentHash !== previousHash;
|
|
178557
180388
|
if (hashChanged) {
|
|
178558
180389
|
sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${frozenPrompt.length})`);
|
|
@@ -179179,6 +181010,19 @@ function extractStableId(msg, index, entryIds) {
|
|
|
179179
181010
|
// src/context-handler.ts
|
|
179180
181011
|
var FORCE_MATERIALIZATION_PERCENTAGE = 85;
|
|
179181
181012
|
var EMERGENCY_BLOCK_PERCENTAGE = 95;
|
|
181013
|
+
var FORWARD_PRESSURE_LIMIT_FACTOR = 0.85;
|
|
181014
|
+
function applyForwardPressureFloor(trailingPercentage, trailingInputTokens, piUsageTokens, correctedLimit) {
|
|
181015
|
+
const forwardTokens = typeof piUsageTokens === "number" && piUsageTokens > 0 ? piUsageTokens : 0;
|
|
181016
|
+
if (forwardTokens === 0 || !isSaneLimit(correctedLimit)) {
|
|
181017
|
+
return { percentage: trailingPercentage, inputTokens: trailingInputTokens };
|
|
181018
|
+
}
|
|
181019
|
+
const forwardPressureLimit = correctedLimit * FORWARD_PRESSURE_LIMIT_FACTOR;
|
|
181020
|
+
const forwardPercentage = forwardTokens / forwardPressureLimit * 100;
|
|
181021
|
+
return forwardPercentage > trailingPercentage ? {
|
|
181022
|
+
percentage: forwardPercentage,
|
|
181023
|
+
inputTokens: Math.max(trailingInputTokens, forwardTokens)
|
|
181024
|
+
} : { percentage: trailingPercentage, inputTokens: trailingInputTokens };
|
|
181025
|
+
}
|
|
179182
181026
|
var DEFAULT_CLEAR_REASONING_AGE = 50;
|
|
179183
181027
|
var PI_STABLE_ID_SCHEME = 1;
|
|
179184
181028
|
var lastEmergencyNotificationAtMs = new Map;
|
|
@@ -179263,7 +181107,7 @@ function trackSessionForProject(projectIdentity, sessionId) {
|
|
|
179263
181107
|
function isContextHandlerSessionActive(sessionId) {
|
|
179264
181108
|
return activeContextHandlerSessions.has(sessionId);
|
|
179265
181109
|
}
|
|
179266
|
-
function updateSessionProjectTracking(sessionId, projectIdentity) {
|
|
181110
|
+
function updateSessionProjectTracking(sessionId, projectIdentity, db) {
|
|
179267
181111
|
const prev = lastSeenProjectIdentityBySession.get(sessionId);
|
|
179268
181112
|
if (prev && prev !== projectIdentity) {
|
|
179269
181113
|
const prevSessions = sessionsByProject.get(prev);
|
|
@@ -179272,6 +181116,11 @@ function updateSessionProjectTracking(sessionId, projectIdentity) {
|
|
|
179272
181116
|
sessionsByProject.delete(prev);
|
|
179273
181117
|
clearPiSystemPromptSession(sessionId);
|
|
179274
181118
|
}
|
|
181119
|
+
if (db && prev !== projectIdentity) {
|
|
181120
|
+
try {
|
|
181121
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
181122
|
+
} catch {}
|
|
181123
|
+
}
|
|
179275
181124
|
trackSessionForProject(projectIdentity, sessionId);
|
|
179276
181125
|
lastSeenProjectIdentityBySession.set(sessionId, projectIdentity);
|
|
179277
181126
|
}
|
|
@@ -179552,7 +181401,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
179552
181401
|
const schedulerConfig = options.scheduler ?? DEFAULT_SCHEDULER_CONFIG;
|
|
179553
181402
|
const scheduler2 = schedulerFor(options);
|
|
179554
181403
|
const projectIdentity = resolveProjectIdentity(projectDirectory);
|
|
179555
|
-
updateSessionProjectTracking(sessionId, projectIdentity);
|
|
181404
|
+
updateSessionProjectTracking(sessionId, projectIdentity, options.db);
|
|
179556
181405
|
logTransformTiming(sessionId, "findSessionId", tFindSession, `messages=${event.messages.length}`);
|
|
179557
181406
|
const branchEntries = readPiBranchEntriesForContext(ctx, sessionId);
|
|
179558
181407
|
const rawMessageProvider = {
|
|
@@ -179661,9 +181510,10 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
179661
181510
|
if (!usedPersistedUsage && isSaneLimit(usageContextLimit) && usageInputTokens > 0) {
|
|
179662
181511
|
usagePercentage = usageInputTokens / usageContextLimit * 100;
|
|
179663
181512
|
}
|
|
181513
|
+
({ percentage: usagePercentage, inputTokens: usageInputTokens } = applyForwardPressureFloor(usagePercentage, usageInputTokens, piUsage?.tokens, usageContextLimit));
|
|
179664
181514
|
if (needsEmergencyBump) {
|
|
179665
181515
|
sessionLog(sessionId, `transform: overflow recovery flag set — bumping percentage to 95% (detectedLimit=${usageContextLimit ?? "unknown"})`);
|
|
179666
|
-
usagePercentage = 95;
|
|
181516
|
+
usagePercentage = Math.max(usagePercentage, 95);
|
|
179667
181517
|
}
|
|
179668
181518
|
let schedulerDecision;
|
|
179669
181519
|
const tScheduler = performance.now();
|
|
@@ -180047,6 +181897,7 @@ function spawnPiHistorianRun(args) {
|
|
|
180047
181897
|
provider: provider2,
|
|
180048
181898
|
unregister,
|
|
180049
181899
|
boundarySnapshot,
|
|
181900
|
+
refreshBoundarySnapshot,
|
|
180050
181901
|
currentContextLimit
|
|
180051
181902
|
} = args;
|
|
180052
181903
|
const holderId = crypto3.randomUUID();
|
|
@@ -180070,6 +181921,7 @@ function spawnPiHistorianRun(args) {
|
|
|
180070
181921
|
fallbackModels: historian.fallbackModels,
|
|
180071
181922
|
historianChunkTokens: historian.historianChunkTokens,
|
|
180072
181923
|
boundarySnapshot,
|
|
181924
|
+
refreshBoundarySnapshot,
|
|
180073
181925
|
currentContextLimit,
|
|
180074
181926
|
historianTimeoutMs: historian.timeoutMs,
|
|
180075
181927
|
twoPass: historian.twoPass,
|
|
@@ -180136,6 +181988,7 @@ function maybeFireHistorian(args) {
|
|
|
180136
181988
|
let usageContextLimit;
|
|
180137
181989
|
try {
|
|
180138
181990
|
const piUsage = ctx.getContextUsage?.();
|
|
181991
|
+
let usageSource;
|
|
180139
181992
|
usageContextLimit = isSaneLimit(piUsage?.contextWindow) ? piUsage.contextWindow : undefined;
|
|
180140
181993
|
if (usageContextLimit === undefined && isSaneLimit(ctx.model?.contextWindow)) {
|
|
180141
181994
|
usageContextLimit = ctx.model.contextWindow;
|
|
@@ -180152,7 +182005,7 @@ function maybeFireHistorian(args) {
|
|
|
180152
182005
|
percentage: sessionMetaForUsage.lastContextPercentage,
|
|
180153
182006
|
inputTokens: sessionMetaForUsage.lastInputTokens
|
|
180154
182007
|
};
|
|
180155
|
-
|
|
182008
|
+
usageSource = "session_meta";
|
|
180156
182009
|
} else {
|
|
180157
182010
|
if (!piUsage || piUsage.tokens === null || piUsage.percent === null || piUsage.contextWindow === 0) {
|
|
180158
182011
|
sessionLog(sessionId, `historian trigger eval: no usage info yet (tokens=${piUsage?.tokens ?? "<no piUsage>"}, percent=${piUsage?.percent ?? "<no piUsage>"}, contextWindow=${piUsage?.contextWindow ?? "<no piUsage>"})`);
|
|
@@ -180163,8 +182016,10 @@ function maybeFireHistorian(args) {
|
|
|
180163
182016
|
percentage: fallbackPercentage,
|
|
180164
182017
|
inputTokens: piUsage.tokens
|
|
180165
182018
|
};
|
|
180166
|
-
|
|
182019
|
+
usageSource = "piUsage fallback";
|
|
180167
182020
|
}
|
|
182021
|
+
usage = applyForwardPressureFloor(usage.percentage, usage.inputTokens, piUsage?.tokens, usageContextLimit);
|
|
182022
|
+
sessionLog(sessionId, `historian trigger eval: usage=${usage.percentage.toFixed(1)}% (${usage.inputTokens} tokens) [${usageSource}], checking trigger...`);
|
|
180168
182023
|
} catch (err) {
|
|
180169
182024
|
sessionLog(sessionId, `historian trigger eval: getContextUsage threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
180170
182025
|
return;
|
|
@@ -180195,10 +182050,14 @@ function maybeFireHistorian(args) {
|
|
|
180195
182050
|
cacheNamespace: `pi:${sessionId}`,
|
|
180196
182051
|
emergencyTailScale
|
|
180197
182052
|
}));
|
|
180198
|
-
|
|
180199
|
-
|
|
180200
|
-
|
|
180201
|
-
|
|
182053
|
+
const resolveRunnablePiBoundarySnapshot = () => {
|
|
182054
|
+
let snapshot = ensureRunnablePiBoundaryForTests(resolvePiBoundarySnapshot());
|
|
182055
|
+
if (!hasRunnableCompartmentWindow(snapshot) && usage.percentage >= 80) {
|
|
182056
|
+
snapshot = ensureRunnablePiBoundaryForTests(resolvePiBoundarySnapshot(usage.percentage >= 95 ? 0.25 : 0.5));
|
|
182057
|
+
}
|
|
182058
|
+
return snapshot;
|
|
182059
|
+
};
|
|
182060
|
+
const boundarySnapshot = resolveRunnablePiBoundarySnapshot();
|
|
180202
182061
|
let triggered = false;
|
|
180203
182062
|
try {
|
|
180204
182063
|
if (isFirstContextPassForSession) {
|
|
@@ -180223,6 +182082,7 @@ Historian previously failed ${failureState.failureCount} time(s), so Magic Conte
|
|
|
180223
182082
|
provider: provider2,
|
|
180224
182083
|
unregister,
|
|
180225
182084
|
boundarySnapshot,
|
|
182085
|
+
refreshBoundarySnapshot: resolveRunnablePiBoundarySnapshot,
|
|
180226
182086
|
currentContextLimit: boundaryContextLimit
|
|
180227
182087
|
});
|
|
180228
182088
|
return;
|
|
@@ -180246,6 +182106,7 @@ Historian previously failed ${failureState.failureCount} time(s), so Magic Conte
|
|
|
180246
182106
|
resolvedBoundarySnapshot: boundarySnapshot,
|
|
180247
182107
|
triggerBoundarySnapshot: trigger.boundarySnapshot
|
|
180248
182108
|
}),
|
|
182109
|
+
refreshBoundarySnapshot: resolveRunnablePiBoundarySnapshot,
|
|
180249
182110
|
currentContextLimit: boundaryContextLimit
|
|
180250
182111
|
});
|
|
180251
182112
|
} catch (err) {
|
|
@@ -180286,7 +182147,31 @@ async function runPipeline(args) {
|
|
|
180286
182147
|
const alreadyRanHeuristicsThisTurn = currentTurnId !== null && lastHeuristicsTurnIdBySession.get(args.sessionId) === currentTurnId;
|
|
180287
182148
|
const canConsumeDeferredLate = args.schedulerDecision === "execute" || args.forceMaterialization === true || args.contextUsage.percentage >= FORCE_MATERIALIZATION_PERCENTAGE;
|
|
180288
182149
|
const deferredMaterializeEligible = canConsumeDeferredLate && deferredMaterializationSessions.has(args.sessionId);
|
|
180289
|
-
const
|
|
182150
|
+
const piHardSignals = args.injection ? (() => {
|
|
182151
|
+
const hardMeta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
182152
|
+
let piTtlMs = 5 * 60 * 1000;
|
|
182153
|
+
try {
|
|
182154
|
+
piTtlMs = parseCacheTtl(hardMeta.cacheTtl);
|
|
182155
|
+
} catch {}
|
|
182156
|
+
return {
|
|
182157
|
+
systemHash: typeof hardMeta.systemPromptHash === "string" ? hardMeta.systemPromptHash : "",
|
|
182158
|
+
modelKey: liveModelBySession.get(args.sessionId) ?? "",
|
|
182159
|
+
cacheExpired: hardMeta.lastResponseTime > 0 && Date.now() - hardMeta.lastResponseTime >= piTtlMs,
|
|
182160
|
+
lastResponseTime: hardMeta.lastResponseTime
|
|
182161
|
+
};
|
|
182162
|
+
})() : undefined;
|
|
182163
|
+
const m0HardFoldThisPass = args.injection && piHardSignals ? mustMaterializePi({
|
|
182164
|
+
sessionId: args.sessionId,
|
|
182165
|
+
projectIdentity: args.projectIdentity,
|
|
182166
|
+
projectDirectory: args.projectDirectory,
|
|
182167
|
+
memoryEnabled: args.injection.memoryEnabled,
|
|
182168
|
+
injectionBudgetTokens: args.injection.injectionBudgetTokens,
|
|
182169
|
+
historyBudgetTokens: args.injection.historyBudgetTokens,
|
|
182170
|
+
keyFilesEnabled: args.injection.keyFilesEnabled,
|
|
182171
|
+
keyFilesTokenBudget: args.injection.keyFilesTokenBudget,
|
|
182172
|
+
hardSignals: piHardSignals
|
|
182173
|
+
}, args.db, getCompartments(args.db, args.sessionId)).value : false;
|
|
182174
|
+
const shouldRunHeuristics = args.heuristics !== undefined && (args.forceMaterialization === true || hasPendingMaterialization(args.sessionId) || deferredMaterializeEligible || m0HardFoldThisPass || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
|
|
180290
182175
|
const entryFingerprintByMessageId = buildEntryFingerprintMap(args.messages, stableIdResolver);
|
|
180291
182176
|
adoptPiFallbackTags(args.db, args.sessionId, args.tagger, entryFingerprintByMessageId);
|
|
180292
182177
|
const tTag = performance.now();
|
|
@@ -180313,12 +182198,12 @@ async function runPipeline(args) {
|
|
|
180313
182198
|
const deferredMaterializationWasPending = deferredMaterializationSessions.has(args.sessionId);
|
|
180314
182199
|
const deferredHistoryRefreshWasPending = deferredHistoryWasPendingAtPassStart;
|
|
180315
182200
|
const pendingOps = getPendingOps(args.db, args.sessionId);
|
|
180316
|
-
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal;
|
|
182201
|
+
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal || m0HardFoldThisPass;
|
|
180317
182202
|
const deferredMaterialize = canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
180318
182203
|
const deferredHistoryRefresh = canConsumeDeferredLate && deferredHistoryRefreshWasPending;
|
|
180319
182204
|
const shouldApplyPendingOps = baseShouldApplyPendingOps || deferredMaterialize;
|
|
180320
182205
|
if (shouldApplyPendingOps) {
|
|
180321
|
-
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
182206
|
+
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : m0HardFoldThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into known m[0] bust, scheduler=${args.schedulerDecision})` : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
180322
182207
|
sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
|
|
180323
182208
|
try {
|
|
180324
182209
|
const tApplyPending = performance.now();
|
|
@@ -180389,7 +182274,7 @@ async function runPipeline(args) {
|
|
|
180389
182274
|
const activeTags = getActiveTagsBySession(args.db, args.sessionId);
|
|
180390
182275
|
logTransformTiming(args.sessionId, "getActiveTagsBySession", tActiveTags, `count=${activeTags.length}`);
|
|
180391
182276
|
if (shouldRunHeuristics) {
|
|
180392
|
-
const reason = args.forceMaterialization ? "force_materialization" : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
182277
|
+
const reason = args.forceMaterialization ? "force_materialization" : m0HardFoldThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into known m[0] bust, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
180393
182278
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=n/a`);
|
|
180394
182279
|
} else {
|
|
180395
182280
|
const reason = args.heuristics === undefined ? "disabled" : "scheduler_defer";
|
|
@@ -180477,17 +182362,6 @@ async function runPipeline(args) {
|
|
|
180477
182362
|
if (args.injection) {
|
|
180478
182363
|
try {
|
|
180479
182364
|
const tInjection = performance.now();
|
|
180480
|
-
const hardMeta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
180481
|
-
let piTtlMs = 5 * 60 * 1000;
|
|
180482
|
-
try {
|
|
180483
|
-
piTtlMs = parseCacheTtl(hardMeta.cacheTtl);
|
|
180484
|
-
} catch {}
|
|
180485
|
-
const piHardSignals = {
|
|
180486
|
-
systemHash: typeof hardMeta.systemPromptHash === "string" ? hardMeta.systemPromptHash : "",
|
|
180487
|
-
modelKey: liveModelBySession.get(args.sessionId) ?? "",
|
|
180488
|
-
cacheExpired: hardMeta.lastResponseTime > 0 && Date.now() - hardMeta.lastResponseTime >= piTtlMs,
|
|
180489
|
-
lastResponseTime: hardMeta.lastResponseTime
|
|
180490
|
-
};
|
|
180491
182365
|
injectionResult = injectM0M1Pi({
|
|
180492
182366
|
sessionId: args.sessionId,
|
|
180493
182367
|
projectIdentity: args.projectIdentity,
|
|
@@ -181577,8 +183451,12 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
181577
183451
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181578
183452
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
181579
183453
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181580
|
-
const
|
|
181581
|
-
|
|
183454
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
183455
|
+
id: c.id,
|
|
183456
|
+
startMessage: c.startMessage,
|
|
183457
|
+
endMessage: c.endMessage
|
|
183458
|
+
}));
|
|
183459
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
181582
183460
|
}
|
|
181583
183461
|
const lastCompartmentEnd2 = promoted2.compartments[promoted2.compartments.length - 1]?.endMessage ?? 0;
|
|
181584
183462
|
if (lastCompartmentEnd2 > 0) {
|
|
@@ -181791,8 +183669,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
181791
183669
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181792
183670
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
181793
183671
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181794
|
-
const
|
|
181795
|
-
|
|
183672
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
183673
|
+
id: c.id,
|
|
183674
|
+
startMessage: c.startMessage,
|
|
183675
|
+
endMessage: c.endMessage
|
|
183676
|
+
}));
|
|
183677
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
181796
183678
|
}
|
|
181797
183679
|
if (lastCompartmentEnd > 0) {
|
|
181798
183680
|
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
@@ -181949,8 +183831,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
181949
183831
|
if (deps.memoryEnabled !== false) {
|
|
181950
183832
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181951
183833
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181952
|
-
const
|
|
181953
|
-
|
|
183834
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
183835
|
+
id: c.id,
|
|
183836
|
+
startMessage: c.startMessage,
|
|
183837
|
+
endMessage: c.endMessage
|
|
183838
|
+
}));
|
|
183839
|
+
Promise.resolve(deps.ensureProjectRegistered?.(sessionDirectory, db)).then(() => embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed));
|
|
181954
183840
|
}
|
|
181955
183841
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
181956
183842
|
if (lastEnd > 0) {
|
|
@@ -182762,7 +184648,7 @@ function applyMemoryMigration(db, projectPath, result) {
|
|
|
182762
184648
|
inserted++;
|
|
182763
184649
|
}
|
|
182764
184650
|
if (removed > 0 || inserted > 0) {
|
|
182765
|
-
|
|
184651
|
+
bumpEpochsForWorkspaceMembers(db, projectPath);
|
|
182766
184652
|
}
|
|
182767
184653
|
})();
|
|
182768
184654
|
return { removed, inserted };
|
|
@@ -183238,7 +185124,7 @@ function formatThresholdPercent(value) {
|
|
|
183238
185124
|
// package.json
|
|
183239
185125
|
var package_default = {
|
|
183240
185126
|
name: "@cortexkit/pi-magic-context",
|
|
183241
|
-
version: "0.
|
|
185127
|
+
version: "0.24.0",
|
|
183242
185128
|
type: "module",
|
|
183243
185129
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
183244
185130
|
main: "dist/index.js",
|
|
@@ -188102,6 +189988,23 @@ function createCtxMemoryTool(deps) {
|
|
|
188102
189988
|
}
|
|
188103
189989
|
const projectIdentity = resolveProjectIdentity(ctx.cwd);
|
|
188104
189990
|
await deps.ensureProjectRegistered?.(ctx.cwd, deps.db);
|
|
189991
|
+
const workspaceIdentitySet = resolveWorkspaceIdentitySet(deps.db, projectIdentity);
|
|
189992
|
+
const expandedWorkspace = expandWorkspaceIdentitySetWithAliases(deps.db, workspaceIdentitySet.identities);
|
|
189993
|
+
const workspaceVisibleIdentities = workspaceIdentitySet.identities.length > 1 ? expandedWorkspace.expandedIdentities : workspaceIdentitySet.identities;
|
|
189994
|
+
const targetIdentityForStoredPath = (rawProjectPath) => workspaceIdentitySet.identities.length > 1 ? resolveStoredPathWorkspaceIdentity(rawProjectPath, workspaceIdentitySet.identities, expandedWorkspace.canonicalIdentityByStoredPath) ?? normalizeStoredProjectPath(rawProjectPath) : normalizeStoredProjectPath(rawProjectPath);
|
|
189995
|
+
const toolShareCategories = workspaceIdentitySet.identities.length > 1 ? resolveWorkspaceShareCategories(deps.db, projectIdentity) : null;
|
|
189996
|
+
const memoryVisibleToTool = (memory2) => {
|
|
189997
|
+
if (workspaceIdentitySet.identities.length <= 1) {
|
|
189998
|
+
return storedPathBelongsToIdentity(memory2.projectPath, projectIdentity);
|
|
189999
|
+
}
|
|
190000
|
+
if (!storedPathBelongsToWorkspace(memory2.projectPath, workspaceIdentitySet.identities, workspaceVisibleIdentities, expandedWorkspace.canonicalIdentityByStoredPath)) {
|
|
190001
|
+
return false;
|
|
190002
|
+
}
|
|
190003
|
+
const isOwn = targetIdentityForStoredPath(memory2.projectPath) === projectIdentity;
|
|
190004
|
+
if (isOwn)
|
|
190005
|
+
return true;
|
|
190006
|
+
return toolShareCategories === null || toolShareCategories.includes(memory2.category);
|
|
190007
|
+
};
|
|
188105
190008
|
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
188106
190009
|
if (snapshot ? !snapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
188107
190010
|
return err2("Cross-session memory is disabled for this project.");
|
|
@@ -188148,28 +190051,34 @@ function createCtxMemoryTool(deps) {
|
|
|
188148
190051
|
return err2("Error: 'content' is required when action is 'update'.");
|
|
188149
190052
|
}
|
|
188150
190053
|
const memory2 = getMemoryById(deps.db, updateId);
|
|
188151
|
-
if (!memory2 || !
|
|
190054
|
+
if (!memory2 || !memoryVisibleToTool(memory2)) {
|
|
188152
190055
|
return err2(`Error: Memory with ID ${updateId} was not found.`);
|
|
188153
190056
|
}
|
|
188154
190057
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
188155
190058
|
return err2(inactiveMemoryError(updateId, "updating"));
|
|
188156
190059
|
}
|
|
188157
190060
|
const normalizedHash = computeNormalizedHash(content);
|
|
188158
|
-
const
|
|
190061
|
+
const targetIdentity = targetIdentityForStoredPath(memory2.projectPath);
|
|
190062
|
+
const duplicate = getMemoryByHash(deps.db, targetIdentity, memory2.category, normalizedHash);
|
|
188159
190063
|
if (duplicate && duplicate.id !== memory2.id) {
|
|
188160
190064
|
return err2(`Error: Memory content already exists as ID ${duplicate.id}; merge or archive duplicates instead.`);
|
|
188161
190065
|
}
|
|
188162
190066
|
deps.db.transaction(() => {
|
|
188163
190067
|
updateMemoryContent(deps.db, memory2.id, content, normalizedHash);
|
|
188164
190068
|
queueMemoryMutation(deps.db, {
|
|
188165
|
-
projectPath:
|
|
190069
|
+
projectPath: targetIdentity,
|
|
188166
190070
|
mutationType: "update",
|
|
188167
190071
|
targetMemoryId: memory2.id,
|
|
188168
190072
|
category: memory2.category,
|
|
188169
190073
|
newContent: content
|
|
188170
190074
|
});
|
|
188171
190075
|
})();
|
|
188172
|
-
queueEmbedding({
|
|
190076
|
+
queueEmbedding({
|
|
190077
|
+
deps,
|
|
190078
|
+
projectIdentity: targetIdentity,
|
|
190079
|
+
memoryId: memory2.id,
|
|
190080
|
+
content
|
|
190081
|
+
});
|
|
188173
190082
|
return ok2(`Updated memory [ID: ${memory2.id}] in ${memory2.category}.`);
|
|
188174
190083
|
}
|
|
188175
190084
|
if (params.action === "merge") {
|
|
@@ -188189,7 +190098,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188189
190098
|
return err2("Error: One or more source memories were not found.");
|
|
188190
190099
|
}
|
|
188191
190100
|
if (!dreamerAllowed) {
|
|
188192
|
-
const foreign = sourceMemories.find((memory2) => !
|
|
190101
|
+
const foreign = sourceMemories.find((memory2) => !memoryVisibleToTool(memory2));
|
|
188193
190102
|
if (foreign) {
|
|
188194
190103
|
return err2(`Error: Memory with ID ${foreign.id} was not found.`);
|
|
188195
190104
|
}
|
|
@@ -188278,26 +190187,36 @@ function createCtxMemoryTool(deps) {
|
|
|
188278
190187
|
return ok2(`Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`);
|
|
188279
190188
|
}
|
|
188280
190189
|
if (params.action === "archive") {
|
|
188281
|
-
const
|
|
188282
|
-
if (!
|
|
190190
|
+
const rawArchiveIds = params.ids;
|
|
190191
|
+
if (!rawArchiveIds || rawArchiveIds.length === 0 || !rawArchiveIds.every(Number.isInteger)) {
|
|
188283
190192
|
return err2("Error: 'ids' must contain at least one integer memory ID when action is 'archive'.");
|
|
188284
190193
|
}
|
|
190194
|
+
const archiveIds = [...new Set(rawArchiveIds)];
|
|
188285
190195
|
for (const memoryId of archiveIds) {
|
|
188286
190196
|
const memory2 = getMemoryById(deps.db, memoryId);
|
|
188287
|
-
if (!memory2 || !
|
|
190197
|
+
if (!memory2 || !memoryVisibleToTool(memory2)) {
|
|
188288
190198
|
return err2(`Error: Memory with ID ${memoryId} was not found.`);
|
|
188289
190199
|
}
|
|
188290
190200
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
188291
190201
|
return err2(inactiveMemoryError(memoryId, "archiving"));
|
|
188292
190202
|
}
|
|
188293
190203
|
}
|
|
190204
|
+
const targets = archiveIds.map((memoryId) => {
|
|
190205
|
+
const memory2 = getMemoryById(deps.db, memoryId);
|
|
190206
|
+
if (!memory2)
|
|
190207
|
+
throw new Error(`validated memory ${memoryId} disappeared`);
|
|
190208
|
+
return {
|
|
190209
|
+
memoryId,
|
|
190210
|
+
projectIdentity: targetIdentityForStoredPath(memory2.projectPath)
|
|
190211
|
+
};
|
|
190212
|
+
});
|
|
188294
190213
|
deps.db.transaction(() => {
|
|
188295
|
-
for (const
|
|
188296
|
-
archiveMemory(deps.db, memoryId, params.reason);
|
|
190214
|
+
for (const target2 of targets) {
|
|
190215
|
+
archiveMemory(deps.db, target2.memoryId, params.reason);
|
|
188297
190216
|
queueMemoryMutation(deps.db, {
|
|
188298
|
-
projectPath: projectIdentity,
|
|
190217
|
+
projectPath: target2.projectIdentity,
|
|
188299
190218
|
mutationType: "archive",
|
|
188300
|
-
targetMemoryId: memoryId
|
|
190219
|
+
targetMemoryId: target2.memoryId
|
|
188301
190220
|
});
|
|
188302
190221
|
}
|
|
188303
190222
|
})();
|
|
@@ -188805,8 +190724,9 @@ function formatAge2(committedAtMs) {
|
|
|
188805
190724
|
}
|
|
188806
190725
|
function formatResult(result, index) {
|
|
188807
190726
|
if (result.source === "memory") {
|
|
190727
|
+
const source = result.sourceName ? ` source=${result.sourceName}` : "";
|
|
188808
190728
|
return [
|
|
188809
|
-
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category} match=${result.matchType}`,
|
|
190729
|
+
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category}${source} match=${result.matchType}`,
|
|
188810
190730
|
result.content
|
|
188811
190731
|
].join(`
|
|
188812
190732
|
`);
|
|
@@ -188816,6 +190736,13 @@ function formatResult(result, index) {
|
|
|
188816
190736
|
`[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge2(result.committedAtMs)} match=${result.matchType}`,
|
|
188817
190737
|
result.content
|
|
188818
190738
|
].join(`
|
|
190739
|
+
`);
|
|
190740
|
+
}
|
|
190741
|
+
if (result.source === "compartment") {
|
|
190742
|
+
return [
|
|
190743
|
+
`[${index}] [message] score=${result.score.toFixed(2)} compartment_id=${result.compartmentId} range=${result.startOrdinal}-${result.endOrdinal} match=${result.matchType} title=${result.title}`,
|
|
190744
|
+
result.snippet ? `Snippet: ${result.snippet}` : result.content
|
|
190745
|
+
].join(`
|
|
188819
190746
|
`);
|
|
188820
190747
|
}
|
|
188821
190748
|
const expandStart = Math.max(1, result.messageOrdinal - 3);
|
|
@@ -188831,7 +190758,7 @@ function formatSearchResults(query, results) {
|
|
|
188831
190758
|
return `No results found for "${query}" across memories, git commits, or message history.`;
|
|
188832
190759
|
}
|
|
188833
190760
|
const bodyParts = results.map((result, index) => formatResult(result, index + 1));
|
|
188834
|
-
if (results.some((result) => result.source === "message")) {
|
|
190761
|
+
if (results.some((result) => result.source === "message" || result.source === "compartment")) {
|
|
188835
190762
|
bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
|
|
188836
190763
|
}
|
|
188837
190764
|
const body = bodyParts.join(`
|
|
@@ -189327,6 +191254,14 @@ async function src_default2(pi) {
|
|
|
189327
191254
|
onProjectSeen: (identity) => seenDreamerProjectIdentities.add(identity)
|
|
189328
191255
|
});
|
|
189329
191256
|
info("registered /ctx-dream");
|
|
191257
|
+
registerCtxEmbedHistoryCommand(pi, {
|
|
191258
|
+
db,
|
|
191259
|
+
projectDir,
|
|
191260
|
+
projectIdentity,
|
|
191261
|
+
memoryEnabled: config2.memory.enabled,
|
|
191262
|
+
resolveProject: resolveCurrentProject
|
|
191263
|
+
});
|
|
191264
|
+
info("registered /ctx-embed-history");
|
|
189330
191265
|
const dreamerConfig = resolveDreamerFromConfig(config2);
|
|
189331
191266
|
if (dreamerConfig) {
|
|
189332
191267
|
registerPiDreamerProject({
|