@cortexkit/pi-magic-context 0.23.0 → 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 +2242 -306
- package/dist/subagent-entry.js +2071 -410
- 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 = ?,
|
|
@@ -142200,9 +142206,8 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
142200
142206
|
cached_m0_session_facts_version = ?,
|
|
142201
142207
|
cached_m0_upgrade_state = ?,
|
|
142202
142208
|
cached_m0_system_hash = ?,
|
|
142203
|
-
cached_m0_tool_set_hash = ?,
|
|
142204
142209
|
cached_m0_model_key = ?
|
|
142205
|
-
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.
|
|
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);
|
|
142206
142211
|
}
|
|
142207
142212
|
function clearCachedM0M1(db, sessionId) {
|
|
142208
142213
|
ensureSessionMetaRow(db, sessionId);
|
|
@@ -142211,6 +142216,7 @@ function clearCachedM0M1(db, sessionId) {
|
|
|
142211
142216
|
["cached_m0_bytes", null],
|
|
142212
142217
|
["cached_m1_bytes", null],
|
|
142213
142218
|
["cached_m0_project_memory_epoch", null],
|
|
142219
|
+
["cached_m0_workspace_fingerprint", null],
|
|
142214
142220
|
["cached_m0_project_user_profile_version", null],
|
|
142215
142221
|
["cached_m0_max_compartment_seq", null],
|
|
142216
142222
|
["cached_m0_max_memory_id", null],
|
|
@@ -142925,7 +142931,7 @@ var databases = new Map;
|
|
|
142925
142931
|
var persistenceByDatabase = new WeakMap;
|
|
142926
142932
|
var persistenceErrorByDatabase = new WeakMap;
|
|
142927
142933
|
var lastSchemaFenceRejection = null;
|
|
142928
|
-
var LATEST_SUPPORTED_VERSION =
|
|
142934
|
+
var LATEST_SUPPORTED_VERSION = 36;
|
|
142929
142935
|
function resolveDatabasePath(dbPathOverride) {
|
|
142930
142936
|
if (dbPathOverride) {
|
|
142931
142937
|
return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
|
|
@@ -143091,6 +143097,35 @@ function initializeDatabase(db) {
|
|
|
143091
143097
|
);
|
|
143092
143098
|
CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
|
|
143093
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
|
+
|
|
143094
143129
|
CREATE TABLE IF NOT EXISTS compartment_events (
|
|
143095
143130
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143096
143131
|
session_id TEXT NOT NULL,
|
|
@@ -143276,6 +143311,25 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143276
143311
|
rekeyed_at INTEGER NOT NULL
|
|
143277
143312
|
);
|
|
143278
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
|
+
|
|
143279
143333
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
143280
143334
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143281
143335
|
table_name TEXT NOT NULL,
|
|
@@ -143387,6 +143441,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143387
143441
|
deferred_execute_state TEXT,
|
|
143388
143442
|
cached_m0_bytes BLOB,
|
|
143389
143443
|
cached_m0_project_memory_epoch INTEGER,
|
|
143444
|
+
cached_m0_workspace_fingerprint TEXT,
|
|
143390
143445
|
cached_m0_project_user_profile_version INTEGER,
|
|
143391
143446
|
cached_m0_max_compartment_seq INTEGER,
|
|
143392
143447
|
cached_m0_max_memory_id INTEGER,
|
|
@@ -143545,6 +143600,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143545
143600
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
143546
143601
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
143547
143602
|
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
143603
|
+
ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
|
|
143548
143604
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
143549
143605
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
143550
143606
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -143598,6 +143654,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143598
143654
|
ensureColumn(db, "memories", "importance", "INTEGER");
|
|
143599
143655
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
143600
143656
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
143657
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
143601
143658
|
ensureColumn(db, "session_meta", "cached_m0_project_user_profile_version", "INTEGER");
|
|
143602
143659
|
ensureColumn(db, "session_meta", "cached_m0_max_compartment_seq", "INTEGER");
|
|
143603
143660
|
ensureColumn(db, "session_meta", "cached_m0_max_memory_id", "INTEGER");
|
|
@@ -143629,6 +143686,15 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143629
143686
|
project_user_profile_version INTEGER NOT NULL DEFAULT 0,
|
|
143630
143687
|
updated_at INTEGER NOT NULL DEFAULT 0
|
|
143631
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);
|
|
143632
143698
|
CREATE TABLE IF NOT EXISTS m0_mutation_log (
|
|
143633
143699
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143634
143700
|
session_id TEXT NOT NULL,
|
|
@@ -143656,6 +143722,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143656
143722
|
new_project_path TEXT NOT NULL,
|
|
143657
143723
|
rekeyed_at INTEGER NOT NULL
|
|
143658
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);
|
|
143659
143742
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
143660
143743
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143661
143744
|
table_name TEXT NOT NULL,
|
|
@@ -143677,6 +143760,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143677
143760
|
ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
143678
143761
|
ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
143679
143762
|
ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
143763
|
+
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
143680
143764
|
}
|
|
143681
143765
|
function healAllNullColumns(db) {
|
|
143682
143766
|
healNullTextColumns(db);
|
|
@@ -143715,6 +143799,7 @@ function healNullTextColumns(db) {
|
|
|
143715
143799
|
["system_prompt_hash", ""],
|
|
143716
143800
|
["stripped_placeholder_ids", ""],
|
|
143717
143801
|
["stale_reduce_stripped_ids", ""],
|
|
143802
|
+
["processed_image_stripped_ids", ""],
|
|
143718
143803
|
["memory_block_cache", ""],
|
|
143719
143804
|
["memory_block_ids", ""],
|
|
143720
143805
|
["compaction_marker_state", ""],
|
|
@@ -143759,7 +143844,7 @@ function healNullIntegerColumns(db) {
|
|
|
143759
143844
|
}
|
|
143760
143845
|
}
|
|
143761
143846
|
function ensureColumn(db, table, column, definition) {
|
|
143762
|
-
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)) {
|
|
143763
143848
|
throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
|
|
143764
143849
|
}
|
|
143765
143850
|
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
@@ -143836,10 +143921,291 @@ function openDatabase(dbPathOrOptions) {
|
|
|
143836
143921
|
}
|
|
143837
143922
|
}
|
|
143838
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
|
+
|
|
143839
144201
|
// ../plugin/src/features/magic-context/migrations.ts
|
|
143840
|
-
function
|
|
144202
|
+
function tableExists2(db, name2) {
|
|
143841
144203
|
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name2));
|
|
143842
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
|
+
}
|
|
143843
144209
|
var MIGRATIONS = [
|
|
143844
144210
|
{
|
|
143845
144211
|
version: 1,
|
|
@@ -144298,9 +144664,9 @@ var MIGRATIONS = [
|
|
|
144298
144664
|
version: 22,
|
|
144299
144665
|
description: "v2.0 cache architecture schema foundation",
|
|
144300
144666
|
up: (db) => {
|
|
144301
|
-
const hasSessionMetaTable =
|
|
144302
|
-
const hasCompartmentsTable =
|
|
144303
|
-
const hasMemoriesTable =
|
|
144667
|
+
const hasSessionMetaTable = tableExists2(db, "session_meta");
|
|
144668
|
+
const hasCompartmentsTable = tableExists2(db, "compartments");
|
|
144669
|
+
const hasMemoriesTable = tableExists2(db, "memories");
|
|
144304
144670
|
if (hasSessionMetaTable) {
|
|
144305
144671
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
144306
144672
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
@@ -144325,7 +144691,7 @@ var MIGRATIONS = [
|
|
|
144325
144691
|
ensureColumn(db, "compartments", "p1_embedding_model_id", "TEXT");
|
|
144326
144692
|
ensureColumn(db, "compartments", "legacy", "INTEGER NOT NULL DEFAULT 0");
|
|
144327
144693
|
}
|
|
144328
|
-
const hasRecompCompartmentsTable =
|
|
144694
|
+
const hasRecompCompartmentsTable = tableExists2(db, "recomp_compartments");
|
|
144329
144695
|
if (hasRecompCompartmentsTable) {
|
|
144330
144696
|
ensureColumn(db, "recomp_compartments", "p1", "TEXT");
|
|
144331
144697
|
ensureColumn(db, "recomp_compartments", "p2", "TEXT");
|
|
@@ -144636,6 +145002,156 @@ var MIGRATIONS = [
|
|
|
144636
145002
|
db.prepare("UPDATE session_meta SET force_emergency_bypass_used = 0 WHERE force_emergency_bypass_used IS NULL").run();
|
|
144637
145003
|
db.prepare("UPDATE session_meta SET last_usage_context_limit = 0 WHERE last_usage_context_limit IS NULL").run();
|
|
144638
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
|
+
}
|
|
144639
145155
|
}
|
|
144640
145156
|
];
|
|
144641
145157
|
var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -144705,7 +145221,7 @@ function runMigrations(db) {
|
|
|
144705
145221
|
log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
|
|
144706
145222
|
}
|
|
144707
145223
|
// ../plugin/src/features/magic-context/project-docs-hash.ts
|
|
144708
|
-
import { createHash as
|
|
145224
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
144709
145225
|
import { lstatSync, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
144710
145226
|
import path4 from "node:path";
|
|
144711
145227
|
var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
|
|
@@ -144803,7 +145319,7 @@ function hashCanonicalPieces(hashPieces) {
|
|
|
144803
145319
|
if (hashPieces.length === 0) {
|
|
144804
145320
|
return "";
|
|
144805
145321
|
}
|
|
144806
|
-
return
|
|
145322
|
+
return createHash4("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
|
|
144807
145323
|
}
|
|
144808
145324
|
function readProjectDocsCanonical(projectDirectory) {
|
|
144809
145325
|
const canonicalDirectory = path4.resolve(projectDirectory);
|
|
@@ -144909,18 +145425,13 @@ function getMemoryMutation(db, id) {
|
|
|
144909
145425
|
WHERE id = ?`).get(id);
|
|
144910
145426
|
return row ? toMemoryMutation(row) : null;
|
|
144911
145427
|
}
|
|
144912
|
-
function
|
|
144913
|
-
|
|
144914
|
-
|
|
144915
|
-
|
|
144916
|
-
|
|
144917
|
-
|
|
144918
|
-
|
|
144919
|
-
FROM memory_mutation_log
|
|
144920
|
-
WHERE project_path = ?
|
|
144921
|
-
AND id > ?
|
|
144922
|
-
AND target_memory_id IN (${placeholders})
|
|
144923
|
-
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) {
|
|
144924
145435
|
const chosenByTarget = new Map;
|
|
144925
145436
|
for (const dbRow of rows) {
|
|
144926
145437
|
const candidate = toMemoryMutation(dbRow);
|
|
@@ -144941,10 +145452,54 @@ function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds
|
|
|
144941
145452
|
}
|
|
144942
145453
|
return [...chosenByTarget.values()].sort((left, right) => left.id - right.id);
|
|
144943
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
|
+
}
|
|
144944
145488
|
function getMaxMemoryMutationId(db, projectPath) {
|
|
144945
145489
|
const row = db.prepare("SELECT MAX(id) AS max_id FROM memory_mutation_log WHERE project_path = ?").get(projectPath);
|
|
144946
145490
|
return row?.max_id ?? null;
|
|
144947
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
|
+
}
|
|
144948
145503
|
// ../plugin/src/features/magic-context/storage-meta-persisted.ts
|
|
144949
145504
|
init_logger();
|
|
144950
145505
|
var CAS_RETRY_LIMIT = 5;
|
|
@@ -145790,9 +146345,9 @@ function buildStatusClause(status) {
|
|
|
145790
146345
|
if (statuses.length === 0) {
|
|
145791
146346
|
return null;
|
|
145792
146347
|
}
|
|
145793
|
-
const
|
|
146348
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
145794
146349
|
return {
|
|
145795
|
-
sql: `status IN (${
|
|
146350
|
+
sql: `status IN (${placeholders3})`,
|
|
145796
146351
|
params: statuses
|
|
145797
146352
|
};
|
|
145798
146353
|
}
|
|
@@ -145988,19 +146543,6 @@ function getProjectState(db, projectPath) {
|
|
|
145988
146543
|
WHERE project_path = ?`).get(projectPath);
|
|
145989
146544
|
return row ? toProjectState(row) : null;
|
|
145990
146545
|
}
|
|
145991
|
-
function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
|
|
145992
|
-
db.prepare(`INSERT INTO project_state
|
|
145993
|
-
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
145994
|
-
VALUES (?, 1, 0, ?)
|
|
145995
|
-
ON CONFLICT(project_path) DO UPDATE SET
|
|
145996
|
-
project_memory_epoch = project_memory_epoch + 1,
|
|
145997
|
-
updated_at = excluded.updated_at`).run(projectPath, now);
|
|
145998
|
-
const state = getProjectState(db, projectPath);
|
|
145999
|
-
if (!state) {
|
|
146000
|
-
throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
|
|
146001
|
-
}
|
|
146002
|
-
return state;
|
|
146003
|
-
}
|
|
146004
146546
|
function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PROJECT_PATH, now = Date.now()) {
|
|
146005
146547
|
db.prepare(`INSERT INTO project_state
|
|
146006
146548
|
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
@@ -146034,8 +146576,8 @@ function getSourceContents(db, sessionId, tagIds) {
|
|
|
146034
146576
|
if (tagIds.length === 0) {
|
|
146035
146577
|
return new Map;
|
|
146036
146578
|
}
|
|
146037
|
-
const
|
|
146038
|
-
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);
|
|
146039
146581
|
const sources = new Map;
|
|
146040
146582
|
for (const row of rows) {
|
|
146041
146583
|
sources.set(row.tag_id, row.content);
|
|
@@ -146325,8 +146867,8 @@ function getTagsByNumbers(db, sessionId, tagNumbers) {
|
|
|
146325
146867
|
}
|
|
146326
146868
|
return all;
|
|
146327
146869
|
}
|
|
146328
|
-
const
|
|
146329
|
-
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);
|
|
146330
146872
|
return rows.map(toTagEntry);
|
|
146331
146873
|
}
|
|
146332
146874
|
var getToolTagNumberByOwnerStatements = new WeakMap;
|
|
@@ -146396,7 +146938,7 @@ var ERROR_CLASSES = new Set([
|
|
|
146396
146938
|
]);
|
|
146397
146939
|
// ../plugin/src/features/magic-context/v22-deferred-backfill.ts
|
|
146398
146940
|
init_logger();
|
|
146399
|
-
import { createHash as
|
|
146941
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
146400
146942
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
146401
146943
|
import path5 from "node:path";
|
|
146402
146944
|
var BATCH_SIZE = 25;
|
|
@@ -146450,7 +146992,7 @@ function computeLegacyRustDirIdentity(rawProjectPath) {
|
|
|
146450
146992
|
} catch {
|
|
146451
146993
|
canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
|
|
146452
146994
|
}
|
|
146453
|
-
return `dir:${
|
|
146995
|
+
return `dir:${createHash5("sha256").update(canonical, "utf8").digest("hex")}`;
|
|
146454
146996
|
}
|
|
146455
146997
|
function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
|
|
146456
146998
|
db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
|
|
@@ -147008,7 +147550,7 @@ function clearNoteNudgeTriggerOnly(db, sessionId) {
|
|
|
147008
147550
|
}
|
|
147009
147551
|
|
|
147010
147552
|
// ../plugin/src/hooks/magic-context/todo-view.ts
|
|
147011
|
-
import { createHash as
|
|
147553
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
147012
147554
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
147013
147555
|
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
147014
147556
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
@@ -147053,7 +147595,7 @@ function buildSyntheticTodoPart(stateJson) {
|
|
|
147053
147595
|
};
|
|
147054
147596
|
}
|
|
147055
147597
|
function computeSyntheticCallId(stateJson) {
|
|
147056
|
-
const hash =
|
|
147598
|
+
const hash = createHash6("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
147057
147599
|
return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
|
|
147058
147600
|
}
|
|
147059
147601
|
function parseTodoState(stateJson) {
|
|
@@ -147194,13 +147736,13 @@ async function maybeSendUpgradeReminder(deps, sessionId) {
|
|
|
147194
147736
|
init_data_path();
|
|
147195
147737
|
import * as fs2 from "node:fs";
|
|
147196
147738
|
import * as path6 from "node:path";
|
|
147197
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
147739
|
+
var ANNOUNCEMENT_VERSION = "0.24.0";
|
|
147198
147740
|
var ANNOUNCEMENT_FEATURES = [
|
|
147199
|
-
"
|
|
147200
|
-
"
|
|
147201
|
-
"
|
|
147202
|
-
"
|
|
147203
|
-
"
|
|
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)."
|
|
147204
147746
|
];
|
|
147205
147747
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
|
|
147206
147748
|
var STATE_FILENAME = "last_announced_version";
|
|
@@ -149083,7 +149625,7 @@ function isEmbeddingRow(row) {
|
|
|
149083
149625
|
if (row === null || typeof row !== "object")
|
|
149084
149626
|
return false;
|
|
149085
149627
|
const candidate = row;
|
|
149086
|
-
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding);
|
|
149628
|
+
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding) && (candidate.modelId === null || typeof candidate.modelId === "string");
|
|
149087
149629
|
}
|
|
149088
149630
|
function toFloat32Array(blob) {
|
|
149089
149631
|
if (blob instanceof Uint8Array) {
|
|
@@ -149103,7 +149645,7 @@ function getSaveEmbeddingStatement(db) {
|
|
|
149103
149645
|
function getLoadAllEmbeddingsStatement(db) {
|
|
149104
149646
|
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
149105
149647
|
if (!stmt) {
|
|
149106
|
-
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");
|
|
149107
149649
|
loadAllEmbeddingsStatements.set(db, stmt);
|
|
149108
149650
|
}
|
|
149109
149651
|
return stmt;
|
|
@@ -149132,7 +149674,10 @@ function loadAllEmbeddings(db, projectPath) {
|
|
|
149132
149674
|
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath).filter(isEmbeddingRow);
|
|
149133
149675
|
const embeddings = new Map;
|
|
149134
149676
|
for (const row of rows) {
|
|
149135
|
-
embeddings.set(row.memoryId,
|
|
149677
|
+
embeddings.set(row.memoryId, {
|
|
149678
|
+
embedding: toFloat32Array(row.embedding),
|
|
149679
|
+
modelId: row.modelId
|
|
149680
|
+
});
|
|
149136
149681
|
}
|
|
149137
149682
|
return embeddings;
|
|
149138
149683
|
}
|
|
@@ -149183,13 +149728,13 @@ function invalidateMemory(projectPath, memoryId) {
|
|
|
149183
149728
|
}
|
|
149184
149729
|
|
|
149185
149730
|
// ../plugin/src/features/magic-context/memory/normalize-hash.ts
|
|
149186
|
-
import { createHash as
|
|
149731
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
149187
149732
|
function normalizeMemoryContent(content) {
|
|
149188
149733
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
149189
149734
|
}
|
|
149190
149735
|
function computeNormalizedHash(content) {
|
|
149191
149736
|
const normalized = normalizeMemoryContent(content);
|
|
149192
|
-
return
|
|
149737
|
+
return createHash7("md5").update(normalized).digest("hex");
|
|
149193
149738
|
}
|
|
149194
149739
|
|
|
149195
149740
|
// ../plugin/src/features/magic-context/memory/storage-memory.ts
|
|
@@ -149377,8 +149922,8 @@ function getMemoriesByProjectStatement(db, statuses) {
|
|
|
149377
149922
|
}
|
|
149378
149923
|
let stmt = statements.get(db);
|
|
149379
149924
|
if (!stmt) {
|
|
149380
|
-
const
|
|
149381
|
-
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`);
|
|
149382
149927
|
statements.set(db, stmt);
|
|
149383
149928
|
}
|
|
149384
149929
|
return stmt;
|
|
@@ -149523,6 +150068,97 @@ function getMemoriesByProject(db, projectPath, statuses = ["active", "permanent"
|
|
|
149523
150068
|
const rows = getMemoriesByProjectStatement(db, statuses).all(projectPath, ...statuses, expiryCutoff).filter(isMemoryRow);
|
|
149524
150069
|
return rows.map(toMemory);
|
|
149525
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
|
+
}
|
|
149526
150162
|
function getAllActiveMemoriesForMigration(db, projectPath) {
|
|
149527
150163
|
const rows = getActiveMemoriesNoExpiryStatement(db).all(projectPath).filter(isMemoryRow);
|
|
149528
150164
|
return rows.map(toMemory);
|
|
@@ -150044,8 +150680,8 @@ function getUserMemoryCandidates(db) {
|
|
|
150044
150680
|
function deleteUserMemoryCandidates(db, ids) {
|
|
150045
150681
|
if (ids.length === 0)
|
|
150046
150682
|
return;
|
|
150047
|
-
const
|
|
150048
|
-
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);
|
|
150049
150685
|
}
|
|
150050
150686
|
function insertUserMemory(db, content, sourceCandidateIds) {
|
|
150051
150687
|
const now = Date.now();
|
|
@@ -165535,7 +166171,8 @@ var BaseEmbeddingConfigSchema = exports_external.object({
|
|
|
165535
166171
|
endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
|
|
165536
166172
|
api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
|
|
165537
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."),
|
|
165538
|
-
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.")
|
|
165539
166176
|
}).superRefine((data, ctx) => {
|
|
165540
166177
|
if (data.provider === "openai-compatible" && !data.endpoint?.trim()) {
|
|
165541
166178
|
ctx.addIssue({
|
|
@@ -165556,7 +166193,8 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
|
|
|
165556
166193
|
if (data.provider === "local") {
|
|
165557
166194
|
return {
|
|
165558
166195
|
provider: "local",
|
|
165559
|
-
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 } : {}
|
|
165560
166198
|
};
|
|
165561
166199
|
}
|
|
165562
166200
|
if (data.provider === "openai-compatible") {
|
|
@@ -165569,7 +166207,8 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
|
|
|
165569
166207
|
endpoint: data.endpoint?.trim() ?? "",
|
|
165570
166208
|
...apiKey ? { api_key: apiKey } : {},
|
|
165571
166209
|
...inputType ? { input_type: inputType } : {},
|
|
165572
|
-
...truncate ? { truncate } : {}
|
|
166210
|
+
...truncate ? { truncate } : {},
|
|
166211
|
+
...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
|
|
165573
166212
|
};
|
|
165574
166213
|
}
|
|
165575
166214
|
return { provider: "off" };
|
|
@@ -165651,6 +166290,441 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
165651
166290
|
// ../plugin/src/features/magic-context/memory/embedding.ts
|
|
165652
166291
|
init_logger();
|
|
165653
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
|
+
|
|
165654
166728
|
// ../plugin/src/features/magic-context/memory/cosine-similarity.ts
|
|
165655
166729
|
function cosineSimilarity(a, b) {
|
|
165656
166730
|
if (a.length !== b.length) {
|
|
@@ -165809,19 +166883,19 @@ function isArrayLikeNumber(value) {
|
|
|
165809
166883
|
}
|
|
165810
166884
|
return arr.length === 0 || typeof arr[0] === "number";
|
|
165811
166885
|
}
|
|
165812
|
-
function
|
|
166886
|
+
function toFloat32Array3(values) {
|
|
165813
166887
|
return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
|
|
165814
166888
|
}
|
|
165815
166889
|
function extractBatchEmbeddings(result, expectedCount) {
|
|
165816
166890
|
const { data } = result;
|
|
165817
166891
|
if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
|
|
165818
|
-
return data.map((entry) =>
|
|
166892
|
+
return data.map((entry) => toFloat32Array3(entry));
|
|
165819
166893
|
}
|
|
165820
166894
|
if (!isArrayLikeNumber(data)) {
|
|
165821
166895
|
log("[magic-context] embedding batch returned unexpected data shape");
|
|
165822
166896
|
return Array.from({ length: expectedCount }, () => null);
|
|
165823
166897
|
}
|
|
165824
|
-
const flatData =
|
|
166898
|
+
const flatData = toFloat32Array3(data);
|
|
165825
166899
|
const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
|
|
165826
166900
|
if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
|
|
165827
166901
|
log("[magic-context] embedding batch returned invalid dimensions");
|
|
@@ -165836,6 +166910,7 @@ function extractBatchEmbeddings(result, expectedCount) {
|
|
|
165836
166910
|
|
|
165837
166911
|
class LocalEmbeddingProvider {
|
|
165838
166912
|
modelId;
|
|
166913
|
+
maxInputTokens;
|
|
165839
166914
|
model;
|
|
165840
166915
|
pipeline = null;
|
|
165841
166916
|
initPromise = null;
|
|
@@ -165843,8 +166918,9 @@ class LocalEmbeddingProvider {
|
|
|
165843
166918
|
disposing = false;
|
|
165844
166919
|
disposePromise = null;
|
|
165845
166920
|
inFlightWaiters = [];
|
|
165846
|
-
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
166921
|
+
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
|
|
165847
166922
|
this.model = model;
|
|
166923
|
+
this.maxInputTokens = maxInputTokens;
|
|
165848
166924
|
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
165849
166925
|
}
|
|
165850
166926
|
async initialize() {
|
|
@@ -166099,6 +167175,7 @@ var FETCH_TIMEOUT_MS = 30000;
|
|
|
166099
167175
|
|
|
166100
167176
|
class OpenAICompatibleEmbeddingProvider {
|
|
166101
167177
|
modelId;
|
|
167178
|
+
maxInputTokens;
|
|
166102
167179
|
endpoint;
|
|
166103
167180
|
model;
|
|
166104
167181
|
apiKey;
|
|
@@ -166115,11 +167192,13 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166115
167192
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
166116
167193
|
this.inputType = options.inputType?.trim() ?? "";
|
|
166117
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;
|
|
166118
167196
|
this.modelId = getEmbeddingProviderIdentity({
|
|
166119
167197
|
provider: "openai-compatible",
|
|
166120
167198
|
endpoint: this.endpoint,
|
|
166121
167199
|
model: this.model,
|
|
166122
|
-
...this.apiKey ? { api_key: this.apiKey } : {}
|
|
167200
|
+
...this.apiKey ? { api_key: this.apiKey } : {},
|
|
167201
|
+
...this.inputType ? { input_type: this.inputType } : {}
|
|
166123
167202
|
});
|
|
166124
167203
|
}
|
|
166125
167204
|
async initialize() {
|
|
@@ -166310,7 +167389,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166310
167389
|
}
|
|
166311
167390
|
|
|
166312
167391
|
// ../plugin/src/features/magic-context/project-embedding-registry.ts
|
|
166313
|
-
import { createHash as
|
|
167392
|
+
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
166314
167393
|
init_logger();
|
|
166315
167394
|
|
|
166316
167395
|
// ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
|
|
@@ -166318,7 +167397,7 @@ var saveStatements = new WeakMap;
|
|
|
166318
167397
|
var loadProjectStatements = new WeakMap;
|
|
166319
167398
|
var loadUnembeddedStatements = new WeakMap;
|
|
166320
167399
|
var countEmbeddedStatements = new WeakMap;
|
|
166321
|
-
var
|
|
167400
|
+
var clearProjectStatements2 = new WeakMap;
|
|
166322
167401
|
var distinctModelIdStatements = new WeakMap;
|
|
166323
167402
|
function getSaveStatement(db) {
|
|
166324
167403
|
let stmt = saveStatements.get(db);
|
|
@@ -166366,12 +167445,12 @@ function getCountEmbeddedStatement(db) {
|
|
|
166366
167445
|
}
|
|
166367
167446
|
return stmt;
|
|
166368
167447
|
}
|
|
166369
|
-
function
|
|
166370
|
-
let stmt =
|
|
167448
|
+
function getClearProjectStatement2(db) {
|
|
167449
|
+
let stmt = clearProjectStatements2.get(db);
|
|
166371
167450
|
if (!stmt) {
|
|
166372
167451
|
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
166373
167452
|
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
166374
|
-
|
|
167453
|
+
clearProjectStatements2.set(db, stmt);
|
|
166375
167454
|
}
|
|
166376
167455
|
return stmt;
|
|
166377
167456
|
}
|
|
@@ -166407,7 +167486,7 @@ function countEmbeddedCommits(db, projectPath) {
|
|
|
166407
167486
|
return row?.count ?? 0;
|
|
166408
167487
|
}
|
|
166409
167488
|
function clearProjectCommitEmbeddings(db, projectPath) {
|
|
166410
|
-
return
|
|
167489
|
+
return getClearProjectStatement2(db).run(projectPath).changes;
|
|
166411
167490
|
}
|
|
166412
167491
|
function getDistinctCommitEmbeddingModelIds(db, projectPath) {
|
|
166413
167492
|
const rows = getDistinctModelIdStatement(db).all(projectPath);
|
|
@@ -166533,9 +167612,83 @@ function releaseGitSweepLease(db, projectPath, holderId) {
|
|
|
166533
167612
|
});
|
|
166534
167613
|
}
|
|
166535
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
|
+
|
|
166536
167686
|
// ../plugin/src/features/magic-context/project-embedding-registry.ts
|
|
166537
167687
|
var OFF_PROVIDER_IDENTITY = "embedding-provider:off";
|
|
166538
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;
|
|
166539
167692
|
var projectRegistrations = new Map;
|
|
166540
167693
|
var loadUnembeddedMemoriesStatements = new WeakMap;
|
|
166541
167694
|
var globalRegistrationGeneration = 0;
|
|
@@ -166544,7 +167697,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
166544
167697
|
if (!config2 || config2.provider === "local") {
|
|
166545
167698
|
return {
|
|
166546
167699
|
provider: "local",
|
|
166547
|
-
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
|
+
} : {}
|
|
166548
167704
|
};
|
|
166549
167705
|
}
|
|
166550
167706
|
if (config2.provider === "openai-compatible") {
|
|
@@ -166557,7 +167713,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
166557
167713
|
endpoint: config2.endpoint.trim(),
|
|
166558
167714
|
...apiKey ? { api_key: apiKey } : {},
|
|
166559
167715
|
...inputType ? { input_type: inputType } : {},
|
|
166560
|
-
...truncate ? { truncate } : {}
|
|
167716
|
+
...truncate ? { truncate } : {},
|
|
167717
|
+
...config2.max_input_tokens ? {
|
|
167718
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
167719
|
+
} : {}
|
|
166561
167720
|
};
|
|
166562
167721
|
}
|
|
166563
167722
|
return { provider: "off" };
|
|
@@ -166575,10 +167734,11 @@ function createProvider(config2) {
|
|
|
166575
167734
|
model: config2.model,
|
|
166576
167735
|
apiKey: config2.api_key,
|
|
166577
167736
|
inputType: config2.input_type,
|
|
166578
|
-
truncate: config2.truncate
|
|
167737
|
+
truncate: config2.truncate,
|
|
167738
|
+
maxInputTokens: config2.max_input_tokens
|
|
166579
167739
|
});
|
|
166580
167740
|
}
|
|
166581
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
167741
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
166582
167742
|
}
|
|
166583
167743
|
function stableStringify2(value) {
|
|
166584
167744
|
if (Array.isArray(value)) {
|
|
@@ -166591,7 +167751,7 @@ function stableStringify2(value) {
|
|
|
166591
167751
|
return JSON.stringify(value);
|
|
166592
167752
|
}
|
|
166593
167753
|
function sha256Prefix(value, length = 16) {
|
|
166594
|
-
return
|
|
167754
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, length);
|
|
166595
167755
|
}
|
|
166596
167756
|
function getRuntimeFingerprint(config2) {
|
|
166597
167757
|
if (config2.provider === "off") {
|
|
@@ -166599,6 +167759,18 @@ function getRuntimeFingerprint(config2) {
|
|
|
166599
167759
|
}
|
|
166600
167760
|
return `${getEmbeddingProviderIdentity(config2)}:${sha256Prefix(stableStringify2(config2))}`;
|
|
166601
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
|
+
}
|
|
166602
167774
|
function sameFeatures(a, b) {
|
|
166603
167775
|
return a.memoryEnabled === b.memoryEnabled && a.gitCommitEnabled === b.gitCommitEnabled;
|
|
166604
167776
|
}
|
|
@@ -166615,7 +167787,8 @@ function snapshotFor(registration) {
|
|
|
166615
167787
|
features: { ...registration.features },
|
|
166616
167788
|
enabled,
|
|
166617
167789
|
gitCommitEnabled,
|
|
166618
|
-
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId
|
|
167790
|
+
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
|
|
167791
|
+
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId
|
|
166619
167792
|
};
|
|
166620
167793
|
}
|
|
166621
167794
|
function disposeProvider(provider) {
|
|
@@ -166635,7 +167808,7 @@ function anyStoredModelIdIsStale(storedIds, currentId) {
|
|
|
166635
167808
|
}
|
|
166636
167809
|
return false;
|
|
166637
167810
|
}
|
|
166638
|
-
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, features) {
|
|
167811
|
+
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, currentChunkIdentity, features) {
|
|
166639
167812
|
if (currentProviderIdentity === OFF_PROVIDER_IDENTITY) {
|
|
166640
167813
|
return false;
|
|
166641
167814
|
}
|
|
@@ -166656,6 +167829,14 @@ function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity,
|
|
|
166656
167829
|
wiped = true;
|
|
166657
167830
|
}
|
|
166658
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
|
+
}
|
|
166659
167840
|
})();
|
|
166660
167841
|
return wiped;
|
|
166661
167842
|
}
|
|
@@ -166663,10 +167844,11 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
166663
167844
|
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
166664
167845
|
const providerIdentity = getEmbeddingProviderIdentity(resolvedConfig);
|
|
166665
167846
|
const runtimeFingerprint = getRuntimeFingerprint(resolvedConfig);
|
|
167847
|
+
const chunkModelId = getChunkEmbeddingModelId(resolvedConfig, providerIdentity);
|
|
166666
167848
|
const prior = projectRegistrations.get(projectIdentity);
|
|
166667
167849
|
const canReuseProvider = prior !== undefined && !prior.observationMode && prior.runtimeFingerprint === runtimeFingerprint && prior.providerIdentity === providerIdentity;
|
|
166668
|
-
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, features);
|
|
166669
|
-
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;
|
|
166670
167852
|
const generation = generationChanged ? ++globalRegistrationGeneration : prior.generation;
|
|
166671
167853
|
const registration = {
|
|
166672
167854
|
projectIdentity,
|
|
@@ -166678,6 +167860,7 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
166678
167860
|
generation,
|
|
166679
167861
|
features: { ...features },
|
|
166680
167862
|
modelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : providerIdentity,
|
|
167863
|
+
chunkModelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : chunkModelId,
|
|
166681
167864
|
observationMode: false
|
|
166682
167865
|
};
|
|
166683
167866
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -166700,6 +167883,7 @@ function registerProjectInObservationMode(db, projectIdentity, sourceDirectory,
|
|
|
166700
167883
|
generation,
|
|
166701
167884
|
features: { memoryEnabled: false, gitCommitEnabled: false },
|
|
166702
167885
|
modelId: "off",
|
|
167886
|
+
chunkModelId: "off",
|
|
166703
167887
|
observationMode: true
|
|
166704
167888
|
};
|
|
166705
167889
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -166710,6 +167894,15 @@ function getProjectEmbeddingSnapshot(projectIdentity) {
|
|
|
166710
167894
|
const registration = projectRegistrations.get(projectIdentity);
|
|
166711
167895
|
return registration ? snapshotFor(registration) : null;
|
|
166712
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
|
+
}
|
|
166713
167906
|
function getOrCreateProjectProvider(registration) {
|
|
166714
167907
|
if (registration.providerIdentity === OFF_PROVIDER_IDENTITY || registration.observationMode) {
|
|
166715
167908
|
return null;
|
|
@@ -166804,6 +167997,131 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
166804
167997
|
return 0;
|
|
166805
167998
|
}
|
|
166806
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
|
+
}
|
|
166807
168125
|
|
|
166808
168126
|
// ../plugin/src/features/magic-context/memory/embedding.ts
|
|
166809
168127
|
var DEFAULT_EMBEDDING_CONFIG = {
|
|
@@ -166823,10 +168141,11 @@ function createProvider2(config2) {
|
|
|
166823
168141
|
model: config2.model,
|
|
166824
168142
|
apiKey: config2.api_key,
|
|
166825
168143
|
inputType: config2.input_type,
|
|
166826
|
-
truncate: config2.truncate
|
|
168144
|
+
truncate: config2.truncate,
|
|
168145
|
+
maxInputTokens: config2.max_input_tokens
|
|
166827
168146
|
});
|
|
166828
168147
|
}
|
|
166829
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
168148
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
166830
168149
|
}
|
|
166831
168150
|
function getOrCreateProvider() {
|
|
166832
168151
|
if (provider) {
|
|
@@ -167069,6 +168388,7 @@ init_logger();
|
|
|
167069
168388
|
// ../plugin/src/features/magic-context/memory/storage-memory-fts.ts
|
|
167070
168389
|
var DEFAULT_SEARCH_LIMIT = 10;
|
|
167071
168390
|
var searchStatements = new WeakMap;
|
|
168391
|
+
var unionSearchStatements = new Map;
|
|
167072
168392
|
function getSearchStatement(db) {
|
|
167073
168393
|
let stmt = searchStatements.get(db);
|
|
167074
168394
|
if (!stmt) {
|
|
@@ -167077,6 +168397,23 @@ function getSearchStatement(db) {
|
|
|
167077
168397
|
}
|
|
167078
168398
|
return stmt;
|
|
167079
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
|
+
}
|
|
167080
168417
|
function sanitizeFtsQuery(query) {
|
|
167081
168418
|
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
167082
168419
|
if (tokens.length === 0)
|
|
@@ -167095,6 +168432,28 @@ function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT)
|
|
|
167095
168432
|
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
167096
168433
|
return rows.map(toMemory);
|
|
167097
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
|
+
}
|
|
167098
168457
|
|
|
167099
168458
|
// ../plugin/src/features/magic-context/git-commits/search-git-commits.ts
|
|
167100
168459
|
var ftsStatements = new WeakMap;
|
|
@@ -167387,7 +168746,7 @@ async function sweepGitCommits(args) {
|
|
|
167387
168746
|
}
|
|
167388
168747
|
|
|
167389
168748
|
// ../plugin/src/plugin/embedding-bootstrap-helpers.ts
|
|
167390
|
-
import { createHash as
|
|
168749
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
167391
168750
|
init_logger();
|
|
167392
168751
|
var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
167393
168752
|
"embedding.api_key",
|
|
@@ -167409,7 +168768,7 @@ var EMBEDDING_WARNING_TERMS = [
|
|
|
167409
168768
|
];
|
|
167410
168769
|
var loggedFailureSignatures = new Map;
|
|
167411
168770
|
function sha256Prefix2(value, length = 16) {
|
|
167412
|
-
return
|
|
168771
|
+
return createHash10("sha256").update(value).digest("hex").slice(0, length);
|
|
167413
168772
|
}
|
|
167414
168773
|
function warningLooksEmbeddingRelated(message) {
|
|
167415
168774
|
const lower = message.toLowerCase();
|
|
@@ -168451,6 +169810,88 @@ function registerCtxDreamCommand(pi, deps) {
|
|
|
168451
169810
|
});
|
|
168452
169811
|
}
|
|
168453
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
|
+
|
|
168454
169895
|
// ../plugin/src/hooks/magic-context/execute-flush.ts
|
|
168455
169896
|
init_logger();
|
|
168456
169897
|
function executeFlush(db, sessionId) {
|
|
@@ -168866,6 +170307,7 @@ function computePiWorkMetrics(sessionEntries) {
|
|
|
168866
170307
|
|
|
168867
170308
|
// ../plugin/src/hooks/magic-context/apply-operations.ts
|
|
168868
170309
|
var USER_DROP_PREVIEW_CHARS = 250;
|
|
170310
|
+
var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
168869
170311
|
function buildReplacementContent(tagId, target) {
|
|
168870
170312
|
const role = target.message?.info.role;
|
|
168871
170313
|
if (role !== "user") {
|
|
@@ -168891,6 +170333,7 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
168891
170333
|
const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
|
|
168892
170334
|
const protectedTagIds = protectedTags > 0 ? new Set(tags.filter((tag) => tag.status === "active").map((tag) => tag.tagNumber).sort((left, right) => right - left).slice(0, protectedTags)) : new Set;
|
|
168893
170335
|
const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
|
|
170336
|
+
const skeletonWindow = new Set(tags.filter((tag) => tag.type === "tool").map((tag) => tag.tagNumber).sort((left, right) => right - left).slice(0, RECENT_TOOL_SKELETON_WINDOW));
|
|
168894
170337
|
for (const pendingOp of pendingOps) {
|
|
168895
170338
|
const tagStatus = tagStatusById.get(pendingOp.tagId);
|
|
168896
170339
|
if (tagStatus === "compacted" || tagStatus === "dropped") {
|
|
@@ -168903,14 +170346,25 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
168903
170346
|
const target = targets.get(pendingOp.tagId);
|
|
168904
170347
|
const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
|
|
168905
170348
|
if (isToolTag) {
|
|
168906
|
-
|
|
168907
|
-
|
|
168908
|
-
|
|
168909
|
-
|
|
168910
|
-
|
|
168911
|
-
|
|
170349
|
+
if (skeletonWindow.has(pendingOp.tagId)) {
|
|
170350
|
+
const truncResult = target?.truncate?.() ?? "absent";
|
|
170351
|
+
if (truncResult === "incomplete") {
|
|
170352
|
+
continue;
|
|
170353
|
+
}
|
|
170354
|
+
if (truncResult === "truncated") {
|
|
170355
|
+
didMutateMessage = true;
|
|
170356
|
+
}
|
|
170357
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, "truncated");
|
|
170358
|
+
} else {
|
|
170359
|
+
const dropResult = target?.drop?.() ?? "absent";
|
|
170360
|
+
if (dropResult === "incomplete") {
|
|
170361
|
+
continue;
|
|
170362
|
+
}
|
|
170363
|
+
if (dropResult === "removed") {
|
|
170364
|
+
didMutateMessage = true;
|
|
170365
|
+
}
|
|
170366
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, "full");
|
|
168912
170367
|
}
|
|
168913
|
-
updateTagDropMode(db, sessionId, pendingOp.tagId, "full");
|
|
168914
170368
|
} else if (target) {
|
|
168915
170369
|
const changed = target.setContent(buildReplacementContent(pendingOp.tagId, target));
|
|
168916
170370
|
if (changed)
|
|
@@ -170573,53 +172027,6 @@ ${body}
|
|
|
170573
172027
|
</system-reminder>`;
|
|
170574
172028
|
}
|
|
170575
172029
|
|
|
170576
|
-
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
170577
|
-
var V2_MEMORY_CATEGORIES = [
|
|
170578
|
-
"PROJECT_RULES",
|
|
170579
|
-
"ARCHITECTURE",
|
|
170580
|
-
"CONSTRAINTS",
|
|
170581
|
-
"CONFIG_VALUES",
|
|
170582
|
-
"NAMING"
|
|
170583
|
-
];
|
|
170584
|
-
var PROMOTABLE_CATEGORIES = [
|
|
170585
|
-
"PROJECT_RULES",
|
|
170586
|
-
"ARCHITECTURE",
|
|
170587
|
-
"CONSTRAINTS",
|
|
170588
|
-
"CONFIG_VALUES",
|
|
170589
|
-
"NAMING",
|
|
170590
|
-
"ARCHITECTURE_DECISIONS",
|
|
170591
|
-
"CONFIG_DEFAULTS",
|
|
170592
|
-
"USER_PREFERENCES",
|
|
170593
|
-
"USER_DIRECTIVES",
|
|
170594
|
-
"ENVIRONMENT",
|
|
170595
|
-
"WORKFLOW_RULES",
|
|
170596
|
-
"KNOWN_ISSUES"
|
|
170597
|
-
];
|
|
170598
|
-
var CATEGORY_PRIORITY = [
|
|
170599
|
-
"PROJECT_RULES",
|
|
170600
|
-
"ARCHITECTURE",
|
|
170601
|
-
"CONSTRAINTS",
|
|
170602
|
-
"CONFIG_VALUES",
|
|
170603
|
-
"NAMING",
|
|
170604
|
-
"USER_DIRECTIVES",
|
|
170605
|
-
"USER_PREFERENCES",
|
|
170606
|
-
"CONFIG_DEFAULTS",
|
|
170607
|
-
"ARCHITECTURE_DECISIONS",
|
|
170608
|
-
"ENVIRONMENT",
|
|
170609
|
-
"WORKFLOW_RULES",
|
|
170610
|
-
"KNOWN_ISSUES"
|
|
170611
|
-
];
|
|
170612
|
-
var MEMORY_CATEGORY_ORDER_UNKNOWN = 99;
|
|
170613
|
-
var MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
170614
|
-
acc[category] = index;
|
|
170615
|
-
return acc;
|
|
170616
|
-
}, {});
|
|
170617
|
-
var MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
170618
|
-
var CATEGORY_DEFAULT_TTL = {
|
|
170619
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
170620
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
170621
|
-
};
|
|
170622
|
-
|
|
170623
172030
|
// ../plugin/src/shared/bounded-session-map.ts
|
|
170624
172031
|
class BoundedSessionMap {
|
|
170625
172032
|
maxEntries;
|
|
@@ -171030,26 +172437,40 @@ ${sections.join(`
|
|
|
171030
172437
|
var DEFAULT_MEMORY_BUDGET_TOKENS = 8000;
|
|
171031
172438
|
var MEMORY_BLOCK_WRAPPER_TOKENS = 6;
|
|
171032
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
|
+
}
|
|
171033
172463
|
var maxCompartmentSeqStatements = new WeakMap;
|
|
171034
172464
|
var maxMemoryIdStatements = new WeakMap;
|
|
171035
172465
|
var legacyCompartmentCountStatements = new WeakMap;
|
|
171036
172466
|
var m0CompartmentStatements = new WeakMap;
|
|
171037
172467
|
var newCompartmentStatements = new WeakMap;
|
|
171038
|
-
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
171039
|
-
const selectionOrder = [...memories].sort(
|
|
171040
|
-
if (a.status === "permanent" && b.status !== "permanent")
|
|
171041
|
-
return -1;
|
|
171042
|
-
if (b.status === "permanent" && a.status !== "permanent")
|
|
171043
|
-
return 1;
|
|
171044
|
-
const importanceDiff = (b.importance ?? 50) - (a.importance ?? 50);
|
|
171045
|
-
if (importanceDiff !== 0)
|
|
171046
|
-
return importanceDiff;
|
|
171047
|
-
return a.id - b.id;
|
|
171048
|
-
});
|
|
172468
|
+
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions = {}) {
|
|
172469
|
+
const selectionOrder = [...memories].sort(memorySelectionOrder);
|
|
171049
172470
|
const selected = [];
|
|
171050
172471
|
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
171051
172472
|
for (const memory of selectionOrder) {
|
|
171052
|
-
const memoryTokens = estimateTokens(renderMemoryLineV2(memory));
|
|
172473
|
+
const memoryTokens = estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
171053
172474
|
if (usedTokens + memoryTokens > budgetTokens)
|
|
171054
172475
|
continue;
|
|
171055
172476
|
selected.push(memory);
|
|
@@ -171058,16 +172479,70 @@ function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
|
171058
172479
|
if (selected.length < memories.length) {
|
|
171059
172480
|
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
171060
172481
|
}
|
|
171061
|
-
const renderOrder = [...selected].sort(
|
|
171062
|
-
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[a.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
171063
|
-
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[b.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
171064
|
-
const categoryDiff = aPriority - bPriority;
|
|
171065
|
-
if (categoryDiff !== 0)
|
|
171066
|
-
return categoryDiff;
|
|
171067
|
-
return a.id - b.id;
|
|
171068
|
-
});
|
|
172482
|
+
const renderOrder = [...selected].sort(memoryRenderOrder);
|
|
171069
172483
|
return { selected, renderOrder };
|
|
171070
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
|
+
}
|
|
171071
172546
|
function trimUserMemoriesToBudget(memories, budgetTokens) {
|
|
171072
172547
|
const selected = [];
|
|
171073
172548
|
let usedTokens = 0;
|
|
@@ -171080,15 +172555,16 @@ function trimUserMemoriesToBudget(memories, budgetTokens) {
|
|
|
171080
172555
|
}
|
|
171081
172556
|
return selected;
|
|
171082
172557
|
}
|
|
171083
|
-
function renderMemoryLineV2(memory) {
|
|
171084
|
-
|
|
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>`;
|
|
171085
172561
|
}
|
|
171086
|
-
function renderMemoryBlockV2(memories, wrapper = "project-memory") {
|
|
172562
|
+
function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions = {}) {
|
|
171087
172563
|
if (memories.length === 0)
|
|
171088
172564
|
return "";
|
|
171089
172565
|
const lines = [`<${wrapper}>`];
|
|
171090
172566
|
for (const memory of memories) {
|
|
171091
|
-
lines.push(renderMemoryLineV2(memory));
|
|
172567
|
+
lines.push(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
171092
172568
|
}
|
|
171093
172569
|
lines.push(`</${wrapper}>`);
|
|
171094
172570
|
return lines.join(`
|
|
@@ -171682,7 +173158,7 @@ async function ensureMemoryEmbeddings(args) {
|
|
|
171682
173158
|
continue;
|
|
171683
173159
|
}
|
|
171684
173160
|
saveEmbedding(args.db, memory.id, embedding, result.modelId);
|
|
171685
|
-
staged.set(memory.id, embedding);
|
|
173161
|
+
staged.set(memory.id, { embedding, modelId: result.modelId });
|
|
171686
173162
|
}
|
|
171687
173163
|
})();
|
|
171688
173164
|
const currentSnapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -171773,6 +173249,37 @@ function previewText(text) {
|
|
|
171773
173249
|
}
|
|
171774
173250
|
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}…`;
|
|
171775
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
|
+
}
|
|
171776
173283
|
function getMessageSearchStatement(db) {
|
|
171777
173284
|
let stmt = messageSearchStatements.get(db);
|
|
171778
173285
|
if (!stmt) {
|
|
@@ -171781,6 +173288,30 @@ function getMessageSearchStatement(db) {
|
|
|
171781
173288
|
}
|
|
171782
173289
|
return stmt;
|
|
171783
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
|
+
}
|
|
171784
173315
|
function getMessageOrdinal(value) {
|
|
171785
173316
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
171786
173317
|
return value;
|
|
@@ -171796,25 +173327,63 @@ async function getSemanticScores(args) {
|
|
|
171796
173327
|
if (!args.queryEmbedding || args.memories.length === 0) {
|
|
171797
173328
|
return semanticScores;
|
|
171798
173329
|
}
|
|
171799
|
-
|
|
171800
|
-
|
|
171801
|
-
|
|
171802
|
-
|
|
171803
|
-
|
|
171804
|
-
|
|
171805
|
-
|
|
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;
|
|
171806
173352
|
for (const memory of args.memories) {
|
|
171807
|
-
const
|
|
171808
|
-
if (!
|
|
173353
|
+
const identity = memoryWorkspaceIdentity(memory, workspace);
|
|
173354
|
+
if (!identity)
|
|
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)
|
|
171809
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)));
|
|
171810
173380
|
}
|
|
171811
|
-
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
|
|
171812
173381
|
}
|
|
171813
173382
|
return semanticScores;
|
|
171814
173383
|
}
|
|
171815
173384
|
function getFtsMatches(args) {
|
|
171816
173385
|
try {
|
|
171817
|
-
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);
|
|
171818
173387
|
} catch (error51) {
|
|
171819
173388
|
log(`[search] FTS query failed for "${args.query}": ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
171820
173389
|
return [];
|
|
@@ -171828,8 +173397,11 @@ function selectSemanticCandidates(args) {
|
|
|
171828
173397
|
return args.memories;
|
|
171829
173398
|
}
|
|
171830
173399
|
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
171831
|
-
const
|
|
171832
|
-
|
|
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;
|
|
171833
173405
|
for (const memoryId of cachedEmbeddings.keys()) {
|
|
171834
173406
|
candidateIds.add(memoryId);
|
|
171835
173407
|
}
|
|
@@ -171871,7 +173443,8 @@ function mergeMemoryResults(args) {
|
|
|
171871
173443
|
score,
|
|
171872
173444
|
memoryId: memory.id,
|
|
171873
173445
|
category: memory.category,
|
|
171874
|
-
matchType
|
|
173446
|
+
matchType,
|
|
173447
|
+
sourceName: args.sourceNameByMemoryId?.get(memory.id)
|
|
171875
173448
|
});
|
|
171876
173449
|
}
|
|
171877
173450
|
return results.sort((left, right) => {
|
|
@@ -171885,7 +173458,7 @@ async function searchMemories(args) {
|
|
|
171885
173458
|
if (!args.memoryEnabled) {
|
|
171886
173459
|
return [];
|
|
171887
173460
|
}
|
|
171888
|
-
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);
|
|
171889
173462
|
if (memories.length === 0) {
|
|
171890
173463
|
return [];
|
|
171891
173464
|
}
|
|
@@ -171893,26 +173466,43 @@ async function searchMemories(args) {
|
|
|
171893
173466
|
db: args.db,
|
|
171894
173467
|
projectPath: args.projectPath,
|
|
171895
173468
|
query: args.query,
|
|
171896
|
-
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
173469
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT,
|
|
173470
|
+
workspace: args.workspace
|
|
171897
173471
|
});
|
|
171898
173472
|
const ftsScores = getFtsScores(ftsMatches);
|
|
171899
173473
|
const semanticCandidates = selectSemanticCandidates({
|
|
171900
173474
|
memories,
|
|
171901
173475
|
projectPath: args.projectPath,
|
|
171902
|
-
ftsMatches
|
|
173476
|
+
ftsMatches,
|
|
173477
|
+
workspace: args.workspace
|
|
171903
173478
|
});
|
|
171904
173479
|
const semanticScores = await getSemanticScores({
|
|
171905
173480
|
db: args.db,
|
|
171906
173481
|
projectPath: args.projectPath,
|
|
171907
173482
|
memories: semanticCandidates,
|
|
171908
|
-
queryEmbedding: args.queryEmbedding
|
|
173483
|
+
queryEmbedding: args.queryEmbedding,
|
|
173484
|
+
queryModelId: args.queryModelId,
|
|
173485
|
+
workspace: args.workspace
|
|
171909
173486
|
});
|
|
171910
173487
|
return mergeMemoryResults({
|
|
171911
173488
|
memories,
|
|
171912
173489
|
semanticScores,
|
|
171913
173490
|
ftsScores,
|
|
171914
173491
|
limit: args.limit,
|
|
171915
|
-
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
|
+
})
|
|
171916
173506
|
});
|
|
171917
173507
|
}
|
|
171918
173508
|
function linearDecayScore(rank, total) {
|
|
@@ -171943,7 +173533,13 @@ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
|
|
|
171943
173533
|
return result;
|
|
171944
173534
|
}
|
|
171945
173535
|
var RRF_K = 60;
|
|
171946
|
-
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
|
+
}
|
|
171947
173543
|
function searchMessages(args) {
|
|
171948
173544
|
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
171949
173545
|
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
@@ -171960,20 +173556,31 @@ function searchMessages(args) {
|
|
|
171960
173556
|
role: row.role
|
|
171961
173557
|
}));
|
|
171962
173558
|
}
|
|
173559
|
+
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId);
|
|
171963
173560
|
const queryLists = [];
|
|
171964
173561
|
if (baseQuery.length > 0) {
|
|
171965
|
-
queryLists.push(
|
|
173562
|
+
queryLists.push({
|
|
173563
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff),
|
|
173564
|
+
weight: 1
|
|
173565
|
+
});
|
|
171966
173566
|
}
|
|
173567
|
+
const probeWeights = new Map;
|
|
171967
173568
|
for (const probe of probes) {
|
|
171968
173569
|
const probeQuery = sanitizeFtsQuery(probe);
|
|
171969
173570
|
if (probeQuery.length === 0)
|
|
171970
173571
|
continue;
|
|
171971
|
-
|
|
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
|
+
});
|
|
171972
173579
|
}
|
|
171973
173580
|
const fused = new Map;
|
|
171974
173581
|
for (const list of queryLists) {
|
|
171975
|
-
list.forEach((row, rank) => {
|
|
171976
|
-
const rrf =
|
|
173582
|
+
list.rows.forEach((row, rank) => {
|
|
173583
|
+
const rrf = list.weight / (RRF_K + rank);
|
|
171977
173584
|
const existing = fused.get(row.messageId);
|
|
171978
173585
|
if (existing) {
|
|
171979
173586
|
existing.score += rrf;
|
|
@@ -171983,26 +173590,107 @@ function searchMessages(args) {
|
|
|
171983
173590
|
});
|
|
171984
173591
|
}
|
|
171985
173592
|
for (const entry of fused.values()) {
|
|
171986
|
-
|
|
171987
|
-
|
|
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;
|
|
171988
173602
|
}
|
|
171989
173603
|
}
|
|
171990
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);
|
|
171991
|
-
|
|
171992
|
-
return ranked.map((entry) => ({
|
|
173605
|
+
return ranked.map((entry, rank) => ({
|
|
171993
173606
|
source: "message",
|
|
171994
173607
|
content: previewText(entry.row.content),
|
|
171995
|
-
score:
|
|
173608
|
+
score: linearDecayScore(rank, ranked.length),
|
|
171996
173609
|
messageOrdinal: entry.row.messageOrdinal,
|
|
171997
173610
|
messageId: entry.row.messageId,
|
|
171998
173611
|
role: entry.row.role
|
|
171999
173612
|
}));
|
|
172000
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
|
+
}
|
|
172001
173688
|
function getSourceBoost(result) {
|
|
172002
173689
|
switch (result.source) {
|
|
172003
173690
|
case "memory":
|
|
172004
173691
|
return MEMORY_SOURCE_BOOST;
|
|
172005
173692
|
case "message":
|
|
173693
|
+
case "compartment":
|
|
172006
173694
|
return MESSAGE_SOURCE_BOOST;
|
|
172007
173695
|
case "git_commit":
|
|
172008
173696
|
return GIT_COMMIT_SOURCE_BOOST;
|
|
@@ -172020,6 +173708,9 @@ function compareUnifiedResults(left, right) {
|
|
|
172020
173708
|
if (left.source === "message" && right.source === "message") {
|
|
172021
173709
|
return left.messageOrdinal - right.messageOrdinal;
|
|
172022
173710
|
}
|
|
173711
|
+
if (left.source === "compartment" && right.source === "compartment") {
|
|
173712
|
+
return left.startOrdinal - right.startOrdinal;
|
|
173713
|
+
}
|
|
172023
173714
|
if (left.source === "git_commit" && right.source === "git_commit") {
|
|
172024
173715
|
return right.committedAtMs - left.committedAtMs;
|
|
172025
173716
|
}
|
|
@@ -172070,10 +173761,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172070
173761
|
const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
|
|
172071
173762
|
const gitCommitsEnabled = options.gitCommitsEnabled ?? false;
|
|
172072
173763
|
const activeSources = resolveSources(options.sources);
|
|
172073
|
-
const
|
|
173764
|
+
const memoryFeatureEnabled = options.memoryEnabled ?? true;
|
|
173765
|
+
const runMemory = activeSources.has("memory") && memoryFeatureEnabled;
|
|
172074
173766
|
const runMessages = activeSources.has("message");
|
|
172075
173767
|
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
172076
|
-
const
|
|
173768
|
+
const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
|
|
173769
|
+
const needsEmbedding = (runMemory || runGitCommits || runCompartmentChunks) && embeddingEnabled && isEmbeddingRuntimeEnabled();
|
|
172077
173770
|
const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error51) => {
|
|
172078
173771
|
log(`[search] query embedding failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
172079
173772
|
return null;
|
|
@@ -172089,6 +173782,24 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172089
173782
|
probes: messageProbes
|
|
172090
173783
|
}) : [];
|
|
172091
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
|
+
});
|
|
172092
173803
|
const [memoryResults, gitCommitResults] = await Promise.all([
|
|
172093
173804
|
runMemory ? searchMemories({
|
|
172094
173805
|
db,
|
|
@@ -172097,6 +173808,8 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172097
173808
|
limit: tierLimit,
|
|
172098
173809
|
memoryEnabled: true,
|
|
172099
173810
|
queryEmbedding,
|
|
173811
|
+
queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null,
|
|
173812
|
+
workspace,
|
|
172100
173813
|
visibleMemoryIds: options.visibleMemoryIds
|
|
172101
173814
|
}) : Promise.resolve([]),
|
|
172102
173815
|
runGitCommits ? Promise.resolve(searchGitCommits({
|
|
@@ -172107,7 +173820,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172107
173820
|
queryEmbedding
|
|
172108
173821
|
})) : Promise.resolve([])
|
|
172109
173822
|
]);
|
|
172110
|
-
const results = [...memoryResults, ...
|
|
173823
|
+
const results = [...memoryResults, ...messageLikeResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
|
|
172111
173824
|
const countRetrievals = options.countRetrievals ?? true;
|
|
172112
173825
|
if (countRetrievals) {
|
|
172113
173826
|
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
@@ -172167,6 +173880,11 @@ function renderFragment(result, charCap) {
|
|
|
172167
173880
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
172168
173881
|
return truncate(compressed, charCap);
|
|
172169
173882
|
}
|
|
173883
|
+
case "compartment": {
|
|
173884
|
+
const source = result.snippet ?? result.title;
|
|
173885
|
+
const compressed = cavemanCompress(source, "ultra");
|
|
173886
|
+
return truncate(compressed, charCap);
|
|
173887
|
+
}
|
|
172170
173888
|
}
|
|
172171
173889
|
}
|
|
172172
173890
|
function buildAutoSearchHint(results, options = {}) {
|
|
@@ -173590,9 +175308,51 @@ function safeGetActiveUserMemoriesPi(db) {
|
|
|
173590
175308
|
function memoryProjectPath(state) {
|
|
173591
175309
|
return state.memoryEnabled === false ? undefined : state.projectIdentity;
|
|
173592
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
|
+
}
|
|
173593
175354
|
var EMPTY_PI_HARD_SIGNALS = {
|
|
173594
175355
|
systemHash: "",
|
|
173595
|
-
toolSetHash: "",
|
|
173596
175356
|
modelKey: "",
|
|
173597
175357
|
cacheExpired: false,
|
|
173598
175358
|
lastResponseTime: 0
|
|
@@ -173638,6 +175398,7 @@ function getCachedMarkers(db, state, compartmentsForNormalization) {
|
|
|
173638
175398
|
maxMutationId: meta3.cachedM0MaxMutationId,
|
|
173639
175399
|
maxMemoryMutationId: meta3.cachedM0MaxMemoryMutationId,
|
|
173640
175400
|
projectMemoryEpoch: meta3.cachedM0ProjectMemoryEpoch,
|
|
175401
|
+
workspaceFingerprint: meta3.cachedM0WorkspaceFingerprint,
|
|
173641
175402
|
projectUserProfileVersion: meta3.cachedM0ProjectUserProfileVersion,
|
|
173642
175403
|
projectDocsHash: meta3.cachedM0ProjectDocsHash,
|
|
173643
175404
|
sessionFactsVersion: meta3.cachedM0SessionFactsVersion,
|
|
@@ -173645,7 +175406,6 @@ function getCachedMarkers(db, state, compartmentsForNormalization) {
|
|
|
173645
175406
|
upgradeState: meta3.cachedM0UpgradeState,
|
|
173646
175407
|
lastBaselineEndMessageId: cachedBoundary,
|
|
173647
175408
|
systemHash: meta3.cachedM0SystemHash ?? "",
|
|
173648
|
-
toolSetHash: meta3.cachedM0ToolSetHash ?? "",
|
|
173649
175409
|
modelKey: meta3.cachedM0ModelKey ?? ""
|
|
173650
175410
|
};
|
|
173651
175411
|
}
|
|
@@ -173658,15 +175418,17 @@ function readCurrentMarkers(db, state, projectDocsHash) {
|
|
|
173658
175418
|
}
|
|
173659
175419
|
function readCurrentMarkersFromCompartments(db, state, compartments, projectDocsHash) {
|
|
173660
175420
|
const memPath = memoryProjectPath(state);
|
|
173661
|
-
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;
|
|
173662
175423
|
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
173663
175424
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
173664
175425
|
return {
|
|
173665
175426
|
maxCompartmentSeq: compartments.length > 0 ? compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ) : EMPTY_MAX_COMPARTMENT_SEQ,
|
|
173666
|
-
maxMemoryId
|
|
175427
|
+
maxMemoryId,
|
|
173667
175428
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
173668
|
-
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
175429
|
+
maxMemoryMutationId: memPath ? workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(db, workspace.expandedIdentities) ?? 0 : getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
173669
175430
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
175431
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(db, workspace.identities) : null,
|
|
173670
175432
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
173671
175433
|
projectDocsHash: projectDocsHash ?? readProjectDocsCanonical(state.projectDirectory).canonicalHash,
|
|
173672
175434
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
@@ -173674,7 +175436,6 @@ function readCurrentMarkersFromCompartments(db, state, compartments, projectDocs
|
|
|
173674
175436
|
upgradeState: `${PI_M0_UPGRADE_STATE}:${compartments.some((c) => c.legacy === 1) ? "legacy" : "ready"}`,
|
|
173675
175437
|
lastBaselineEndMessageId: lastBaselineEndMessageId(compartments),
|
|
173676
175438
|
systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
|
|
173677
|
-
toolSetHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).toolSetHash,
|
|
173678
175439
|
modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey
|
|
173679
175440
|
};
|
|
173680
175441
|
}
|
|
@@ -173699,19 +175460,17 @@ function mustMaterializePi(state, db, currentCompartmentsOverride) {
|
|
|
173699
175460
|
if (hard.systemHash !== "" && hard.systemHash !== (meta3.cachedM0SystemHash ?? "")) {
|
|
173700
175461
|
return { value: true, reason: "system_hash" };
|
|
173701
175462
|
}
|
|
173702
|
-
if (hard.toolSetHash !== "" && hard.toolSetHash !== (meta3.cachedM0ToolSetHash ?? "")) {
|
|
173703
|
-
return { value: true, reason: "tool_set_hash" };
|
|
173704
|
-
}
|
|
173705
175463
|
if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (meta3.cachedM0MaterializedAt ?? 0)) {
|
|
173706
175464
|
return { value: true, reason: "ttl_idle" };
|
|
173707
175465
|
}
|
|
173708
175466
|
if (meta3.cachedM0UpgradeState !== current.upgradeState) {
|
|
173709
175467
|
return { value: true, reason: "renderer_upgrade" };
|
|
173710
175468
|
}
|
|
173711
|
-
if (current.
|
|
173712
|
-
|
|
173713
|
-
|
|
173714
|
-
|
|
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)) {
|
|
173715
175474
|
return { value: true, reason: "project_memory_change" };
|
|
173716
175475
|
}
|
|
173717
175476
|
if (current.maxMutationId !== (meta3.cachedM0MaxMutationId ?? 0)) {
|
|
@@ -173728,11 +175487,19 @@ ${memories.map((memory) => `- ${escapeXmlContent(memory.content)}`).join(`
|
|
|
173728
175487
|
`)}
|
|
173729
175488
|
</${wrapper}>`;
|
|
173730
175489
|
}
|
|
173731
|
-
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) {
|
|
173732
175491
|
const memPath = memoryProjectPath(state);
|
|
173733
|
-
const
|
|
173734
|
-
const
|
|
173735
|
-
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;
|
|
173736
175503
|
const baseHistoryBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173737
175504
|
const decayed = renderDecayedCompartments({
|
|
173738
175505
|
compartments: compartmentsOverride ?? getCompartments(db, state.sessionId),
|
|
@@ -173754,10 +175521,19 @@ ${decayed}
|
|
|
173754
175521
|
|
|
173755
175522
|
`).trim();
|
|
173756
175523
|
}
|
|
173757
|
-
function renderedMemoryIdsForPi(state, memories) {
|
|
175524
|
+
function renderedMemoryIdsForPi(state, memories, workspace, db) {
|
|
173758
175525
|
if (memories.length === 0)
|
|
173759
175526
|
return [];
|
|
173760
|
-
|
|
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);
|
|
173761
175537
|
}
|
|
173762
175538
|
function isTransientSqliteLockError(error51) {
|
|
173763
175539
|
if (!error51 || typeof error51 !== "object")
|
|
@@ -173782,17 +175558,19 @@ class PiMaterializeContentionError extends Error {
|
|
|
173782
175558
|
function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.projectDirectory), memoryCutoff) {
|
|
173783
175559
|
const memPath = memoryProjectPath(state);
|
|
173784
175560
|
const read = db.transaction(() => {
|
|
175561
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
173785
175562
|
const compartments = getCompartments(db, state.sessionId);
|
|
173786
|
-
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) : [];
|
|
173787
175564
|
const userProfile = safeGetActiveUserMemoriesPi(db);
|
|
173788
175565
|
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
173789
175566
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
173790
175567
|
const markers = {
|
|
173791
175568
|
maxCompartmentSeq: compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ),
|
|
173792
|
-
maxMemoryId:
|
|
175569
|
+
maxMemoryId: memPath ? workspace.isWorkspaced ? getMaxMemoryIdForProjects(db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryIdForProjects(db, [memPath]) : 0,
|
|
173793
175570
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
173794
|
-
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
175571
|
+
maxMemoryMutationId: memPath ? workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(db, workspace.expandedIdentities) ?? 0 : getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
173795
175572
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
175573
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(db, workspace.identities) : null,
|
|
173796
175574
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
173797
175575
|
projectDocsHash: docs.canonicalHash,
|
|
173798
175576
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
@@ -173800,10 +175578,9 @@ function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.p
|
|
|
173800
175578
|
upgradeState: `${PI_M0_UPGRADE_STATE}:${compartments.some((c) => c.legacy === 1) ? "legacy" : "ready"}`,
|
|
173801
175579
|
lastBaselineEndMessageId: lastBaselineEndMessageId(compartments),
|
|
173802
175580
|
systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
|
|
173803
|
-
toolSetHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).toolSetHash,
|
|
173804
175581
|
modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey
|
|
173805
175582
|
};
|
|
173806
|
-
return { docs, markers, compartments, memories, userProfile };
|
|
175583
|
+
return { docs, markers, compartments, memories, userProfile, workspace };
|
|
173807
175584
|
});
|
|
173808
175585
|
return read();
|
|
173809
175586
|
}
|
|
@@ -173814,17 +175591,17 @@ function renderFreshM0PiNonPersisted(state, db) {
|
|
|
173814
175591
|
frozen.markers.materializedAt = cachedMaterializedAt;
|
|
173815
175592
|
const historyBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173816
175593
|
let dpm = 1;
|
|
173817
|
-
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);
|
|
173818
175595
|
let attempts = 0;
|
|
173819
175596
|
while (historyBudget > 0 && historySliceTokensPi(m0) > historyBudget * 1.05 && attempts < 3) {
|
|
173820
175597
|
dpm *= 1.15;
|
|
173821
|
-
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);
|
|
173822
175599
|
attempts += 1;
|
|
173823
175600
|
}
|
|
173824
175601
|
return {
|
|
173825
175602
|
m0,
|
|
173826
175603
|
snapshotMarkers: frozen.markers,
|
|
173827
|
-
renderedMemoryIds: renderedMemoryIdsForPi(state, frozen.memories)
|
|
175604
|
+
renderedMemoryIds: renderedMemoryIdsForPi(state, frozen.memories, frozen.workspace, db)
|
|
173828
175605
|
};
|
|
173829
175606
|
}
|
|
173830
175607
|
function materializeM0Pi(state, db) {
|
|
@@ -173834,14 +175611,14 @@ function materializeM0Pi(state, db) {
|
|
|
173834
175611
|
const snapshotMemories = frozen.memories;
|
|
173835
175612
|
const snapshotCompartments = frozen.compartments;
|
|
173836
175613
|
const snapshotUserProfile = frozen.userProfile;
|
|
173837
|
-
const renderedMemoryIds = renderedMemoryIdsForPi(state, snapshotMemories);
|
|
175614
|
+
const renderedMemoryIds = renderedMemoryIdsForPi(state, snapshotMemories, frozen.workspace, db);
|
|
173838
175615
|
let decayPressureMultiplier = 1;
|
|
173839
|
-
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);
|
|
173840
175617
|
const historyBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173841
175618
|
let attempts = 0;
|
|
173842
175619
|
while (historyBudget > 0 && historySliceTokensPi(m0) > historyBudget * 1.05 && attempts < 3) {
|
|
173843
175620
|
decayPressureMultiplier *= 1.15;
|
|
173844
|
-
m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile);
|
|
175621
|
+
m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile, frozen.workspace);
|
|
173845
175622
|
attempts += 1;
|
|
173846
175623
|
}
|
|
173847
175624
|
const m0Bytes = Buffer.from(m0, "utf8");
|
|
@@ -173857,7 +175634,8 @@ function materializeM0Pi(state, db) {
|
|
|
173857
175634
|
}
|
|
173858
175635
|
try {
|
|
173859
175636
|
const current = readCurrentMarkers(db, state, phase3ProjectDocsHash);
|
|
173860
|
-
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;
|
|
173861
175639
|
if (stale) {
|
|
173862
175640
|
db.exec("ROLLBACK");
|
|
173863
175641
|
throw new PiMaterializeContentionError("snapshot changed before persist");
|
|
@@ -173868,6 +175646,7 @@ function materializeM0Pi(state, db) {
|
|
|
173868
175646
|
persistCachedM0(db, state.sessionId, {
|
|
173869
175647
|
m0Bytes,
|
|
173870
175648
|
projectMemoryEpoch: snapshotMarkers.projectMemoryEpoch,
|
|
175649
|
+
workspaceFingerprint: snapshotMarkers.workspaceFingerprint,
|
|
173871
175650
|
projectUserProfileVersion: snapshotMarkers.projectUserProfileVersion,
|
|
173872
175651
|
maxCompartmentSeq: snapshotMarkers.maxCompartmentSeq,
|
|
173873
175652
|
maxMemoryId: snapshotMarkers.maxMemoryId,
|
|
@@ -173879,7 +175658,6 @@ function materializeM0Pi(state, db) {
|
|
|
173879
175658
|
sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
|
|
173880
175659
|
upgradeState: snapshotMarkers.upgradeState,
|
|
173881
175660
|
systemHash: snapshotMarkers.systemHash,
|
|
173882
|
-
toolSetHash: snapshotMarkers.toolSetHash,
|
|
173883
175661
|
modelKey: snapshotMarkers.modelKey
|
|
173884
175662
|
});
|
|
173885
175663
|
db.prepare("UPDATE session_meta SET memory_block_count = ?, memory_block_ids = ? WHERE session_id = ?").run(renderedMemoryIds.length, JSON.stringify(renderedMemoryIds), state.sessionId);
|
|
@@ -173933,7 +175711,7 @@ function renderMemoryUpdatesBlockPi(args) {
|
|
|
173933
175711
|
if (args.renderedMemoryIds.length === 0)
|
|
173934
175712
|
return { block: "", count: 0 };
|
|
173935
175713
|
const renderedIds = new Set(args.renderedMemoryIds);
|
|
173936
|
-
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);
|
|
173937
175715
|
if (mutations.length === 0)
|
|
173938
175716
|
return { block: "", count: 0 };
|
|
173939
175717
|
const lines = [
|
|
@@ -173964,6 +175742,7 @@ ${lines.join(`
|
|
|
173964
175742
|
}
|
|
173965
175743
|
function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRenderedKeyFilesBlock, compartmentsOverride) {
|
|
173966
175744
|
const sections = [];
|
|
175745
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
173967
175746
|
const keyFiles = renderedKeyFilesBlockPi(state, db, preRenderedKeyFilesBlock);
|
|
173968
175747
|
if (keyFiles)
|
|
173969
175748
|
sections.push(keyFiles);
|
|
@@ -173971,6 +175750,7 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
|
|
|
173971
175750
|
const memoryUpdates = memPath ? renderMemoryUpdatesBlockPi({
|
|
173972
175751
|
db,
|
|
173973
175752
|
projectPath: memPath,
|
|
175753
|
+
workspace,
|
|
173974
175754
|
afterId: markers.maxMemoryMutationId,
|
|
173975
175755
|
renderedMemoryIds
|
|
173976
175756
|
}) : { block: undefined, count: 0 };
|
|
@@ -173985,11 +175765,18 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
|
|
|
173985
175765
|
${body}
|
|
173986
175766
|
</new-compartments>`);
|
|
173987
175767
|
}
|
|
173988
|
-
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) : [];
|
|
173989
175769
|
if (newMemories.length > 0) {
|
|
173990
175770
|
const memoryBudget = state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
173991
|
-
const
|
|
173992
|
-
|
|
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);
|
|
173993
175780
|
if (newMemoriesBlock)
|
|
173994
175781
|
sections.push(newMemoriesBlock);
|
|
173995
175782
|
}
|
|
@@ -174038,6 +175825,7 @@ function parseMemoryBlockIds(raw) {
|
|
|
174038
175825
|
function readCachedPiM0M1Row(db, sessionId) {
|
|
174039
175826
|
return db.prepare(`SELECT cached_m0_bytes, cached_m1_bytes,
|
|
174040
175827
|
cached_m0_project_memory_epoch,
|
|
175828
|
+
cached_m0_workspace_fingerprint,
|
|
174041
175829
|
cached_m0_project_user_profile_version,
|
|
174042
175830
|
cached_m0_max_compartment_seq,
|
|
174043
175831
|
cached_m0_max_memory_id,
|
|
@@ -174048,7 +175836,6 @@ function readCachedPiM0M1Row(db, sessionId) {
|
|
|
174048
175836
|
cached_m0_session_facts_version,
|
|
174049
175837
|
cached_m0_upgrade_state,
|
|
174050
175838
|
cached_m0_system_hash,
|
|
174051
|
-
cached_m0_tool_set_hash,
|
|
174052
175839
|
cached_m0_model_key,
|
|
174053
175840
|
cached_m0_last_baseline_end_message_id,
|
|
174054
175841
|
memory_block_ids
|
|
@@ -174082,6 +175869,7 @@ function markersFromCachedPiRow(row, compartmentsForNormalization) {
|
|
|
174082
175869
|
maxMutationId: row.cached_m0_max_mutation_id,
|
|
174083
175870
|
maxMemoryMutationId: row.cached_m0_max_memory_mutation_id,
|
|
174084
175871
|
projectMemoryEpoch: row.cached_m0_project_memory_epoch,
|
|
175872
|
+
workspaceFingerprint: row.cached_m0_workspace_fingerprint,
|
|
174085
175873
|
projectUserProfileVersion: row.cached_m0_project_user_profile_version,
|
|
174086
175874
|
projectDocsHash: row.cached_m0_project_docs_hash ?? "",
|
|
174087
175875
|
materializedAt: row.cached_m0_materialized_at,
|
|
@@ -174089,7 +175877,6 @@ function markersFromCachedPiRow(row, compartmentsForNormalization) {
|
|
|
174089
175877
|
upgradeState: row.cached_m0_upgrade_state,
|
|
174090
175878
|
lastBaselineEndMessageId: typeof row.cached_m0_last_baseline_end_message_id === "string" && row.cached_m0_last_baseline_end_message_id.length > 0 ? row.cached_m0_last_baseline_end_message_id : null,
|
|
174091
175879
|
systemHash: row.cached_m0_system_hash ?? "",
|
|
174092
|
-
toolSetHash: row.cached_m0_tool_set_hash ?? "",
|
|
174093
175880
|
modelKey: row.cached_m0_model_key ?? ""
|
|
174094
175881
|
};
|
|
174095
175882
|
}
|
|
@@ -174097,7 +175884,7 @@ function cachedPiRowMatchesSnapshot(args) {
|
|
|
174097
175884
|
const rowMarkers = markersFromCachedPiRow(args.row, args.compartmentsForNormalization);
|
|
174098
175885
|
if (!rowMarkers)
|
|
174099
175886
|
return false;
|
|
174100
|
-
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);
|
|
174101
175888
|
}
|
|
174102
175889
|
function decodeCachedM1(row, sessionId) {
|
|
174103
175890
|
if (!row.cached_m1_bytes) {
|
|
@@ -174308,14 +176095,14 @@ function injectM0M1Pi(state, db, piMessages, entryIds, recomputeM1ThisPass = fal
|
|
|
174308
176095
|
const skippedVisibleMessages = boundaryId ? trimPiMessagesToBoundary(piMessages, entryIds, boundaryId) : 0;
|
|
174309
176096
|
prependM0M1Messages(piMessages, m0, m1);
|
|
174310
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;
|
|
174311
176101
|
return {
|
|
174312
176102
|
injected: true,
|
|
174313
176103
|
compartmentCount: getCompartments(db, state.sessionId).length,
|
|
174314
176104
|
factCount: 0,
|
|
174315
|
-
memoryCount
|
|
174316
|
-
"active",
|
|
174317
|
-
"permanent"
|
|
174318
|
-
]).length : 0,
|
|
176105
|
+
memoryCount,
|
|
174319
176106
|
skippedVisibleMessages,
|
|
174320
176107
|
m0Materialized: materialized,
|
|
174321
176108
|
m0Reason: decision.reason,
|
|
@@ -174376,21 +176163,48 @@ import * as crypto2 from "node:crypto";
|
|
|
174376
176163
|
|
|
174377
176164
|
// ../plugin/src/features/magic-context/compartment-embedding.ts
|
|
174378
176165
|
init_logger();
|
|
174379
|
-
async function
|
|
176166
|
+
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
174380
176167
|
if (compartments.length === 0)
|
|
174381
176168
|
return;
|
|
174382
|
-
const
|
|
174383
|
-
for (const
|
|
174384
|
-
if (!c.p1 || c.p1.length === 0)
|
|
174385
|
-
continue;
|
|
176169
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
176170
|
+
for (const compartment of compartments) {
|
|
174386
176171
|
try {
|
|
174387
|
-
const
|
|
174388
|
-
|
|
174389
|
-
|
|
174390
|
-
|
|
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);
|
|
174391
176205
|
}
|
|
174392
176206
|
} catch (error51) {
|
|
174393
|
-
sessionLog(sessionId, `compartment embedding failed for compartment ${
|
|
176207
|
+
sessionLog(sessionId, `compartment chunk embedding failed for compartment ${compartment.id}:`, error51);
|
|
174394
176208
|
}
|
|
174395
176209
|
}
|
|
174396
176210
|
}
|
|
@@ -177459,6 +179273,7 @@ async function runPiHistorian(deps) {
|
|
|
177459
179273
|
fallbackModels,
|
|
177460
179274
|
historianChunkTokens,
|
|
177461
179275
|
boundarySnapshot: providedBoundarySnapshot,
|
|
179276
|
+
refreshBoundarySnapshot,
|
|
177462
179277
|
currentContextLimit,
|
|
177463
179278
|
historianTimeoutMs = DEFAULT_HISTORIAN_TIMEOUT_MS2,
|
|
177464
179279
|
twoPass,
|
|
@@ -177512,16 +179327,29 @@ async function runPiHistorian(deps) {
|
|
|
177512
179327
|
return;
|
|
177513
179328
|
}
|
|
177514
179329
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
177515
|
-
|
|
179330
|
+
let boundarySnapshot = providedBoundarySnapshot ?? null;
|
|
177516
179331
|
if (!boundarySnapshot) {
|
|
177517
179332
|
sessionLog(sessionId, "historian no-op: missing protected-tail boundary snapshot from Pi trigger decision");
|
|
177518
179333
|
return;
|
|
177519
179334
|
}
|
|
177520
|
-
|
|
179335
|
+
let validation = boundarySnapshot.rawRangeFingerprint.length > 0 ? validateBoundarySnapshot({
|
|
177521
179336
|
db,
|
|
177522
179337
|
snapshot: boundarySnapshot,
|
|
177523
179338
|
currentContextLimit: currentContextLimit ?? boundarySnapshot.contextLimit
|
|
177524
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
|
+
}
|
|
177525
179353
|
if (!validation.ok) {
|
|
177526
179354
|
sessionLog(sessionId, `historian no-op: stale protected-tail snapshot (${validation.detail ?? validation.reason ?? "unknown"})`);
|
|
177527
179355
|
return;
|
|
@@ -177850,8 +179678,13 @@ ${chunkText}`,
|
|
|
177850
179678
|
}
|
|
177851
179679
|
}
|
|
177852
179680
|
if (embeddingActive) {
|
|
177853
|
-
const
|
|
177854
|
-
|
|
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);
|
|
177855
179688
|
}
|
|
177856
179689
|
onPublished?.();
|
|
177857
179690
|
completedSuccessfully = true;
|
|
@@ -178399,7 +180232,7 @@ function stripPiDroppedPlaceholderMessages(args) {
|
|
|
178399
180232
|
}
|
|
178400
180233
|
|
|
178401
180234
|
// src/system-prompt.ts
|
|
178402
|
-
import { createHash as
|
|
180235
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
178403
180236
|
|
|
178404
180237
|
// ../plugin/src/agents/magic-context-prompt.ts
|
|
178405
180238
|
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
@@ -178550,7 +180383,7 @@ function processSystemPromptForCache(args) {
|
|
|
178550
180383
|
sessionLog(sessionId, `system prompt date frozen: real=${liveDate}, using=${stickyDate} (cache-stable pass)`);
|
|
178551
180384
|
}
|
|
178552
180385
|
}
|
|
178553
|
-
const currentHash =
|
|
180386
|
+
const currentHash = createHash11("md5").update(frozenPrompt).digest("hex");
|
|
178554
180387
|
const hashChanged = !isFirstHash && currentHash !== previousHash;
|
|
178555
180388
|
if (hashChanged) {
|
|
178556
180389
|
sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${frozenPrompt.length})`);
|
|
@@ -179177,6 +181010,19 @@ function extractStableId(msg, index, entryIds) {
|
|
|
179177
181010
|
// src/context-handler.ts
|
|
179178
181011
|
var FORCE_MATERIALIZATION_PERCENTAGE = 85;
|
|
179179
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
|
+
}
|
|
179180
181026
|
var DEFAULT_CLEAR_REASONING_AGE = 50;
|
|
179181
181027
|
var PI_STABLE_ID_SCHEME = 1;
|
|
179182
181028
|
var lastEmergencyNotificationAtMs = new Map;
|
|
@@ -179261,7 +181107,7 @@ function trackSessionForProject(projectIdentity, sessionId) {
|
|
|
179261
181107
|
function isContextHandlerSessionActive(sessionId) {
|
|
179262
181108
|
return activeContextHandlerSessions.has(sessionId);
|
|
179263
181109
|
}
|
|
179264
|
-
function updateSessionProjectTracking(sessionId, projectIdentity) {
|
|
181110
|
+
function updateSessionProjectTracking(sessionId, projectIdentity, db) {
|
|
179265
181111
|
const prev = lastSeenProjectIdentityBySession.get(sessionId);
|
|
179266
181112
|
if (prev && prev !== projectIdentity) {
|
|
179267
181113
|
const prevSessions = sessionsByProject.get(prev);
|
|
@@ -179270,6 +181116,11 @@ function updateSessionProjectTracking(sessionId, projectIdentity) {
|
|
|
179270
181116
|
sessionsByProject.delete(prev);
|
|
179271
181117
|
clearPiSystemPromptSession(sessionId);
|
|
179272
181118
|
}
|
|
181119
|
+
if (db && prev !== projectIdentity) {
|
|
181120
|
+
try {
|
|
181121
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
181122
|
+
} catch {}
|
|
181123
|
+
}
|
|
179273
181124
|
trackSessionForProject(projectIdentity, sessionId);
|
|
179274
181125
|
lastSeenProjectIdentityBySession.set(sessionId, projectIdentity);
|
|
179275
181126
|
}
|
|
@@ -179550,7 +181401,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
179550
181401
|
const schedulerConfig = options.scheduler ?? DEFAULT_SCHEDULER_CONFIG;
|
|
179551
181402
|
const scheduler2 = schedulerFor(options);
|
|
179552
181403
|
const projectIdentity = resolveProjectIdentity(projectDirectory);
|
|
179553
|
-
updateSessionProjectTracking(sessionId, projectIdentity);
|
|
181404
|
+
updateSessionProjectTracking(sessionId, projectIdentity, options.db);
|
|
179554
181405
|
logTransformTiming(sessionId, "findSessionId", tFindSession, `messages=${event.messages.length}`);
|
|
179555
181406
|
const branchEntries = readPiBranchEntriesForContext(ctx, sessionId);
|
|
179556
181407
|
const rawMessageProvider = {
|
|
@@ -179659,9 +181510,10 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
179659
181510
|
if (!usedPersistedUsage && isSaneLimit(usageContextLimit) && usageInputTokens > 0) {
|
|
179660
181511
|
usagePercentage = usageInputTokens / usageContextLimit * 100;
|
|
179661
181512
|
}
|
|
181513
|
+
({ percentage: usagePercentage, inputTokens: usageInputTokens } = applyForwardPressureFloor(usagePercentage, usageInputTokens, piUsage?.tokens, usageContextLimit));
|
|
179662
181514
|
if (needsEmergencyBump) {
|
|
179663
181515
|
sessionLog(sessionId, `transform: overflow recovery flag set — bumping percentage to 95% (detectedLimit=${usageContextLimit ?? "unknown"})`);
|
|
179664
|
-
usagePercentage = 95;
|
|
181516
|
+
usagePercentage = Math.max(usagePercentage, 95);
|
|
179665
181517
|
}
|
|
179666
181518
|
let schedulerDecision;
|
|
179667
181519
|
const tScheduler = performance.now();
|
|
@@ -180045,6 +181897,7 @@ function spawnPiHistorianRun(args) {
|
|
|
180045
181897
|
provider: provider2,
|
|
180046
181898
|
unregister,
|
|
180047
181899
|
boundarySnapshot,
|
|
181900
|
+
refreshBoundarySnapshot,
|
|
180048
181901
|
currentContextLimit
|
|
180049
181902
|
} = args;
|
|
180050
181903
|
const holderId = crypto3.randomUUID();
|
|
@@ -180068,6 +181921,7 @@ function spawnPiHistorianRun(args) {
|
|
|
180068
181921
|
fallbackModels: historian.fallbackModels,
|
|
180069
181922
|
historianChunkTokens: historian.historianChunkTokens,
|
|
180070
181923
|
boundarySnapshot,
|
|
181924
|
+
refreshBoundarySnapshot,
|
|
180071
181925
|
currentContextLimit,
|
|
180072
181926
|
historianTimeoutMs: historian.timeoutMs,
|
|
180073
181927
|
twoPass: historian.twoPass,
|
|
@@ -180134,6 +181988,7 @@ function maybeFireHistorian(args) {
|
|
|
180134
181988
|
let usageContextLimit;
|
|
180135
181989
|
try {
|
|
180136
181990
|
const piUsage = ctx.getContextUsage?.();
|
|
181991
|
+
let usageSource;
|
|
180137
181992
|
usageContextLimit = isSaneLimit(piUsage?.contextWindow) ? piUsage.contextWindow : undefined;
|
|
180138
181993
|
if (usageContextLimit === undefined && isSaneLimit(ctx.model?.contextWindow)) {
|
|
180139
181994
|
usageContextLimit = ctx.model.contextWindow;
|
|
@@ -180150,7 +182005,7 @@ function maybeFireHistorian(args) {
|
|
|
180150
182005
|
percentage: sessionMetaForUsage.lastContextPercentage,
|
|
180151
182006
|
inputTokens: sessionMetaForUsage.lastInputTokens
|
|
180152
182007
|
};
|
|
180153
|
-
|
|
182008
|
+
usageSource = "session_meta";
|
|
180154
182009
|
} else {
|
|
180155
182010
|
if (!piUsage || piUsage.tokens === null || piUsage.percent === null || piUsage.contextWindow === 0) {
|
|
180156
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>"})`);
|
|
@@ -180161,8 +182016,10 @@ function maybeFireHistorian(args) {
|
|
|
180161
182016
|
percentage: fallbackPercentage,
|
|
180162
182017
|
inputTokens: piUsage.tokens
|
|
180163
182018
|
};
|
|
180164
|
-
|
|
182019
|
+
usageSource = "piUsage fallback";
|
|
180165
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...`);
|
|
180166
182023
|
} catch (err) {
|
|
180167
182024
|
sessionLog(sessionId, `historian trigger eval: getContextUsage threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
180168
182025
|
return;
|
|
@@ -180193,10 +182050,14 @@ function maybeFireHistorian(args) {
|
|
|
180193
182050
|
cacheNamespace: `pi:${sessionId}`,
|
|
180194
182051
|
emergencyTailScale
|
|
180195
182052
|
}));
|
|
180196
|
-
|
|
180197
|
-
|
|
180198
|
-
|
|
180199
|
-
|
|
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();
|
|
180200
182061
|
let triggered = false;
|
|
180201
182062
|
try {
|
|
180202
182063
|
if (isFirstContextPassForSession) {
|
|
@@ -180221,6 +182082,7 @@ Historian previously failed ${failureState.failureCount} time(s), so Magic Conte
|
|
|
180221
182082
|
provider: provider2,
|
|
180222
182083
|
unregister,
|
|
180223
182084
|
boundarySnapshot,
|
|
182085
|
+
refreshBoundarySnapshot: resolveRunnablePiBoundarySnapshot,
|
|
180224
182086
|
currentContextLimit: boundaryContextLimit
|
|
180225
182087
|
});
|
|
180226
182088
|
return;
|
|
@@ -180244,6 +182106,7 @@ Historian previously failed ${failureState.failureCount} time(s), so Magic Conte
|
|
|
180244
182106
|
resolvedBoundarySnapshot: boundarySnapshot,
|
|
180245
182107
|
triggerBoundarySnapshot: trigger.boundarySnapshot
|
|
180246
182108
|
}),
|
|
182109
|
+
refreshBoundarySnapshot: resolveRunnablePiBoundarySnapshot,
|
|
180247
182110
|
currentContextLimit: boundaryContextLimit
|
|
180248
182111
|
});
|
|
180249
182112
|
} catch (err) {
|
|
@@ -180284,7 +182147,31 @@ async function runPipeline(args) {
|
|
|
180284
182147
|
const alreadyRanHeuristicsThisTurn = currentTurnId !== null && lastHeuristicsTurnIdBySession.get(args.sessionId) === currentTurnId;
|
|
180285
182148
|
const canConsumeDeferredLate = args.schedulerDecision === "execute" || args.forceMaterialization === true || args.contextUsage.percentage >= FORCE_MATERIALIZATION_PERCENTAGE;
|
|
180286
182149
|
const deferredMaterializeEligible = canConsumeDeferredLate && deferredMaterializationSessions.has(args.sessionId);
|
|
180287
|
-
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);
|
|
180288
182175
|
const entryFingerprintByMessageId = buildEntryFingerprintMap(args.messages, stableIdResolver);
|
|
180289
182176
|
adoptPiFallbackTags(args.db, args.sessionId, args.tagger, entryFingerprintByMessageId);
|
|
180290
182177
|
const tTag = performance.now();
|
|
@@ -180311,12 +182198,12 @@ async function runPipeline(args) {
|
|
|
180311
182198
|
const deferredMaterializationWasPending = deferredMaterializationSessions.has(args.sessionId);
|
|
180312
182199
|
const deferredHistoryRefreshWasPending = deferredHistoryWasPendingAtPassStart;
|
|
180313
182200
|
const pendingOps = getPendingOps(args.db, args.sessionId);
|
|
180314
|
-
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal;
|
|
182201
|
+
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal || m0HardFoldThisPass;
|
|
180315
182202
|
const deferredMaterialize = canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
180316
182203
|
const deferredHistoryRefresh = canConsumeDeferredLate && deferredHistoryRefreshWasPending;
|
|
180317
182204
|
const shouldApplyPendingOps = baseShouldApplyPendingOps || deferredMaterialize;
|
|
180318
182205
|
if (shouldApplyPendingOps) {
|
|
180319
|
-
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})`;
|
|
180320
182207
|
sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
|
|
180321
182208
|
try {
|
|
180322
182209
|
const tApplyPending = performance.now();
|
|
@@ -180387,7 +182274,7 @@ async function runPipeline(args) {
|
|
|
180387
182274
|
const activeTags = getActiveTagsBySession(args.db, args.sessionId);
|
|
180388
182275
|
logTransformTiming(args.sessionId, "getActiveTagsBySession", tActiveTags, `count=${activeTags.length}`);
|
|
180389
182276
|
if (shouldRunHeuristics) {
|
|
180390
|
-
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})`;
|
|
180391
182278
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=n/a`);
|
|
180392
182279
|
} else {
|
|
180393
182280
|
const reason = args.heuristics === undefined ? "disabled" : "scheduler_defer";
|
|
@@ -180475,18 +182362,6 @@ async function runPipeline(args) {
|
|
|
180475
182362
|
if (args.injection) {
|
|
180476
182363
|
try {
|
|
180477
182364
|
const tInjection = performance.now();
|
|
180478
|
-
const hardMeta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
180479
|
-
let piTtlMs = 5 * 60 * 1000;
|
|
180480
|
-
try {
|
|
180481
|
-
piTtlMs = parseCacheTtl(hardMeta.cacheTtl);
|
|
180482
|
-
} catch {}
|
|
180483
|
-
const piHardSignals = {
|
|
180484
|
-
systemHash: typeof hardMeta.systemPromptHash === "string" ? hardMeta.systemPromptHash : "",
|
|
180485
|
-
toolSetHash: "",
|
|
180486
|
-
modelKey: liveModelBySession.get(args.sessionId) ?? "",
|
|
180487
|
-
cacheExpired: hardMeta.lastResponseTime > 0 && Date.now() - hardMeta.lastResponseTime >= piTtlMs,
|
|
180488
|
-
lastResponseTime: hardMeta.lastResponseTime
|
|
180489
|
-
};
|
|
180490
182365
|
injectionResult = injectM0M1Pi({
|
|
180491
182366
|
sessionId: args.sessionId,
|
|
180492
182367
|
projectIdentity: args.projectIdentity,
|
|
@@ -181576,8 +183451,12 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
181576
183451
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181577
183452
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
181578
183453
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181579
|
-
const
|
|
181580
|
-
|
|
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);
|
|
181581
183460
|
}
|
|
181582
183461
|
const lastCompartmentEnd2 = promoted2.compartments[promoted2.compartments.length - 1]?.endMessage ?? 0;
|
|
181583
183462
|
if (lastCompartmentEnd2 > 0) {
|
|
@@ -181790,8 +183669,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
181790
183669
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181791
183670
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
181792
183671
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181793
|
-
const
|
|
181794
|
-
|
|
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);
|
|
181795
183678
|
}
|
|
181796
183679
|
if (lastCompartmentEnd > 0) {
|
|
181797
183680
|
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
@@ -181948,8 +183831,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
181948
183831
|
if (deps.memoryEnabled !== false) {
|
|
181949
183832
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181950
183833
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181951
|
-
const
|
|
181952
|
-
|
|
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));
|
|
181953
183840
|
}
|
|
181954
183841
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
181955
183842
|
if (lastEnd > 0) {
|
|
@@ -182761,7 +184648,7 @@ function applyMemoryMigration(db, projectPath, result) {
|
|
|
182761
184648
|
inserted++;
|
|
182762
184649
|
}
|
|
182763
184650
|
if (removed > 0 || inserted > 0) {
|
|
182764
|
-
|
|
184651
|
+
bumpEpochsForWorkspaceMembers(db, projectPath);
|
|
182765
184652
|
}
|
|
182766
184653
|
})();
|
|
182767
184654
|
return { removed, inserted };
|
|
@@ -183237,7 +185124,7 @@ function formatThresholdPercent(value) {
|
|
|
183237
185124
|
// package.json
|
|
183238
185125
|
var package_default = {
|
|
183239
185126
|
name: "@cortexkit/pi-magic-context",
|
|
183240
|
-
version: "0.
|
|
185127
|
+
version: "0.24.0",
|
|
183241
185128
|
type: "module",
|
|
183242
185129
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
183243
185130
|
main: "dist/index.js",
|
|
@@ -188101,6 +189988,23 @@ function createCtxMemoryTool(deps) {
|
|
|
188101
189988
|
}
|
|
188102
189989
|
const projectIdentity = resolveProjectIdentity(ctx.cwd);
|
|
188103
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
|
+
};
|
|
188104
190008
|
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
188105
190009
|
if (snapshot ? !snapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
188106
190010
|
return err2("Cross-session memory is disabled for this project.");
|
|
@@ -188147,28 +190051,34 @@ function createCtxMemoryTool(deps) {
|
|
|
188147
190051
|
return err2("Error: 'content' is required when action is 'update'.");
|
|
188148
190052
|
}
|
|
188149
190053
|
const memory2 = getMemoryById(deps.db, updateId);
|
|
188150
|
-
if (!memory2 || !
|
|
190054
|
+
if (!memory2 || !memoryVisibleToTool(memory2)) {
|
|
188151
190055
|
return err2(`Error: Memory with ID ${updateId} was not found.`);
|
|
188152
190056
|
}
|
|
188153
190057
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
188154
190058
|
return err2(inactiveMemoryError(updateId, "updating"));
|
|
188155
190059
|
}
|
|
188156
190060
|
const normalizedHash = computeNormalizedHash(content);
|
|
188157
|
-
const
|
|
190061
|
+
const targetIdentity = targetIdentityForStoredPath(memory2.projectPath);
|
|
190062
|
+
const duplicate = getMemoryByHash(deps.db, targetIdentity, memory2.category, normalizedHash);
|
|
188158
190063
|
if (duplicate && duplicate.id !== memory2.id) {
|
|
188159
190064
|
return err2(`Error: Memory content already exists as ID ${duplicate.id}; merge or archive duplicates instead.`);
|
|
188160
190065
|
}
|
|
188161
190066
|
deps.db.transaction(() => {
|
|
188162
190067
|
updateMemoryContent(deps.db, memory2.id, content, normalizedHash);
|
|
188163
190068
|
queueMemoryMutation(deps.db, {
|
|
188164
|
-
projectPath:
|
|
190069
|
+
projectPath: targetIdentity,
|
|
188165
190070
|
mutationType: "update",
|
|
188166
190071
|
targetMemoryId: memory2.id,
|
|
188167
190072
|
category: memory2.category,
|
|
188168
190073
|
newContent: content
|
|
188169
190074
|
});
|
|
188170
190075
|
})();
|
|
188171
|
-
queueEmbedding({
|
|
190076
|
+
queueEmbedding({
|
|
190077
|
+
deps,
|
|
190078
|
+
projectIdentity: targetIdentity,
|
|
190079
|
+
memoryId: memory2.id,
|
|
190080
|
+
content
|
|
190081
|
+
});
|
|
188172
190082
|
return ok2(`Updated memory [ID: ${memory2.id}] in ${memory2.category}.`);
|
|
188173
190083
|
}
|
|
188174
190084
|
if (params.action === "merge") {
|
|
@@ -188188,7 +190098,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188188
190098
|
return err2("Error: One or more source memories were not found.");
|
|
188189
190099
|
}
|
|
188190
190100
|
if (!dreamerAllowed) {
|
|
188191
|
-
const foreign = sourceMemories.find((memory2) => !
|
|
190101
|
+
const foreign = sourceMemories.find((memory2) => !memoryVisibleToTool(memory2));
|
|
188192
190102
|
if (foreign) {
|
|
188193
190103
|
return err2(`Error: Memory with ID ${foreign.id} was not found.`);
|
|
188194
190104
|
}
|
|
@@ -188277,26 +190187,36 @@ function createCtxMemoryTool(deps) {
|
|
|
188277
190187
|
return ok2(`Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`);
|
|
188278
190188
|
}
|
|
188279
190189
|
if (params.action === "archive") {
|
|
188280
|
-
const
|
|
188281
|
-
if (!
|
|
190190
|
+
const rawArchiveIds = params.ids;
|
|
190191
|
+
if (!rawArchiveIds || rawArchiveIds.length === 0 || !rawArchiveIds.every(Number.isInteger)) {
|
|
188282
190192
|
return err2("Error: 'ids' must contain at least one integer memory ID when action is 'archive'.");
|
|
188283
190193
|
}
|
|
190194
|
+
const archiveIds = [...new Set(rawArchiveIds)];
|
|
188284
190195
|
for (const memoryId of archiveIds) {
|
|
188285
190196
|
const memory2 = getMemoryById(deps.db, memoryId);
|
|
188286
|
-
if (!memory2 || !
|
|
190197
|
+
if (!memory2 || !memoryVisibleToTool(memory2)) {
|
|
188287
190198
|
return err2(`Error: Memory with ID ${memoryId} was not found.`);
|
|
188288
190199
|
}
|
|
188289
190200
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
188290
190201
|
return err2(inactiveMemoryError(memoryId, "archiving"));
|
|
188291
190202
|
}
|
|
188292
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
|
+
});
|
|
188293
190213
|
deps.db.transaction(() => {
|
|
188294
|
-
for (const
|
|
188295
|
-
archiveMemory(deps.db, memoryId, params.reason);
|
|
190214
|
+
for (const target2 of targets) {
|
|
190215
|
+
archiveMemory(deps.db, target2.memoryId, params.reason);
|
|
188296
190216
|
queueMemoryMutation(deps.db, {
|
|
188297
|
-
projectPath: projectIdentity,
|
|
190217
|
+
projectPath: target2.projectIdentity,
|
|
188298
190218
|
mutationType: "archive",
|
|
188299
|
-
targetMemoryId: memoryId
|
|
190219
|
+
targetMemoryId: target2.memoryId
|
|
188300
190220
|
});
|
|
188301
190221
|
}
|
|
188302
190222
|
})();
|
|
@@ -188804,8 +190724,9 @@ function formatAge2(committedAtMs) {
|
|
|
188804
190724
|
}
|
|
188805
190725
|
function formatResult(result, index) {
|
|
188806
190726
|
if (result.source === "memory") {
|
|
190727
|
+
const source = result.sourceName ? ` source=${result.sourceName}` : "";
|
|
188807
190728
|
return [
|
|
188808
|
-
`[${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}`,
|
|
188809
190730
|
result.content
|
|
188810
190731
|
].join(`
|
|
188811
190732
|
`);
|
|
@@ -188815,6 +190736,13 @@ function formatResult(result, index) {
|
|
|
188815
190736
|
`[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge2(result.committedAtMs)} match=${result.matchType}`,
|
|
188816
190737
|
result.content
|
|
188817
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(`
|
|
188818
190746
|
`);
|
|
188819
190747
|
}
|
|
188820
190748
|
const expandStart = Math.max(1, result.messageOrdinal - 3);
|
|
@@ -188830,7 +190758,7 @@ function formatSearchResults(query, results) {
|
|
|
188830
190758
|
return `No results found for "${query}" across memories, git commits, or message history.`;
|
|
188831
190759
|
}
|
|
188832
190760
|
const bodyParts = results.map((result, index) => formatResult(result, index + 1));
|
|
188833
|
-
if (results.some((result) => result.source === "message")) {
|
|
190761
|
+
if (results.some((result) => result.source === "message" || result.source === "compartment")) {
|
|
188834
190762
|
bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
|
|
188835
190763
|
}
|
|
188836
190764
|
const body = bodyParts.join(`
|
|
@@ -189326,6 +191254,14 @@ async function src_default2(pi) {
|
|
|
189326
191254
|
onProjectSeen: (identity) => seenDreamerProjectIdentities.add(identity)
|
|
189327
191255
|
});
|
|
189328
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");
|
|
189329
191265
|
const dreamerConfig = resolveDreamerFromConfig(config2);
|
|
189330
191266
|
if (dreamerConfig) {
|
|
189331
191267
|
registerPiDreamerProject({
|