@wolfx/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 +2243 -307
- 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" };
|
|
@@ -165654,6 +166293,441 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
165654
166293
|
// ../plugin/src/features/magic-context/memory/embedding.ts
|
|
165655
166294
|
init_logger();
|
|
165656
166295
|
|
|
166296
|
+
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
166297
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
166298
|
+
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512;
|
|
166299
|
+
var loadFtsRowsStatements = new WeakMap;
|
|
166300
|
+
var existingHashStatements = new WeakMap;
|
|
166301
|
+
var existingHashByProjectStatements = new WeakMap;
|
|
166302
|
+
var deleteByCompartmentStatements = new WeakMap;
|
|
166303
|
+
var insertEmbeddingStatements = new WeakMap;
|
|
166304
|
+
var distinctModelStatements = new WeakMap;
|
|
166305
|
+
var clearProjectStatements = new WeakMap;
|
|
166306
|
+
var clearProjectModelStatements = new WeakMap;
|
|
166307
|
+
var searchRowsStatements = new WeakMap;
|
|
166308
|
+
var searchRowsByModelStatements = new WeakMap;
|
|
166309
|
+
var backfillCandidateStatements = new WeakMap;
|
|
166310
|
+
function getLoadFtsRowsStatement(db) {
|
|
166311
|
+
let stmt = loadFtsRowsStatements.get(db);
|
|
166312
|
+
if (!stmt) {
|
|
166313
|
+
stmt = db.prepare(`SELECT message_ordinal AS messageOrdinal, role, content
|
|
166314
|
+
FROM message_history_fts
|
|
166315
|
+
WHERE session_id = ?
|
|
166316
|
+
AND message_ordinal >= ?
|
|
166317
|
+
AND message_ordinal <= ?
|
|
166318
|
+
AND role IN ('user', 'assistant')
|
|
166319
|
+
ORDER BY message_ordinal ASC`);
|
|
166320
|
+
loadFtsRowsStatements.set(db, stmt);
|
|
166321
|
+
}
|
|
166322
|
+
return stmt;
|
|
166323
|
+
}
|
|
166324
|
+
function getExistingHashStatement(db, scopedToProject) {
|
|
166325
|
+
const map2 = scopedToProject ? existingHashByProjectStatements : existingHashStatements;
|
|
166326
|
+
let stmt = map2.get(db);
|
|
166327
|
+
if (!stmt) {
|
|
166328
|
+
stmt = db.prepare(`SELECT window_index AS windowIndex, chunk_hash AS chunkHash
|
|
166329
|
+
FROM compartment_chunk_embeddings
|
|
166330
|
+
WHERE compartment_id = ?
|
|
166331
|
+
AND model_id = ?
|
|
166332
|
+
${scopedToProject ? "AND project_path = ?" : ""}
|
|
166333
|
+
ORDER BY window_index ASC`);
|
|
166334
|
+
map2.set(db, stmt);
|
|
166335
|
+
}
|
|
166336
|
+
return stmt;
|
|
166337
|
+
}
|
|
166338
|
+
function getDeleteByCompartmentStatement(db) {
|
|
166339
|
+
let stmt = deleteByCompartmentStatements.get(db);
|
|
166340
|
+
if (!stmt) {
|
|
166341
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE compartment_id = ?");
|
|
166342
|
+
deleteByCompartmentStatements.set(db, stmt);
|
|
166343
|
+
}
|
|
166344
|
+
return stmt;
|
|
166345
|
+
}
|
|
166346
|
+
function getInsertEmbeddingStatement(db) {
|
|
166347
|
+
let stmt = insertEmbeddingStatements.get(db);
|
|
166348
|
+
if (!stmt) {
|
|
166349
|
+
stmt = db.prepare(`INSERT INTO compartment_chunk_embeddings (
|
|
166350
|
+
compartment_id, session_id, project_path, harness, window_index,
|
|
166351
|
+
start_ordinal, end_ordinal, chunk_hash, model_id, dims, vector, created_at
|
|
166352
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
166353
|
+
insertEmbeddingStatements.set(db, stmt);
|
|
166354
|
+
}
|
|
166355
|
+
return stmt;
|
|
166356
|
+
}
|
|
166357
|
+
function getDistinctModelStatement(db) {
|
|
166358
|
+
let stmt = distinctModelStatements.get(db);
|
|
166359
|
+
if (!stmt) {
|
|
166360
|
+
stmt = db.prepare(`SELECT DISTINCT model_id AS modelId
|
|
166361
|
+
FROM compartment_chunk_embeddings
|
|
166362
|
+
WHERE project_path = ?`);
|
|
166363
|
+
distinctModelStatements.set(db, stmt);
|
|
166364
|
+
}
|
|
166365
|
+
return stmt;
|
|
166366
|
+
}
|
|
166367
|
+
function getClearProjectStatement(db) {
|
|
166368
|
+
let stmt = clearProjectStatements.get(db);
|
|
166369
|
+
if (!stmt) {
|
|
166370
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ?");
|
|
166371
|
+
clearProjectStatements.set(db, stmt);
|
|
166372
|
+
}
|
|
166373
|
+
return stmt;
|
|
166374
|
+
}
|
|
166375
|
+
function getClearProjectModelStatement(db) {
|
|
166376
|
+
let stmt = clearProjectModelStatements.get(db);
|
|
166377
|
+
if (!stmt) {
|
|
166378
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ? AND model_id = ?");
|
|
166379
|
+
clearProjectModelStatements.set(db, stmt);
|
|
166380
|
+
}
|
|
166381
|
+
return stmt;
|
|
166382
|
+
}
|
|
166383
|
+
function getSearchRowsStatement(db, withModel) {
|
|
166384
|
+
const map2 = withModel ? searchRowsByModelStatements : searchRowsStatements;
|
|
166385
|
+
let stmt = map2.get(db);
|
|
166386
|
+
if (!stmt) {
|
|
166387
|
+
stmt = db.prepare(`SELECT e.compartment_id AS compartmentId,
|
|
166388
|
+
e.session_id AS sessionId,
|
|
166389
|
+
c.title AS title,
|
|
166390
|
+
c.start_message AS compartmentStart,
|
|
166391
|
+
c.end_message AS compartmentEnd,
|
|
166392
|
+
e.window_index AS windowIndex,
|
|
166393
|
+
e.start_ordinal AS windowStart,
|
|
166394
|
+
e.end_ordinal AS windowEnd,
|
|
166395
|
+
e.chunk_hash AS chunkHash,
|
|
166396
|
+
e.model_id AS modelId,
|
|
166397
|
+
e.dims AS dims,
|
|
166398
|
+
e.vector AS vector
|
|
166399
|
+
FROM compartment_chunk_embeddings e
|
|
166400
|
+
JOIN compartments c ON c.id = e.compartment_id
|
|
166401
|
+
WHERE e.session_id = ?
|
|
166402
|
+
AND e.project_path = ?
|
|
166403
|
+
${withModel ? "AND e.model_id = ?" : ""}
|
|
166404
|
+
ORDER BY e.compartment_id ASC, e.window_index ASC`);
|
|
166405
|
+
map2.set(db, stmt);
|
|
166406
|
+
}
|
|
166407
|
+
return stmt;
|
|
166408
|
+
}
|
|
166409
|
+
function isFinitePositiveInteger(value) {
|
|
166410
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
166411
|
+
}
|
|
166412
|
+
function normalizeCompartmentChunkMaxInputTokens(value) {
|
|
166413
|
+
if (!isFinitePositiveInteger(value)) {
|
|
166414
|
+
return DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS;
|
|
166415
|
+
}
|
|
166416
|
+
return Math.max(1, Math.floor(value));
|
|
166417
|
+
}
|
|
166418
|
+
function normalizeContent(text) {
|
|
166419
|
+
return text.replace(/\s+/g, " ").trim();
|
|
166420
|
+
}
|
|
166421
|
+
function formatOrdinalRange(start, end) {
|
|
166422
|
+
return start === end ? `[${start}]` : `[${start}-${end}]`;
|
|
166423
|
+
}
|
|
166424
|
+
function rolePrefix(role) {
|
|
166425
|
+
if (role === "user")
|
|
166426
|
+
return "U";
|
|
166427
|
+
if (role === "assistant")
|
|
166428
|
+
return "A";
|
|
166429
|
+
return null;
|
|
166430
|
+
}
|
|
166431
|
+
function parseOrdinal(value) {
|
|
166432
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
166433
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
166434
|
+
}
|
|
166435
|
+
function parseCanonicalLineRange(line) {
|
|
166436
|
+
const match = /^\[(\d+)(?:-(\d+))?\]\s+[UA]:/.exec(line.trim());
|
|
166437
|
+
if (!match)
|
|
166438
|
+
return null;
|
|
166439
|
+
const start = Number.parseInt(match[1], 10);
|
|
166440
|
+
const end = match[2] ? Number.parseInt(match[2], 10) : start;
|
|
166441
|
+
if (!Number.isFinite(start) || !Number.isFinite(end))
|
|
166442
|
+
return null;
|
|
166443
|
+
return { start, end };
|
|
166444
|
+
}
|
|
166445
|
+
function hashChunkText(text) {
|
|
166446
|
+
return createHash8("sha256").update(text).digest("hex");
|
|
166447
|
+
}
|
|
166448
|
+
function vectorBlob(vector) {
|
|
166449
|
+
return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
|
|
166450
|
+
}
|
|
166451
|
+
function toFloat32Array2(blob) {
|
|
166452
|
+
if (blob instanceof Uint8Array) {
|
|
166453
|
+
const buffer2 = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
166454
|
+
return new Float32Array(buffer2);
|
|
166455
|
+
}
|
|
166456
|
+
return new Float32Array(blob.slice(0));
|
|
166457
|
+
}
|
|
166458
|
+
function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal) {
|
|
166459
|
+
if (endOrdinal < startOrdinal)
|
|
166460
|
+
return "";
|
|
166461
|
+
const rows = getLoadFtsRowsStatement(db).all(sessionId, startOrdinal, endOrdinal).map((row) => row);
|
|
166462
|
+
const lines = [];
|
|
166463
|
+
let current = null;
|
|
166464
|
+
const flush2 = () => {
|
|
166465
|
+
if (!current || current.parts.length === 0)
|
|
166466
|
+
return;
|
|
166467
|
+
lines.push(`${formatOrdinalRange(current.start, current.end)} ${current.role}: ${current.parts.join(" / ")}`);
|
|
166468
|
+
current = null;
|
|
166469
|
+
};
|
|
166470
|
+
for (const row of rows) {
|
|
166471
|
+
const ordinal = parseOrdinal(row.messageOrdinal);
|
|
166472
|
+
const prefix = rolePrefix(row.role);
|
|
166473
|
+
const content = typeof row.content === "string" ? normalizeContent(row.content) : "";
|
|
166474
|
+
if (ordinal === null || prefix === null || content.length === 0)
|
|
166475
|
+
continue;
|
|
166476
|
+
if (current && current.role === prefix) {
|
|
166477
|
+
current.end = ordinal;
|
|
166478
|
+
current.parts.push(content);
|
|
166479
|
+
continue;
|
|
166480
|
+
}
|
|
166481
|
+
flush2();
|
|
166482
|
+
current = { role: prefix, start: ordinal, end: ordinal, parts: [content] };
|
|
166483
|
+
}
|
|
166484
|
+
flush2();
|
|
166485
|
+
return lines.join(`
|
|
166486
|
+
`);
|
|
166487
|
+
}
|
|
166488
|
+
function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
|
|
166489
|
+
const lines = [];
|
|
166490
|
+
for (const rawLine of chunkText.split(/\r?\n/)) {
|
|
166491
|
+
const line = rawLine.trim();
|
|
166492
|
+
const match = /^(\[(\d+)(?:-(\d+))?\]\s+[UA]:)\s*(.*)$/.exec(line);
|
|
166493
|
+
if (!match)
|
|
166494
|
+
continue;
|
|
166495
|
+
const lineStart = Number.parseInt(match[2], 10);
|
|
166496
|
+
const lineEnd = match[3] ? Number.parseInt(match[3], 10) : lineStart;
|
|
166497
|
+
if (startOrdinal != null && lineEnd < startOrdinal)
|
|
166498
|
+
continue;
|
|
166499
|
+
if (endOrdinal != null && lineStart > endOrdinal)
|
|
166500
|
+
continue;
|
|
166501
|
+
const rawParts = match[4].split(" / ").map((part) => normalizeContent(part)).filter((part) => part.length > 0);
|
|
166502
|
+
const ordinalSpan = lineEnd - lineStart + 1;
|
|
166503
|
+
const roleLabel = match[1].slice(match[1].indexOf("]") + 2);
|
|
166504
|
+
if (ordinalSpan === rawParts.length) {
|
|
166505
|
+
const retained = rawParts.map((part, index) => ({ ordinal: lineStart + index, part })).filter(({ ordinal, part }) => {
|
|
166506
|
+
if (part.startsWith("TC:"))
|
|
166507
|
+
return false;
|
|
166508
|
+
if (startOrdinal != null && ordinal < startOrdinal)
|
|
166509
|
+
return false;
|
|
166510
|
+
if (endOrdinal != null && ordinal > endOrdinal)
|
|
166511
|
+
return false;
|
|
166512
|
+
return true;
|
|
166513
|
+
});
|
|
166514
|
+
if (retained.length === 0)
|
|
166515
|
+
continue;
|
|
166516
|
+
const retainedStart = retained[0].ordinal;
|
|
166517
|
+
const retainedEnd = retained[retained.length - 1].ordinal;
|
|
166518
|
+
lines.push(`${formatOrdinalRange(retainedStart, retainedEnd)} ${roleLabel} ${retained.map(({ part }) => part).join(" / ")}`);
|
|
166519
|
+
continue;
|
|
166520
|
+
}
|
|
166521
|
+
const parts = rawParts.filter((part) => !part.startsWith("TC:"));
|
|
166522
|
+
if (parts.length === 0)
|
|
166523
|
+
continue;
|
|
166524
|
+
lines.push(`${match[1]} ${parts.join(" / ")}`);
|
|
166525
|
+
}
|
|
166526
|
+
return lines.join(`
|
|
166527
|
+
`);
|
|
166528
|
+
}
|
|
166529
|
+
function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTokens) {
|
|
166530
|
+
const lines = canonicalText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
166531
|
+
if (lines.length === 0 || endOrdinal < startOrdinal)
|
|
166532
|
+
return [];
|
|
166533
|
+
const normalizedMax = normalizeCompartmentChunkMaxInputTokens(maxInputTokens);
|
|
166534
|
+
const fullText = lines.join(`
|
|
166535
|
+
`);
|
|
166536
|
+
if (estimateTokens(fullText) <= normalizedMax) {
|
|
166537
|
+
return [
|
|
166538
|
+
{
|
|
166539
|
+
windowIndex: 0,
|
|
166540
|
+
startOrdinal,
|
|
166541
|
+
endOrdinal,
|
|
166542
|
+
text: fullText,
|
|
166543
|
+
chunkHash: hashChunkText(fullText)
|
|
166544
|
+
}
|
|
166545
|
+
];
|
|
166546
|
+
}
|
|
166547
|
+
const windows = [];
|
|
166548
|
+
let currentLines = [];
|
|
166549
|
+
let currentStart = null;
|
|
166550
|
+
let currentEnd = null;
|
|
166551
|
+
let currentTokens = 0;
|
|
166552
|
+
const flush2 = () => {
|
|
166553
|
+
if (currentLines.length === 0 || currentStart === null || currentEnd === null)
|
|
166554
|
+
return;
|
|
166555
|
+
const text = currentLines.join(`
|
|
166556
|
+
`);
|
|
166557
|
+
windows.push({
|
|
166558
|
+
windowIndex: windows.length + 1,
|
|
166559
|
+
startOrdinal: currentStart,
|
|
166560
|
+
endOrdinal: currentEnd,
|
|
166561
|
+
text,
|
|
166562
|
+
chunkHash: hashChunkText(text)
|
|
166563
|
+
});
|
|
166564
|
+
currentLines = [];
|
|
166565
|
+
currentStart = null;
|
|
166566
|
+
currentEnd = null;
|
|
166567
|
+
currentTokens = 0;
|
|
166568
|
+
};
|
|
166569
|
+
for (const line of lines) {
|
|
166570
|
+
const range = parseCanonicalLineRange(line);
|
|
166571
|
+
const lineStart = range?.start ?? startOrdinal;
|
|
166572
|
+
const lineEnd = range?.end ?? lineStart;
|
|
166573
|
+
const lineTokens = estimateTokens(line);
|
|
166574
|
+
if (currentLines.length > 0 && currentTokens + lineTokens > normalizedMax) {
|
|
166575
|
+
flush2();
|
|
166576
|
+
}
|
|
166577
|
+
if (currentLines.length === 0) {
|
|
166578
|
+
currentStart = lineStart;
|
|
166579
|
+
}
|
|
166580
|
+
currentLines.push(line);
|
|
166581
|
+
currentEnd = lineEnd;
|
|
166582
|
+
currentTokens += lineTokens;
|
|
166583
|
+
}
|
|
166584
|
+
flush2();
|
|
166585
|
+
return windows;
|
|
166586
|
+
}
|
|
166587
|
+
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
166588
|
+
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
166589
|
+
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
166590
|
+
return new Map(rows.filter((row) => typeof row.windowIndex === "number" && typeof row.chunkHash === "string").map((row) => [row.windowIndex, row.chunkHash]));
|
|
166591
|
+
}
|
|
166592
|
+
function chunkEmbeddingWindowsAreCurrent(db, compartmentId, modelId, windows, projectPath) {
|
|
166593
|
+
const existing = getExistingChunkHashes(db, compartmentId, modelId, projectPath);
|
|
166594
|
+
if (existing.size !== windows.length)
|
|
166595
|
+
return false;
|
|
166596
|
+
return windows.every((window) => existing.get(window.windowIndex) === window.chunkHash);
|
|
166597
|
+
}
|
|
166598
|
+
function replaceCompartmentChunkEmbeddings(db, rows) {
|
|
166599
|
+
if (rows.length === 0)
|
|
166600
|
+
return;
|
|
166601
|
+
const compartmentId = rows[0].compartmentId;
|
|
166602
|
+
const now = Date.now();
|
|
166603
|
+
db.transaction(() => {
|
|
166604
|
+
getDeleteByCompartmentStatement(db).run(compartmentId);
|
|
166605
|
+
const insert = getInsertEmbeddingStatement(db);
|
|
166606
|
+
for (const row of rows) {
|
|
166607
|
+
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);
|
|
166608
|
+
}
|
|
166609
|
+
})();
|
|
166610
|
+
}
|
|
166611
|
+
function getDistinctChunkEmbeddingModelIds(db, projectPath) {
|
|
166612
|
+
const rows = getDistinctModelStatement(db).all(projectPath);
|
|
166613
|
+
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
166614
|
+
}
|
|
166615
|
+
function clearChunkEmbeddingsForProject(db, projectPath, modelId) {
|
|
166616
|
+
if (modelId) {
|
|
166617
|
+
return getClearProjectModelStatement(db).run(projectPath, modelId).changes;
|
|
166618
|
+
}
|
|
166619
|
+
return getClearProjectStatement(db).run(projectPath).changes;
|
|
166620
|
+
}
|
|
166621
|
+
function loadCompartmentChunkEmbeddingsForSearch(db, sessionId, projectPath, modelId) {
|
|
166622
|
+
const rows = modelId ? getSearchRowsStatement(db, true).all(sessionId, projectPath, modelId) : getSearchRowsStatement(db, false).all(sessionId, projectPath);
|
|
166623
|
+
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) => ({
|
|
166624
|
+
compartmentId: row.compartmentId,
|
|
166625
|
+
sessionId: row.sessionId,
|
|
166626
|
+
title: row.title,
|
|
166627
|
+
startOrdinal: row.compartmentStart,
|
|
166628
|
+
endOrdinal: row.compartmentEnd,
|
|
166629
|
+
windowIndex: row.windowIndex,
|
|
166630
|
+
windowStartOrdinal: row.windowStart,
|
|
166631
|
+
windowEndOrdinal: row.windowEnd,
|
|
166632
|
+
chunkHash: row.chunkHash,
|
|
166633
|
+
modelId: row.modelId,
|
|
166634
|
+
dims: row.dims,
|
|
166635
|
+
vector: toFloat32Array2(row.vector)
|
|
166636
|
+
}));
|
|
166637
|
+
}
|
|
166638
|
+
function mapBackfillCandidateRows(rows) {
|
|
166639
|
+
return rows.filter((row) => {
|
|
166640
|
+
if (row === null || typeof row !== "object")
|
|
166641
|
+
return false;
|
|
166642
|
+
const candidate = row;
|
|
166643
|
+
return typeof candidate.id === "number" && typeof candidate.sessionId === "string" && typeof candidate.startMessage === "number" && typeof candidate.endMessage === "number" && typeof candidate.title === "string";
|
|
166644
|
+
}).map((row) => ({
|
|
166645
|
+
id: row.id,
|
|
166646
|
+
sessionId: row.sessionId,
|
|
166647
|
+
startMessage: row.startMessage,
|
|
166648
|
+
endMessage: row.endMessage,
|
|
166649
|
+
title: row.title
|
|
166650
|
+
}));
|
|
166651
|
+
}
|
|
166652
|
+
var sessionBackfillCandidateStatements = new WeakMap;
|
|
166653
|
+
function loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelId, limit, excludeIds) {
|
|
166654
|
+
if (excludeIds && excludeIds.length > 0) {
|
|
166655
|
+
const placeholders3 = excludeIds.map(() => "?").join(", ");
|
|
166656
|
+
const stmt2 = db.prepare(`SELECT c.id AS id,
|
|
166657
|
+
c.session_id AS sessionId,
|
|
166658
|
+
c.start_message AS startMessage,
|
|
166659
|
+
c.end_message AS endMessage,
|
|
166660
|
+
c.title AS title
|
|
166661
|
+
FROM compartments c
|
|
166662
|
+
JOIN session_projects sp
|
|
166663
|
+
ON sp.session_id = c.session_id
|
|
166664
|
+
AND sp.harness = c.harness
|
|
166665
|
+
AND sp.project_path = ?
|
|
166666
|
+
WHERE c.session_id = ?
|
|
166667
|
+
AND c.start_message IS NOT NULL
|
|
166668
|
+
AND c.end_message IS NOT NULL
|
|
166669
|
+
AND c.id NOT IN (${placeholders3})
|
|
166670
|
+
AND NOT EXISTS (
|
|
166671
|
+
SELECT 1
|
|
166672
|
+
FROM compartment_chunk_embeddings current
|
|
166673
|
+
WHERE current.compartment_id = c.id
|
|
166674
|
+
AND current.project_path = ?
|
|
166675
|
+
AND current.model_id = ?
|
|
166676
|
+
)
|
|
166677
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
166678
|
+
LIMIT ?`);
|
|
166679
|
+
const rows2 = stmt2.all(projectPath, sessionId, ...excludeIds, projectPath, modelId, Math.max(1, limit));
|
|
166680
|
+
return mapBackfillCandidateRows(rows2);
|
|
166681
|
+
}
|
|
166682
|
+
let stmt = sessionBackfillCandidateStatements.get(db);
|
|
166683
|
+
if (!stmt) {
|
|
166684
|
+
stmt = db.prepare(`SELECT c.id AS id,
|
|
166685
|
+
c.session_id AS sessionId,
|
|
166686
|
+
c.start_message AS startMessage,
|
|
166687
|
+
c.end_message AS endMessage,
|
|
166688
|
+
c.title AS title
|
|
166689
|
+
FROM compartments c
|
|
166690
|
+
JOIN session_projects sp
|
|
166691
|
+
ON sp.session_id = c.session_id
|
|
166692
|
+
AND sp.harness = c.harness
|
|
166693
|
+
AND sp.project_path = ?
|
|
166694
|
+
WHERE c.session_id = ?
|
|
166695
|
+
AND c.start_message IS NOT NULL
|
|
166696
|
+
AND c.end_message IS NOT NULL
|
|
166697
|
+
AND NOT EXISTS (
|
|
166698
|
+
SELECT 1
|
|
166699
|
+
FROM compartment_chunk_embeddings current
|
|
166700
|
+
WHERE current.compartment_id = c.id
|
|
166701
|
+
AND current.project_path = ?
|
|
166702
|
+
AND current.model_id = ?
|
|
166703
|
+
)
|
|
166704
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
166705
|
+
LIMIT ?`);
|
|
166706
|
+
sessionBackfillCandidateStatements.set(db, stmt);
|
|
166707
|
+
}
|
|
166708
|
+
const rows = stmt.all(projectPath, sessionId, projectPath, modelId, Math.max(1, limit));
|
|
166709
|
+
return mapBackfillCandidateRows(rows);
|
|
166710
|
+
}
|
|
166711
|
+
function countUnembeddedSessionCompartments(db, projectPath, sessionId, modelId) {
|
|
166712
|
+
const row = db.prepare(`SELECT COUNT(*) AS n
|
|
166713
|
+
FROM compartments c
|
|
166714
|
+
JOIN session_projects sp
|
|
166715
|
+
ON sp.session_id = c.session_id
|
|
166716
|
+
AND sp.harness = c.harness
|
|
166717
|
+
AND sp.project_path = ?
|
|
166718
|
+
WHERE c.session_id = ?
|
|
166719
|
+
AND c.start_message IS NOT NULL
|
|
166720
|
+
AND c.end_message IS NOT NULL
|
|
166721
|
+
AND NOT EXISTS (
|
|
166722
|
+
SELECT 1
|
|
166723
|
+
FROM compartment_chunk_embeddings current
|
|
166724
|
+
WHERE current.compartment_id = c.id
|
|
166725
|
+
AND current.project_path = ?
|
|
166726
|
+
AND current.model_id = ?
|
|
166727
|
+
)`).get(projectPath, sessionId, projectPath, modelId);
|
|
166728
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
166729
|
+
}
|
|
166730
|
+
|
|
165657
166731
|
// ../plugin/src/features/magic-context/memory/cosine-similarity.ts
|
|
165658
166732
|
function cosineSimilarity(a, b) {
|
|
165659
166733
|
if (a.length !== b.length) {
|
|
@@ -165812,19 +166886,19 @@ function isArrayLikeNumber(value) {
|
|
|
165812
166886
|
}
|
|
165813
166887
|
return arr.length === 0 || typeof arr[0] === "number";
|
|
165814
166888
|
}
|
|
165815
|
-
function
|
|
166889
|
+
function toFloat32Array3(values) {
|
|
165816
166890
|
return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
|
|
165817
166891
|
}
|
|
165818
166892
|
function extractBatchEmbeddings(result, expectedCount) {
|
|
165819
166893
|
const { data } = result;
|
|
165820
166894
|
if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
|
|
165821
|
-
return data.map((entry) =>
|
|
166895
|
+
return data.map((entry) => toFloat32Array3(entry));
|
|
165822
166896
|
}
|
|
165823
166897
|
if (!isArrayLikeNumber(data)) {
|
|
165824
166898
|
log("[magic-context] embedding batch returned unexpected data shape");
|
|
165825
166899
|
return Array.from({ length: expectedCount }, () => null);
|
|
165826
166900
|
}
|
|
165827
|
-
const flatData =
|
|
166901
|
+
const flatData = toFloat32Array3(data);
|
|
165828
166902
|
const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
|
|
165829
166903
|
if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
|
|
165830
166904
|
log("[magic-context] embedding batch returned invalid dimensions");
|
|
@@ -165839,6 +166913,7 @@ function extractBatchEmbeddings(result, expectedCount) {
|
|
|
165839
166913
|
|
|
165840
166914
|
class LocalEmbeddingProvider {
|
|
165841
166915
|
modelId;
|
|
166916
|
+
maxInputTokens;
|
|
165842
166917
|
model;
|
|
165843
166918
|
pipeline = null;
|
|
165844
166919
|
initPromise = null;
|
|
@@ -165846,8 +166921,9 @@ class LocalEmbeddingProvider {
|
|
|
165846
166921
|
disposing = false;
|
|
165847
166922
|
disposePromise = null;
|
|
165848
166923
|
inFlightWaiters = [];
|
|
165849
|
-
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
166924
|
+
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
|
|
165850
166925
|
this.model = model;
|
|
166926
|
+
this.maxInputTokens = maxInputTokens;
|
|
165851
166927
|
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
165852
166928
|
}
|
|
165853
166929
|
async initialize() {
|
|
@@ -166102,6 +167178,7 @@ var FETCH_TIMEOUT_MS = 30000;
|
|
|
166102
167178
|
|
|
166103
167179
|
class OpenAICompatibleEmbeddingProvider {
|
|
166104
167180
|
modelId;
|
|
167181
|
+
maxInputTokens;
|
|
166105
167182
|
endpoint;
|
|
166106
167183
|
model;
|
|
166107
167184
|
apiKey;
|
|
@@ -166118,11 +167195,13 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166118
167195
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
166119
167196
|
this.inputType = options.inputType?.trim() ?? "";
|
|
166120
167197
|
this.truncate = options.truncate?.trim() ?? "";
|
|
167198
|
+
this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
|
|
166121
167199
|
this.modelId = getEmbeddingProviderIdentity({
|
|
166122
167200
|
provider: "openai-compatible",
|
|
166123
167201
|
endpoint: this.endpoint,
|
|
166124
167202
|
model: this.model,
|
|
166125
|
-
...this.apiKey ? { api_key: this.apiKey } : {}
|
|
167203
|
+
...this.apiKey ? { api_key: this.apiKey } : {},
|
|
167204
|
+
...this.inputType ? { input_type: this.inputType } : {}
|
|
166126
167205
|
});
|
|
166127
167206
|
}
|
|
166128
167207
|
async initialize() {
|
|
@@ -166313,7 +167392,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166313
167392
|
}
|
|
166314
167393
|
|
|
166315
167394
|
// ../plugin/src/features/magic-context/project-embedding-registry.ts
|
|
166316
|
-
import { createHash as
|
|
167395
|
+
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
166317
167396
|
init_logger();
|
|
166318
167397
|
|
|
166319
167398
|
// ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
|
|
@@ -166321,7 +167400,7 @@ var saveStatements = new WeakMap;
|
|
|
166321
167400
|
var loadProjectStatements = new WeakMap;
|
|
166322
167401
|
var loadUnembeddedStatements = new WeakMap;
|
|
166323
167402
|
var countEmbeddedStatements = new WeakMap;
|
|
166324
|
-
var
|
|
167403
|
+
var clearProjectStatements2 = new WeakMap;
|
|
166325
167404
|
var distinctModelIdStatements = new WeakMap;
|
|
166326
167405
|
function getSaveStatement(db) {
|
|
166327
167406
|
let stmt = saveStatements.get(db);
|
|
@@ -166369,12 +167448,12 @@ function getCountEmbeddedStatement(db) {
|
|
|
166369
167448
|
}
|
|
166370
167449
|
return stmt;
|
|
166371
167450
|
}
|
|
166372
|
-
function
|
|
166373
|
-
let stmt =
|
|
167451
|
+
function getClearProjectStatement2(db) {
|
|
167452
|
+
let stmt = clearProjectStatements2.get(db);
|
|
166374
167453
|
if (!stmt) {
|
|
166375
167454
|
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
166376
167455
|
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
166377
|
-
|
|
167456
|
+
clearProjectStatements2.set(db, stmt);
|
|
166378
167457
|
}
|
|
166379
167458
|
return stmt;
|
|
166380
167459
|
}
|
|
@@ -166410,7 +167489,7 @@ function countEmbeddedCommits(db, projectPath) {
|
|
|
166410
167489
|
return row?.count ?? 0;
|
|
166411
167490
|
}
|
|
166412
167491
|
function clearProjectCommitEmbeddings(db, projectPath) {
|
|
166413
|
-
return
|
|
167492
|
+
return getClearProjectStatement2(db).run(projectPath).changes;
|
|
166414
167493
|
}
|
|
166415
167494
|
function getDistinctCommitEmbeddingModelIds(db, projectPath) {
|
|
166416
167495
|
const rows = getDistinctModelIdStatement(db).all(projectPath);
|
|
@@ -166536,9 +167615,83 @@ function releaseGitSweepLease(db, projectPath, holderId) {
|
|
|
166536
167615
|
});
|
|
166537
167616
|
}
|
|
166538
167617
|
|
|
167618
|
+
// ../plugin/src/features/magic-context/session-project-storage.ts
|
|
167619
|
+
var upsertSessionProjectStatements = new WeakMap;
|
|
167620
|
+
var repairSessionChunkProjectStatements = new WeakMap;
|
|
167621
|
+
var repairProjectChunkProjectStatements = new WeakMap;
|
|
167622
|
+
function getUpsertSessionProjectStatement(db) {
|
|
167623
|
+
let stmt = upsertSessionProjectStatements.get(db);
|
|
167624
|
+
if (!stmt) {
|
|
167625
|
+
stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
|
|
167626
|
+
VALUES (?, ?, ?, ?)
|
|
167627
|
+
ON CONFLICT(session_id, harness) DO UPDATE SET
|
|
167628
|
+
project_path = excluded.project_path,
|
|
167629
|
+
updated_at = excluded.updated_at
|
|
167630
|
+
WHERE session_projects.project_path <> excluded.project_path`);
|
|
167631
|
+
upsertSessionProjectStatements.set(db, stmt);
|
|
167632
|
+
}
|
|
167633
|
+
return stmt;
|
|
167634
|
+
}
|
|
167635
|
+
function getRepairSessionChunkProjectStatement(db) {
|
|
167636
|
+
let stmt = repairSessionChunkProjectStatements.get(db);
|
|
167637
|
+
if (!stmt) {
|
|
167638
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
167639
|
+
SET project_path = ?
|
|
167640
|
+
WHERE session_id = ?
|
|
167641
|
+
AND harness = ?
|
|
167642
|
+
AND project_path <> ?`);
|
|
167643
|
+
repairSessionChunkProjectStatements.set(db, stmt);
|
|
167644
|
+
}
|
|
167645
|
+
return stmt;
|
|
167646
|
+
}
|
|
167647
|
+
function getRepairProjectChunkProjectStatement(db) {
|
|
167648
|
+
let stmt = repairProjectChunkProjectStatements.get(db);
|
|
167649
|
+
if (!stmt) {
|
|
167650
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
167651
|
+
SET project_path = (
|
|
167652
|
+
SELECT sp.project_path
|
|
167653
|
+
FROM session_projects sp
|
|
167654
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
167655
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
167656
|
+
LIMIT 1
|
|
167657
|
+
)
|
|
167658
|
+
WHERE EXISTS (
|
|
167659
|
+
SELECT 1
|
|
167660
|
+
FROM session_projects sp
|
|
167661
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
167662
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
167663
|
+
AND sp.project_path <> compartment_chunk_embeddings.project_path
|
|
167664
|
+
AND (
|
|
167665
|
+
sp.project_path = ?
|
|
167666
|
+
OR compartment_chunk_embeddings.project_path = ?
|
|
167667
|
+
)
|
|
167668
|
+
)`);
|
|
167669
|
+
repairProjectChunkProjectStatements.set(db, stmt);
|
|
167670
|
+
}
|
|
167671
|
+
return stmt;
|
|
167672
|
+
}
|
|
167673
|
+
function recordSessionProjectIdentity(db, sessionId, projectPath) {
|
|
167674
|
+
if (!sessionId || !projectPath)
|
|
167675
|
+
return;
|
|
167676
|
+
const harness = getHarness();
|
|
167677
|
+
const now = Date.now();
|
|
167678
|
+
db.transaction(() => {
|
|
167679
|
+
getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
|
|
167680
|
+
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
|
|
167681
|
+
})();
|
|
167682
|
+
}
|
|
167683
|
+
function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
167684
|
+
if (!projectPath)
|
|
167685
|
+
return 0;
|
|
167686
|
+
return getRepairProjectChunkProjectStatement(db).run(projectPath, projectPath).changes;
|
|
167687
|
+
}
|
|
167688
|
+
|
|
166539
167689
|
// ../plugin/src/features/magic-context/project-embedding-registry.ts
|
|
166540
167690
|
var OFF_PROVIDER_IDENTITY = "embedding-provider:off";
|
|
166541
167691
|
var SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
167692
|
+
var CHUNK_DRAIN_BATCH_SIZE = 8;
|
|
167693
|
+
var MAX_WINDOWS_PER_EMBED_CALL = 16;
|
|
167694
|
+
var SESSION_EMBED_LEASE_RENEWAL_MS = 60 * 1000;
|
|
166542
167695
|
var projectRegistrations = new Map;
|
|
166543
167696
|
var loadUnembeddedMemoriesStatements = new WeakMap;
|
|
166544
167697
|
var globalRegistrationGeneration = 0;
|
|
@@ -166547,7 +167700,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
166547
167700
|
if (!config2 || config2.provider === "local") {
|
|
166548
167701
|
return {
|
|
166549
167702
|
provider: "local",
|
|
166550
|
-
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
167703
|
+
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
167704
|
+
...config2?.max_input_tokens ? {
|
|
167705
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
167706
|
+
} : {}
|
|
166551
167707
|
};
|
|
166552
167708
|
}
|
|
166553
167709
|
if (config2.provider === "openai-compatible") {
|
|
@@ -166560,7 +167716,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
166560
167716
|
endpoint: config2.endpoint.trim(),
|
|
166561
167717
|
...apiKey ? { api_key: apiKey } : {},
|
|
166562
167718
|
...inputType ? { input_type: inputType } : {},
|
|
166563
|
-
...truncate ? { truncate } : {}
|
|
167719
|
+
...truncate ? { truncate } : {},
|
|
167720
|
+
...config2.max_input_tokens ? {
|
|
167721
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
167722
|
+
} : {}
|
|
166564
167723
|
};
|
|
166565
167724
|
}
|
|
166566
167725
|
return { provider: "off" };
|
|
@@ -166578,10 +167737,11 @@ function createProvider(config2) {
|
|
|
166578
167737
|
model: config2.model,
|
|
166579
167738
|
apiKey: config2.api_key,
|
|
166580
167739
|
inputType: config2.input_type,
|
|
166581
|
-
truncate: config2.truncate
|
|
167740
|
+
truncate: config2.truncate,
|
|
167741
|
+
maxInputTokens: config2.max_input_tokens
|
|
166582
167742
|
});
|
|
166583
167743
|
}
|
|
166584
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
167744
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
166585
167745
|
}
|
|
166586
167746
|
function stableStringify2(value) {
|
|
166587
167747
|
if (Array.isArray(value)) {
|
|
@@ -166594,7 +167754,7 @@ function stableStringify2(value) {
|
|
|
166594
167754
|
return JSON.stringify(value);
|
|
166595
167755
|
}
|
|
166596
167756
|
function sha256Prefix(value, length = 16) {
|
|
166597
|
-
return
|
|
167757
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, length);
|
|
166598
167758
|
}
|
|
166599
167759
|
function getRuntimeFingerprint(config2) {
|
|
166600
167760
|
if (config2.provider === "off") {
|
|
@@ -166602,6 +167762,18 @@ function getRuntimeFingerprint(config2) {
|
|
|
166602
167762
|
}
|
|
166603
167763
|
return `${getEmbeddingProviderIdentity(config2)}:${sha256Prefix(stableStringify2(config2))}`;
|
|
166604
167764
|
}
|
|
167765
|
+
function getChunkEmbeddingModelId(config2, providerIdentity) {
|
|
167766
|
+
if (config2.provider === "off") {
|
|
167767
|
+
return OFF_PROVIDER_IDENTITY;
|
|
167768
|
+
}
|
|
167769
|
+
const chunkIdentity = {
|
|
167770
|
+
providerIdentity,
|
|
167771
|
+
chunkerVersion: 1,
|
|
167772
|
+
maxInputTokens: normalizeCompartmentChunkMaxInputTokens("max_input_tokens" in config2 ? config2.max_input_tokens : undefined),
|
|
167773
|
+
truncate: config2.provider === "openai-compatible" ? config2.truncate ?? "" : ""
|
|
167774
|
+
};
|
|
167775
|
+
return `${providerIdentity}:chunk:${sha256Prefix(stableStringify2(chunkIdentity))}`;
|
|
167776
|
+
}
|
|
166605
167777
|
function sameFeatures(a, b) {
|
|
166606
167778
|
return a.memoryEnabled === b.memoryEnabled && a.gitCommitEnabled === b.gitCommitEnabled;
|
|
166607
167779
|
}
|
|
@@ -166618,7 +167790,8 @@ function snapshotFor(registration) {
|
|
|
166618
167790
|
features: { ...registration.features },
|
|
166619
167791
|
enabled,
|
|
166620
167792
|
gitCommitEnabled,
|
|
166621
|
-
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId
|
|
167793
|
+
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
|
|
167794
|
+
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId
|
|
166622
167795
|
};
|
|
166623
167796
|
}
|
|
166624
167797
|
function disposeProvider(provider) {
|
|
@@ -166638,7 +167811,7 @@ function anyStoredModelIdIsStale(storedIds, currentId) {
|
|
|
166638
167811
|
}
|
|
166639
167812
|
return false;
|
|
166640
167813
|
}
|
|
166641
|
-
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, features) {
|
|
167814
|
+
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, currentChunkIdentity, features) {
|
|
166642
167815
|
if (currentProviderIdentity === OFF_PROVIDER_IDENTITY) {
|
|
166643
167816
|
return false;
|
|
166644
167817
|
}
|
|
@@ -166659,6 +167832,14 @@ function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity,
|
|
|
166659
167832
|
wiped = true;
|
|
166660
167833
|
}
|
|
166661
167834
|
}
|
|
167835
|
+
if (features.memoryEnabled) {
|
|
167836
|
+
repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectIdentity);
|
|
167837
|
+
const chunkIds = getDistinctChunkEmbeddingModelIds(db, projectIdentity);
|
|
167838
|
+
if (anyStoredModelIdIsStale(chunkIds, currentChunkIdentity)) {
|
|
167839
|
+
clearChunkEmbeddingsForProject(db, projectIdentity);
|
|
167840
|
+
wiped = true;
|
|
167841
|
+
}
|
|
167842
|
+
}
|
|
166662
167843
|
})();
|
|
166663
167844
|
return wiped;
|
|
166664
167845
|
}
|
|
@@ -166666,10 +167847,11 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
166666
167847
|
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
166667
167848
|
const providerIdentity = getEmbeddingProviderIdentity(resolvedConfig);
|
|
166668
167849
|
const runtimeFingerprint = getRuntimeFingerprint(resolvedConfig);
|
|
167850
|
+
const chunkModelId = getChunkEmbeddingModelId(resolvedConfig, providerIdentity);
|
|
166669
167851
|
const prior = projectRegistrations.get(projectIdentity);
|
|
166670
167852
|
const canReuseProvider = prior !== undefined && !prior.observationMode && prior.runtimeFingerprint === runtimeFingerprint && prior.providerIdentity === providerIdentity;
|
|
166671
|
-
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, features);
|
|
166672
|
-
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || !sameFeatures(prior.features, features) || wiped;
|
|
167853
|
+
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, chunkModelId, features);
|
|
167854
|
+
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || prior.chunkModelId !== chunkModelId || !sameFeatures(prior.features, features) || wiped;
|
|
166673
167855
|
const generation = generationChanged ? ++globalRegistrationGeneration : prior.generation;
|
|
166674
167856
|
const registration = {
|
|
166675
167857
|
projectIdentity,
|
|
@@ -166681,6 +167863,7 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
166681
167863
|
generation,
|
|
166682
167864
|
features: { ...features },
|
|
166683
167865
|
modelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : providerIdentity,
|
|
167866
|
+
chunkModelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : chunkModelId,
|
|
166684
167867
|
observationMode: false
|
|
166685
167868
|
};
|
|
166686
167869
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -166703,6 +167886,7 @@ function registerProjectInObservationMode(db, projectIdentity, sourceDirectory,
|
|
|
166703
167886
|
generation,
|
|
166704
167887
|
features: { memoryEnabled: false, gitCommitEnabled: false },
|
|
166705
167888
|
modelId: "off",
|
|
167889
|
+
chunkModelId: "off",
|
|
166706
167890
|
observationMode: true
|
|
166707
167891
|
};
|
|
166708
167892
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -166713,6 +167897,15 @@ function getProjectEmbeddingSnapshot(projectIdentity) {
|
|
|
166713
167897
|
const registration = projectRegistrations.get(projectIdentity);
|
|
166714
167898
|
return registration ? snapshotFor(registration) : null;
|
|
166715
167899
|
}
|
|
167900
|
+
function getProjectChunkEmbeddingModelId(projectIdentity) {
|
|
167901
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
167902
|
+
return registration && !registration.observationMode ? registration.chunkModelId : "off";
|
|
167903
|
+
}
|
|
167904
|
+
function getProjectEmbeddingMaxInputTokens(projectIdentity) {
|
|
167905
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
167906
|
+
const configMax = registration?.config && "max_input_tokens" in registration.config ? registration.config.max_input_tokens : undefined;
|
|
167907
|
+
return normalizeCompartmentChunkMaxInputTokens(registration?.provider?.maxInputTokens ?? configMax);
|
|
167908
|
+
}
|
|
166716
167909
|
function getOrCreateProjectProvider(registration) {
|
|
166717
167910
|
if (registration.providerIdentity === OFF_PROVIDER_IDENTITY || registration.observationMode) {
|
|
166718
167911
|
return null;
|
|
@@ -166807,6 +168000,131 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
166807
168000
|
return 0;
|
|
166808
168001
|
}
|
|
166809
168002
|
}
|
|
168003
|
+
async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal) {
|
|
168004
|
+
const noWork = [];
|
|
168005
|
+
if (candidates.length === 0)
|
|
168006
|
+
return { embedded: 0, noWork };
|
|
168007
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
|
|
168008
|
+
const prepared = [];
|
|
168009
|
+
for (const candidate of candidates) {
|
|
168010
|
+
const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
|
|
168011
|
+
if (canonicalText.length === 0) {
|
|
168012
|
+
noWork.push(candidate.id);
|
|
168013
|
+
continue;
|
|
168014
|
+
}
|
|
168015
|
+
const windows = chunkCanonicalText(canonicalText, candidate.startMessage, candidate.endMessage, maxInputTokens);
|
|
168016
|
+
if (windows.length === 0 || chunkEmbeddingWindowsAreCurrent(db, candidate.id, modelId, windows, projectIdentity)) {
|
|
168017
|
+
noWork.push(candidate.id);
|
|
168018
|
+
continue;
|
|
168019
|
+
}
|
|
168020
|
+
prepared.push({ candidate, windows });
|
|
168021
|
+
}
|
|
168022
|
+
if (prepared.length === 0)
|
|
168023
|
+
return { embedded: 0, noWork };
|
|
168024
|
+
let embedded = 0;
|
|
168025
|
+
let i = 0;
|
|
168026
|
+
while (i < prepared.length) {
|
|
168027
|
+
if (signal?.aborted)
|
|
168028
|
+
break;
|
|
168029
|
+
const slice = [];
|
|
168030
|
+
let windowCount = 0;
|
|
168031
|
+
do {
|
|
168032
|
+
const item = prepared[i];
|
|
168033
|
+
slice.push(item);
|
|
168034
|
+
windowCount += item.windows.length;
|
|
168035
|
+
i += 1;
|
|
168036
|
+
} while (i < prepared.length && windowCount + prepared[i].windows.length <= MAX_WINDOWS_PER_EMBED_CALL);
|
|
168037
|
+
const texts = [];
|
|
168038
|
+
for (const item of slice)
|
|
168039
|
+
texts.push(...item.windows.map((w) => w.text));
|
|
168040
|
+
try {
|
|
168041
|
+
const result = await embedBatchForProject(projectIdentity, texts, signal);
|
|
168042
|
+
if (!result)
|
|
168043
|
+
continue;
|
|
168044
|
+
if (signal?.aborted)
|
|
168045
|
+
break;
|
|
168046
|
+
let offset = 0;
|
|
168047
|
+
for (const item of slice) {
|
|
168048
|
+
const vectors = result.vectors.slice(offset, offset + item.windows.length);
|
|
168049
|
+
offset += item.windows.length;
|
|
168050
|
+
if (vectors.length !== item.windows.length || vectors.some((v) => !v)) {
|
|
168051
|
+
continue;
|
|
168052
|
+
}
|
|
168053
|
+
const rows = item.windows.map((window, index) => ({
|
|
168054
|
+
compartmentId: item.candidate.id,
|
|
168055
|
+
sessionId: item.candidate.sessionId,
|
|
168056
|
+
projectPath: projectIdentity,
|
|
168057
|
+
window,
|
|
168058
|
+
modelId,
|
|
168059
|
+
vector: vectors[index]
|
|
168060
|
+
}));
|
|
168061
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
168062
|
+
embedded += 1;
|
|
168063
|
+
}
|
|
168064
|
+
} catch (error51) {
|
|
168065
|
+
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
168066
|
+
}
|
|
168067
|
+
}
|
|
168068
|
+
return { embedded, noWork };
|
|
168069
|
+
}
|
|
168070
|
+
async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, options) {
|
|
168071
|
+
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
168072
|
+
if (!snapshot?.enabled || snapshot.chunkModelId === "off") {
|
|
168073
|
+
return { status: "disabled", embedded: 0, total: 0 };
|
|
168074
|
+
}
|
|
168075
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
168076
|
+
const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId);
|
|
168077
|
+
if (total === 0)
|
|
168078
|
+
return { status: "nothing", embedded: 0, total: 0 };
|
|
168079
|
+
const holderId = `session-embed-${randomUUID()}`;
|
|
168080
|
+
const lease2 = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
|
|
168081
|
+
if (!lease2.acquired)
|
|
168082
|
+
return { status: "busy", embedded: 0, total };
|
|
168083
|
+
const renewal = setInterval(() => {
|
|
168084
|
+
try {
|
|
168085
|
+
renewGitSweepLease(db, projectIdentity, holderId);
|
|
168086
|
+
} catch {}
|
|
168087
|
+
}, SESSION_EMBED_LEASE_RENEWAL_MS);
|
|
168088
|
+
renewal.unref?.();
|
|
168089
|
+
const batchSize = Math.max(1, options?.batchSize ?? CHUNK_DRAIN_BATCH_SIZE);
|
|
168090
|
+
const skipIds = [];
|
|
168091
|
+
let embedded = 0;
|
|
168092
|
+
let aborted2 = false;
|
|
168093
|
+
let providerStalled = false;
|
|
168094
|
+
try {
|
|
168095
|
+
options?.onProgress?.({ embedded, total });
|
|
168096
|
+
for (;; ) {
|
|
168097
|
+
if (options?.signal?.aborted) {
|
|
168098
|
+
aborted2 = true;
|
|
168099
|
+
break;
|
|
168100
|
+
}
|
|
168101
|
+
const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, skipIds);
|
|
168102
|
+
if (candidates.length === 0)
|
|
168103
|
+
break;
|
|
168104
|
+
const { embedded: n, noWork } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, options?.signal);
|
|
168105
|
+
for (const id of noWork)
|
|
168106
|
+
skipIds.push(id);
|
|
168107
|
+
if (n === 0 && noWork.length === 0) {
|
|
168108
|
+
providerStalled = true;
|
|
168109
|
+
break;
|
|
168110
|
+
}
|
|
168111
|
+
embedded += n;
|
|
168112
|
+
options?.onProgress?.({ embedded: Math.min(embedded, total), total });
|
|
168113
|
+
await new Promise((resolve4) => setTimeout(resolve4, 0));
|
|
168114
|
+
}
|
|
168115
|
+
} finally {
|
|
168116
|
+
clearInterval(renewal);
|
|
168117
|
+
releaseGitSweepLease(db, projectIdentity, holderId);
|
|
168118
|
+
}
|
|
168119
|
+
if (aborted2)
|
|
168120
|
+
return { status: "aborted", embedded, total };
|
|
168121
|
+
if (providerStalled) {
|
|
168122
|
+
const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId) - skipIds.length);
|
|
168123
|
+
if (remaining > 0)
|
|
168124
|
+
return { status: "stalled", embedded, total, remaining };
|
|
168125
|
+
}
|
|
168126
|
+
return { status: "done", embedded, total };
|
|
168127
|
+
}
|
|
166810
168128
|
|
|
166811
168129
|
// ../plugin/src/features/magic-context/memory/embedding.ts
|
|
166812
168130
|
var DEFAULT_EMBEDDING_CONFIG = {
|
|
@@ -166826,10 +168144,11 @@ function createProvider2(config2) {
|
|
|
166826
168144
|
model: config2.model,
|
|
166827
168145
|
apiKey: config2.api_key,
|
|
166828
168146
|
inputType: config2.input_type,
|
|
166829
|
-
truncate: config2.truncate
|
|
168147
|
+
truncate: config2.truncate,
|
|
168148
|
+
maxInputTokens: config2.max_input_tokens
|
|
166830
168149
|
});
|
|
166831
168150
|
}
|
|
166832
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
168151
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
166833
168152
|
}
|
|
166834
168153
|
function getOrCreateProvider() {
|
|
166835
168154
|
if (provider) {
|
|
@@ -167072,6 +168391,7 @@ init_logger();
|
|
|
167072
168391
|
// ../plugin/src/features/magic-context/memory/storage-memory-fts.ts
|
|
167073
168392
|
var DEFAULT_SEARCH_LIMIT = 10;
|
|
167074
168393
|
var searchStatements = new WeakMap;
|
|
168394
|
+
var unionSearchStatements = new Map;
|
|
167075
168395
|
function getSearchStatement(db) {
|
|
167076
168396
|
let stmt = searchStatements.get(db);
|
|
167077
168397
|
if (!stmt) {
|
|
@@ -167080,6 +168400,23 @@ function getSearchStatement(db) {
|
|
|
167080
168400
|
}
|
|
167081
168401
|
return stmt;
|
|
167082
168402
|
}
|
|
168403
|
+
function getUnionSearchStatement(db, arity) {
|
|
168404
|
+
let statements = unionSearchStatements.get(arity);
|
|
168405
|
+
if (!statements) {
|
|
168406
|
+
statements = new WeakMap;
|
|
168407
|
+
unionSearchStatements.set(arity, statements);
|
|
168408
|
+
}
|
|
168409
|
+
let stmt = statements.get(db);
|
|
168410
|
+
if (!stmt) {
|
|
168411
|
+
const placeholders3 = Array.from({ length: arity }, () => "?").join(", ");
|
|
168412
|
+
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 ?`);
|
|
168413
|
+
statements.set(db, stmt);
|
|
168414
|
+
}
|
|
168415
|
+
return stmt;
|
|
168416
|
+
}
|
|
168417
|
+
function uniqueProjectPaths2(projectPaths) {
|
|
168418
|
+
return [...new Set(projectPaths.filter((path7) => path7.length > 0))];
|
|
168419
|
+
}
|
|
167083
168420
|
function sanitizeFtsQuery(query) {
|
|
167084
168421
|
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
167085
168422
|
if (tokens.length === 0)
|
|
@@ -167098,6 +168435,28 @@ function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT)
|
|
|
167098
168435
|
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
167099
168436
|
return rows.map(toMemory);
|
|
167100
168437
|
}
|
|
168438
|
+
function searchMemoriesFTSUnion(db, projectPaths, query, limit = DEFAULT_SEARCH_LIMIT, ownIdentities, shareCategories) {
|
|
168439
|
+
const identities = uniqueProjectPaths2(projectPaths);
|
|
168440
|
+
if (identities.length === 0)
|
|
168441
|
+
return [];
|
|
168442
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
168443
|
+
identities,
|
|
168444
|
+
ownIdentities,
|
|
168445
|
+
shareCategories,
|
|
168446
|
+
tableName: "memories"
|
|
168447
|
+
});
|
|
168448
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
168449
|
+
return searchMemoriesFTS(db, identities[0], query, limit);
|
|
168450
|
+
}
|
|
168451
|
+
const trimmedQuery = query.trim();
|
|
168452
|
+
if (trimmedQuery.length === 0 || limit <= 0)
|
|
168453
|
+
return [];
|
|
168454
|
+
const sanitized = sanitizeFtsQuery(trimmedQuery);
|
|
168455
|
+
if (sanitized.length === 0)
|
|
168456
|
+
return [];
|
|
168457
|
+
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);
|
|
168458
|
+
return rows.map(toMemory);
|
|
168459
|
+
}
|
|
167101
168460
|
|
|
167102
168461
|
// ../plugin/src/features/magic-context/git-commits/search-git-commits.ts
|
|
167103
168462
|
var ftsStatements = new WeakMap;
|
|
@@ -167390,7 +168749,7 @@ async function sweepGitCommits(args) {
|
|
|
167390
168749
|
}
|
|
167391
168750
|
|
|
167392
168751
|
// ../plugin/src/plugin/embedding-bootstrap-helpers.ts
|
|
167393
|
-
import { createHash as
|
|
168752
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
167394
168753
|
init_logger();
|
|
167395
168754
|
var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
167396
168755
|
"embedding.api_key",
|
|
@@ -167412,7 +168771,7 @@ var EMBEDDING_WARNING_TERMS = [
|
|
|
167412
168771
|
];
|
|
167413
168772
|
var loggedFailureSignatures = new Map;
|
|
167414
168773
|
function sha256Prefix2(value, length = 16) {
|
|
167415
|
-
return
|
|
168774
|
+
return createHash10("sha256").update(value).digest("hex").slice(0, length);
|
|
167416
168775
|
}
|
|
167417
168776
|
function warningLooksEmbeddingRelated(message) {
|
|
167418
168777
|
const lower = message.toLowerCase();
|
|
@@ -168458,6 +169817,88 @@ function registerCtxDreamCommand(pi, deps) {
|
|
|
168458
169817
|
});
|
|
168459
169818
|
}
|
|
168460
169819
|
|
|
169820
|
+
// src/commands/ctx-embed-history.ts
|
|
169821
|
+
function registerCtxEmbedHistoryCommand(pi, deps) {
|
|
169822
|
+
pi.registerCommand("ctx-embed-history", {
|
|
169823
|
+
description: "Embed all of this session's history compartments for semantic search, in one pass",
|
|
169824
|
+
handler: async (_args, ctx) => {
|
|
169825
|
+
const sessionId = resolveSessionId(ctx);
|
|
169826
|
+
if (!sessionId) {
|
|
169827
|
+
sendCtxStatusMessage(pi, {
|
|
169828
|
+
title: "/ctx-embed-history",
|
|
169829
|
+
text: `## /ctx-embed-history
|
|
169830
|
+
|
|
169831
|
+
No active Pi session is available.`,
|
|
169832
|
+
level: "error"
|
|
169833
|
+
});
|
|
169834
|
+
return;
|
|
169835
|
+
}
|
|
169836
|
+
if (deps.memoryEnabled === false) {
|
|
169837
|
+
sendCtxStatusMessage(pi, {
|
|
169838
|
+
title: "/ctx-embed-history",
|
|
169839
|
+
text: `## /ctx-embed-history
|
|
169840
|
+
|
|
169841
|
+
Memory is disabled for this project, so there is no semantic embedding to backfill.`,
|
|
169842
|
+
level: "info"
|
|
169843
|
+
});
|
|
169844
|
+
return;
|
|
169845
|
+
}
|
|
169846
|
+
const project = deps.resolveProject?.(ctx) ?? {
|
|
169847
|
+
projectDir: deps.projectDir,
|
|
169848
|
+
projectIdentity: deps.projectIdentity
|
|
169849
|
+
};
|
|
169850
|
+
await ensureProjectRegisteredFromPiDirectory(project.projectDir, deps.db);
|
|
169851
|
+
const outcome = await embedSessionCompartmentChunks(deps.db, project.projectIdentity, sessionId);
|
|
169852
|
+
const { text, level } = (() => {
|
|
169853
|
+
switch (outcome.status) {
|
|
169854
|
+
case "nothing":
|
|
169855
|
+
return {
|
|
169856
|
+
text: `## /ctx-embed-history
|
|
169857
|
+
|
|
169858
|
+
All of this session's history is already embedded.`,
|
|
169859
|
+
level: "info"
|
|
169860
|
+
};
|
|
169861
|
+
case "disabled":
|
|
169862
|
+
return {
|
|
169863
|
+
text: `## /ctx-embed-history
|
|
169864
|
+
|
|
169865
|
+
No embedding provider is configured, so there is nothing to embed.`,
|
|
169866
|
+
level: "info"
|
|
169867
|
+
};
|
|
169868
|
+
case "busy":
|
|
169869
|
+
return {
|
|
169870
|
+
text: `## /ctx-embed-history
|
|
169871
|
+
|
|
169872
|
+
Embedding is already running for this project — ${outcome.total} compartment${outcome.total === 1 ? "" : "s"} still pending. Try again shortly.`,
|
|
169873
|
+
level: "info"
|
|
169874
|
+
};
|
|
169875
|
+
case "stalled":
|
|
169876
|
+
return {
|
|
169877
|
+
text: `## /ctx-embed-history
|
|
169878
|
+
|
|
169879
|
+
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.`,
|
|
169880
|
+
level: "info"
|
|
169881
|
+
};
|
|
169882
|
+
default:
|
|
169883
|
+
return {
|
|
169884
|
+
text: `## /ctx-embed-history
|
|
169885
|
+
|
|
169886
|
+
Embedded ${outcome.embedded} compartment${outcome.embedded === 1 ? "" : "s"} of history for semantic search.`,
|
|
169887
|
+
level: "success"
|
|
169888
|
+
};
|
|
169889
|
+
}
|
|
169890
|
+
})();
|
|
169891
|
+
sendCtxStatusMessage(pi, { title: "/ctx-embed-history", text, level }, {
|
|
169892
|
+
sessionId,
|
|
169893
|
+
projectIdentity: project.projectIdentity,
|
|
169894
|
+
status: outcome.status,
|
|
169895
|
+
embedded: outcome.embedded,
|
|
169896
|
+
total: outcome.total
|
|
169897
|
+
});
|
|
169898
|
+
}
|
|
169899
|
+
});
|
|
169900
|
+
}
|
|
169901
|
+
|
|
168461
169902
|
// ../plugin/src/hooks/magic-context/execute-flush.ts
|
|
168462
169903
|
init_logger();
|
|
168463
169904
|
function executeFlush(db, sessionId) {
|
|
@@ -168873,6 +170314,7 @@ function computePiWorkMetrics(sessionEntries) {
|
|
|
168873
170314
|
|
|
168874
170315
|
// ../plugin/src/hooks/magic-context/apply-operations.ts
|
|
168875
170316
|
var USER_DROP_PREVIEW_CHARS = 250;
|
|
170317
|
+
var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
168876
170318
|
function buildReplacementContent(tagId, target) {
|
|
168877
170319
|
const role = target.message?.info.role;
|
|
168878
170320
|
if (role !== "user") {
|
|
@@ -168898,6 +170340,7 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
168898
170340
|
const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
|
|
168899
170341
|
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;
|
|
168900
170342
|
const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
|
|
170343
|
+
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));
|
|
168901
170344
|
for (const pendingOp of pendingOps) {
|
|
168902
170345
|
const tagStatus = tagStatusById.get(pendingOp.tagId);
|
|
168903
170346
|
if (tagStatus === "compacted" || tagStatus === "dropped") {
|
|
@@ -168910,14 +170353,25 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
168910
170353
|
const target = targets.get(pendingOp.tagId);
|
|
168911
170354
|
const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
|
|
168912
170355
|
if (isToolTag) {
|
|
168913
|
-
|
|
168914
|
-
|
|
168915
|
-
|
|
168916
|
-
|
|
168917
|
-
|
|
168918
|
-
|
|
170356
|
+
if (skeletonWindow.has(pendingOp.tagId)) {
|
|
170357
|
+
const truncResult = target?.truncate?.() ?? "absent";
|
|
170358
|
+
if (truncResult === "incomplete") {
|
|
170359
|
+
continue;
|
|
170360
|
+
}
|
|
170361
|
+
if (truncResult === "truncated") {
|
|
170362
|
+
didMutateMessage = true;
|
|
170363
|
+
}
|
|
170364
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, "truncated");
|
|
170365
|
+
} else {
|
|
170366
|
+
const dropResult = target?.drop?.() ?? "absent";
|
|
170367
|
+
if (dropResult === "incomplete") {
|
|
170368
|
+
continue;
|
|
170369
|
+
}
|
|
170370
|
+
if (dropResult === "removed") {
|
|
170371
|
+
didMutateMessage = true;
|
|
170372
|
+
}
|
|
170373
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, "full");
|
|
168919
170374
|
}
|
|
168920
|
-
updateTagDropMode(db, sessionId, pendingOp.tagId, "full");
|
|
168921
170375
|
} else if (target) {
|
|
168922
170376
|
const changed = target.setContent(buildReplacementContent(pendingOp.tagId, target));
|
|
168923
170377
|
if (changed)
|
|
@@ -170580,53 +172034,6 @@ ${body}
|
|
|
170580
172034
|
</system-reminder>`;
|
|
170581
172035
|
}
|
|
170582
172036
|
|
|
170583
|
-
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
170584
|
-
var V2_MEMORY_CATEGORIES = [
|
|
170585
|
-
"PROJECT_RULES",
|
|
170586
|
-
"ARCHITECTURE",
|
|
170587
|
-
"CONSTRAINTS",
|
|
170588
|
-
"CONFIG_VALUES",
|
|
170589
|
-
"NAMING"
|
|
170590
|
-
];
|
|
170591
|
-
var PROMOTABLE_CATEGORIES = [
|
|
170592
|
-
"PROJECT_RULES",
|
|
170593
|
-
"ARCHITECTURE",
|
|
170594
|
-
"CONSTRAINTS",
|
|
170595
|
-
"CONFIG_VALUES",
|
|
170596
|
-
"NAMING",
|
|
170597
|
-
"ARCHITECTURE_DECISIONS",
|
|
170598
|
-
"CONFIG_DEFAULTS",
|
|
170599
|
-
"USER_PREFERENCES",
|
|
170600
|
-
"USER_DIRECTIVES",
|
|
170601
|
-
"ENVIRONMENT",
|
|
170602
|
-
"WORKFLOW_RULES",
|
|
170603
|
-
"KNOWN_ISSUES"
|
|
170604
|
-
];
|
|
170605
|
-
var CATEGORY_PRIORITY = [
|
|
170606
|
-
"PROJECT_RULES",
|
|
170607
|
-
"ARCHITECTURE",
|
|
170608
|
-
"CONSTRAINTS",
|
|
170609
|
-
"CONFIG_VALUES",
|
|
170610
|
-
"NAMING",
|
|
170611
|
-
"USER_DIRECTIVES",
|
|
170612
|
-
"USER_PREFERENCES",
|
|
170613
|
-
"CONFIG_DEFAULTS",
|
|
170614
|
-
"ARCHITECTURE_DECISIONS",
|
|
170615
|
-
"ENVIRONMENT",
|
|
170616
|
-
"WORKFLOW_RULES",
|
|
170617
|
-
"KNOWN_ISSUES"
|
|
170618
|
-
];
|
|
170619
|
-
var MEMORY_CATEGORY_ORDER_UNKNOWN = 99;
|
|
170620
|
-
var MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
170621
|
-
acc[category] = index;
|
|
170622
|
-
return acc;
|
|
170623
|
-
}, {});
|
|
170624
|
-
var MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
170625
|
-
var CATEGORY_DEFAULT_TTL = {
|
|
170626
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
170627
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
170628
|
-
};
|
|
170629
|
-
|
|
170630
172037
|
// ../plugin/src/shared/bounded-session-map.ts
|
|
170631
172038
|
class BoundedSessionMap {
|
|
170632
172039
|
maxEntries;
|
|
@@ -171037,26 +172444,40 @@ ${sections.join(`
|
|
|
171037
172444
|
var DEFAULT_MEMORY_BUDGET_TOKENS = 8000;
|
|
171038
172445
|
var MEMORY_BLOCK_WRAPPER_TOKENS = 6;
|
|
171039
172446
|
var DEFAULT_USER_PROFILE_BUDGET_TOKENS = 4000;
|
|
172447
|
+
function memoryCanonicalIdentity(memory, workspace) {
|
|
172448
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
172449
|
+
}
|
|
172450
|
+
function memorySelectionOrder(left, right) {
|
|
172451
|
+
if (left.status === "permanent" && right.status !== "permanent")
|
|
172452
|
+
return -1;
|
|
172453
|
+
if (right.status === "permanent" && left.status !== "permanent")
|
|
172454
|
+
return 1;
|
|
172455
|
+
const leftImportance = left.importance ?? Number.NEGATIVE_INFINITY;
|
|
172456
|
+
const rightImportance = right.importance ?? Number.NEGATIVE_INFINITY;
|
|
172457
|
+
const importanceDiff = rightImportance - leftImportance;
|
|
172458
|
+
if (importanceDiff !== 0)
|
|
172459
|
+
return importanceDiff;
|
|
172460
|
+
return left.id - right.id;
|
|
172461
|
+
}
|
|
172462
|
+
function memoryRenderOrder(left, right) {
|
|
172463
|
+
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[left.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
172464
|
+
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[right.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
172465
|
+
const categoryDiff = aPriority - bPriority;
|
|
172466
|
+
if (categoryDiff !== 0)
|
|
172467
|
+
return categoryDiff;
|
|
172468
|
+
return left.id - right.id;
|
|
172469
|
+
}
|
|
171040
172470
|
var maxCompartmentSeqStatements = new WeakMap;
|
|
171041
172471
|
var maxMemoryIdStatements = new WeakMap;
|
|
171042
172472
|
var legacyCompartmentCountStatements = new WeakMap;
|
|
171043
172473
|
var m0CompartmentStatements = new WeakMap;
|
|
171044
172474
|
var newCompartmentStatements = new WeakMap;
|
|
171045
|
-
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
171046
|
-
const selectionOrder = [...memories].sort(
|
|
171047
|
-
if (a.status === "permanent" && b.status !== "permanent")
|
|
171048
|
-
return -1;
|
|
171049
|
-
if (b.status === "permanent" && a.status !== "permanent")
|
|
171050
|
-
return 1;
|
|
171051
|
-
const importanceDiff = (b.importance ?? 50) - (a.importance ?? 50);
|
|
171052
|
-
if (importanceDiff !== 0)
|
|
171053
|
-
return importanceDiff;
|
|
171054
|
-
return a.id - b.id;
|
|
171055
|
-
});
|
|
172475
|
+
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions = {}) {
|
|
172476
|
+
const selectionOrder = [...memories].sort(memorySelectionOrder);
|
|
171056
172477
|
const selected = [];
|
|
171057
172478
|
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
171058
172479
|
for (const memory of selectionOrder) {
|
|
171059
|
-
const memoryTokens = estimateTokens(renderMemoryLineV2(memory));
|
|
172480
|
+
const memoryTokens = estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
171060
172481
|
if (usedTokens + memoryTokens > budgetTokens)
|
|
171061
172482
|
continue;
|
|
171062
172483
|
selected.push(memory);
|
|
@@ -171065,16 +172486,70 @@ function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
|
171065
172486
|
if (selected.length < memories.length) {
|
|
171066
172487
|
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
171067
172488
|
}
|
|
171068
|
-
const renderOrder = [...selected].sort(
|
|
171069
|
-
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[a.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
171070
|
-
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[b.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
171071
|
-
const categoryDiff = aPriority - bPriority;
|
|
171072
|
-
if (categoryDiff !== 0)
|
|
171073
|
-
return categoryDiff;
|
|
171074
|
-
return a.id - b.id;
|
|
171075
|
-
});
|
|
172489
|
+
const renderOrder = [...selected].sort(memoryRenderOrder);
|
|
171076
172490
|
return { selected, renderOrder };
|
|
171077
172491
|
}
|
|
172492
|
+
function trimWorkspaceMemoriesToBudgetV2(sessionId, memories, budgetTokens, workspace, renderOptions = {}) {
|
|
172493
|
+
if (!workspace.isWorkspaced) {
|
|
172494
|
+
return trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions);
|
|
172495
|
+
}
|
|
172496
|
+
const selected = [];
|
|
172497
|
+
const selectedIds = new Set;
|
|
172498
|
+
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
172499
|
+
const tokenCost = (memory) => estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
172500
|
+
const trySelect = (memory) => {
|
|
172501
|
+
if (selectedIds.has(memory.id))
|
|
172502
|
+
return false;
|
|
172503
|
+
const tokens = tokenCost(memory);
|
|
172504
|
+
if (usedTokens + tokens > budgetTokens)
|
|
172505
|
+
return false;
|
|
172506
|
+
selected.push(memory);
|
|
172507
|
+
selectedIds.add(memory.id);
|
|
172508
|
+
usedTokens += tokens;
|
|
172509
|
+
return true;
|
|
172510
|
+
};
|
|
172511
|
+
for (const memory of memories.filter((candidate) => candidate.status === "permanent").sort(memorySelectionOrder)) {
|
|
172512
|
+
trySelect(memory);
|
|
172513
|
+
}
|
|
172514
|
+
const remainingAfterPermanent = Math.max(0, budgetTokens - usedTokens);
|
|
172515
|
+
const floorTokens = remainingAfterPermanent / Math.max(1, workspace.identities.length);
|
|
172516
|
+
const byIdentity = new Map;
|
|
172517
|
+
for (const memory of memories) {
|
|
172518
|
+
if (memory.status === "permanent")
|
|
172519
|
+
continue;
|
|
172520
|
+
const identity = memoryCanonicalIdentity(memory, workspace);
|
|
172521
|
+
if (!identity)
|
|
172522
|
+
continue;
|
|
172523
|
+
const list = byIdentity.get(identity) ?? [];
|
|
172524
|
+
list.push(memory);
|
|
172525
|
+
byIdentity.set(identity, list);
|
|
172526
|
+
}
|
|
172527
|
+
for (const identity of workspace.identities) {
|
|
172528
|
+
let memberTokens = 0;
|
|
172529
|
+
const candidates = (byIdentity.get(identity) ?? []).sort(memorySelectionOrder);
|
|
172530
|
+
for (const memory of candidates) {
|
|
172531
|
+
if (selectedIds.has(memory.id))
|
|
172532
|
+
continue;
|
|
172533
|
+
const tokens = tokenCost(memory);
|
|
172534
|
+
if (memberTokens + tokens > floorTokens)
|
|
172535
|
+
continue;
|
|
172536
|
+
if (usedTokens + tokens > budgetTokens)
|
|
172537
|
+
continue;
|
|
172538
|
+
selected.push(memory);
|
|
172539
|
+
selectedIds.add(memory.id);
|
|
172540
|
+
usedTokens += tokens;
|
|
172541
|
+
memberTokens += tokens;
|
|
172542
|
+
}
|
|
172543
|
+
}
|
|
172544
|
+
const remaining = memories.filter((memory) => !selectedIds.has(memory.id)).sort(memorySelectionOrder);
|
|
172545
|
+
for (const memory of remaining) {
|
|
172546
|
+
trySelect(memory);
|
|
172547
|
+
}
|
|
172548
|
+
if (selected.length < memories.length) {
|
|
172549
|
+
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
172550
|
+
}
|
|
172551
|
+
return { selected, renderOrder: [...selected].sort(memoryRenderOrder) };
|
|
172552
|
+
}
|
|
171078
172553
|
function trimUserMemoriesToBudget(memories, budgetTokens) {
|
|
171079
172554
|
const selected = [];
|
|
171080
172555
|
let usedTokens = 0;
|
|
@@ -171087,15 +172562,16 @@ function trimUserMemoriesToBudget(memories, budgetTokens) {
|
|
|
171087
172562
|
}
|
|
171088
172563
|
return selected;
|
|
171089
172564
|
}
|
|
171090
|
-
function renderMemoryLineV2(memory) {
|
|
171091
|
-
|
|
172565
|
+
function renderMemoryLineV2(memory, sourceName) {
|
|
172566
|
+
const sourceAttr = sourceName ? ` source="${escapeXmlAttr(sourceName)}"` : "";
|
|
172567
|
+
return ` <memory id="${memory.id}" category="${escapeXmlAttr(memory.category)}"${sourceAttr} importance="${memory.importance ?? 50}">${escapeXmlContent(memory.content)}</memory>`;
|
|
171092
172568
|
}
|
|
171093
|
-
function renderMemoryBlockV2(memories, wrapper = "project-memory") {
|
|
172569
|
+
function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions = {}) {
|
|
171094
172570
|
if (memories.length === 0)
|
|
171095
172571
|
return "";
|
|
171096
172572
|
const lines = [`<${wrapper}>`];
|
|
171097
172573
|
for (const memory of memories) {
|
|
171098
|
-
lines.push(renderMemoryLineV2(memory));
|
|
172574
|
+
lines.push(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
171099
172575
|
}
|
|
171100
172576
|
lines.push(`</${wrapper}>`);
|
|
171101
172577
|
return lines.join(`
|
|
@@ -171689,7 +173165,7 @@ async function ensureMemoryEmbeddings(args) {
|
|
|
171689
173165
|
continue;
|
|
171690
173166
|
}
|
|
171691
173167
|
saveEmbedding(args.db, memory.id, embedding, result.modelId);
|
|
171692
|
-
staged.set(memory.id, embedding);
|
|
173168
|
+
staged.set(memory.id, { embedding, modelId: result.modelId });
|
|
171693
173169
|
}
|
|
171694
173170
|
})();
|
|
171695
173171
|
const currentSnapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -171780,6 +173256,37 @@ function previewText(text) {
|
|
|
171780
173256
|
}
|
|
171781
173257
|
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}…`;
|
|
171782
173258
|
}
|
|
173259
|
+
function resolveSearchWorkspaceContext(db, projectPath, identitySet) {
|
|
173260
|
+
const resolved = identitySet ?? resolveWorkspaceIdentitySet(db, projectPath);
|
|
173261
|
+
const isWorkspaced = resolved.identities.length > 1;
|
|
173262
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(db, resolved.identities);
|
|
173263
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : resolved.identities;
|
|
173264
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(resolved.identities.map((identity) => [identity, identity]));
|
|
173265
|
+
const ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === projectPath);
|
|
173266
|
+
return {
|
|
173267
|
+
identities: resolved.identities,
|
|
173268
|
+
expandedIdentities,
|
|
173269
|
+
ownIdentities,
|
|
173270
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(db, projectPath) : null,
|
|
173271
|
+
namesByIdentity: resolved.namesByIdentity,
|
|
173272
|
+
canonicalIdentityByStoredPath,
|
|
173273
|
+
isWorkspaced
|
|
173274
|
+
};
|
|
173275
|
+
}
|
|
173276
|
+
function memoryWorkspaceIdentity(memory, workspace) {
|
|
173277
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
173278
|
+
}
|
|
173279
|
+
function sourceNamesForSearchMemories(args) {
|
|
173280
|
+
if (!args.workspace.isWorkspaced)
|
|
173281
|
+
return;
|
|
173282
|
+
const sourceNames = new Map;
|
|
173283
|
+
for (const memory of args.memories) {
|
|
173284
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
173285
|
+
if (source)
|
|
173286
|
+
sourceNames.set(memory.id, source);
|
|
173287
|
+
}
|
|
173288
|
+
return sourceNames.size > 0 ? sourceNames : undefined;
|
|
173289
|
+
}
|
|
171783
173290
|
function getMessageSearchStatement(db) {
|
|
171784
173291
|
let stmt = messageSearchStatements.get(db);
|
|
171785
173292
|
if (!stmt) {
|
|
@@ -171788,6 +173295,30 @@ function getMessageSearchStatement(db) {
|
|
|
171788
173295
|
}
|
|
171789
173296
|
return stmt;
|
|
171790
173297
|
}
|
|
173298
|
+
var ftsRowCountStatements = new WeakMap;
|
|
173299
|
+
var ftsMatchCountStatements = new WeakMap;
|
|
173300
|
+
function getSessionFtsRowCount(db, sessionId) {
|
|
173301
|
+
let stmt = ftsRowCountStatements.get(db);
|
|
173302
|
+
if (!stmt) {
|
|
173303
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ?");
|
|
173304
|
+
ftsRowCountStatements.set(db, stmt);
|
|
173305
|
+
}
|
|
173306
|
+
const row = stmt.get(sessionId);
|
|
173307
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
173308
|
+
}
|
|
173309
|
+
function countSessionFtsMatches(db, sessionId, ftsQuery) {
|
|
173310
|
+
let stmt = ftsMatchCountStatements.get(db);
|
|
173311
|
+
if (!stmt) {
|
|
173312
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ?");
|
|
173313
|
+
ftsMatchCountStatements.set(db, stmt);
|
|
173314
|
+
}
|
|
173315
|
+
try {
|
|
173316
|
+
const row = stmt.get(sessionId, ftsQuery);
|
|
173317
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
173318
|
+
} catch {
|
|
173319
|
+
return 0;
|
|
173320
|
+
}
|
|
173321
|
+
}
|
|
171791
173322
|
function getMessageOrdinal(value) {
|
|
171792
173323
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
171793
173324
|
return value;
|
|
@@ -171803,25 +173334,63 @@ async function getSemanticScores(args) {
|
|
|
171803
173334
|
if (!args.queryEmbedding || args.memories.length === 0) {
|
|
171804
173335
|
return semanticScores;
|
|
171805
173336
|
}
|
|
171806
|
-
|
|
171807
|
-
|
|
171808
|
-
|
|
171809
|
-
|
|
171810
|
-
|
|
171811
|
-
|
|
171812
|
-
|
|
173337
|
+
if (!args.workspace?.isWorkspaced) {
|
|
173338
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
173339
|
+
const embeddings = await ensureMemoryEmbeddings({
|
|
173340
|
+
db: args.db,
|
|
173341
|
+
projectIdentity: args.projectPath,
|
|
173342
|
+
memories: args.memories,
|
|
173343
|
+
existingEmbeddings: cachedEmbeddings
|
|
173344
|
+
});
|
|
173345
|
+
for (const memory of args.memories) {
|
|
173346
|
+
const memoryEmbedding = embeddings.get(memory.id);
|
|
173347
|
+
if (!memoryEmbedding) {
|
|
173348
|
+
continue;
|
|
173349
|
+
}
|
|
173350
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
173351
|
+
}
|
|
173352
|
+
return semanticScores;
|
|
173353
|
+
}
|
|
173354
|
+
if (!args.queryModelId || args.queryModelId === "off") {
|
|
173355
|
+
return semanticScores;
|
|
173356
|
+
}
|
|
173357
|
+
const workspace = args.workspace;
|
|
173358
|
+
const memoriesByIdentity = new Map;
|
|
171813
173359
|
for (const memory of args.memories) {
|
|
171814
|
-
const
|
|
171815
|
-
if (!
|
|
173360
|
+
const identity = memoryWorkspaceIdentity(memory, workspace);
|
|
173361
|
+
if (!identity)
|
|
173362
|
+
continue;
|
|
173363
|
+
const list = memoriesByIdentity.get(identity) ?? [];
|
|
173364
|
+
list.push(memory);
|
|
173365
|
+
memoriesByIdentity.set(identity, list);
|
|
173366
|
+
}
|
|
173367
|
+
const ownMemories = memoriesByIdentity.get(args.projectPath) ?? [];
|
|
173368
|
+
if (ownMemories.length > 0) {
|
|
173369
|
+
const ownEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
173370
|
+
await ensureMemoryEmbeddings({
|
|
173371
|
+
db: args.db,
|
|
173372
|
+
projectIdentity: args.projectPath,
|
|
173373
|
+
memories: ownMemories,
|
|
173374
|
+
existingEmbeddings: ownEmbeddings
|
|
173375
|
+
});
|
|
173376
|
+
}
|
|
173377
|
+
for (const identity of workspace.identities) {
|
|
173378
|
+
const memberMemories = memoriesByIdentity.get(identity) ?? [];
|
|
173379
|
+
if (memberMemories.length === 0)
|
|
171816
173380
|
continue;
|
|
173381
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, identity);
|
|
173382
|
+
for (const memory of memberMemories) {
|
|
173383
|
+
const memoryEmbedding = cachedEmbeddings.get(memory.id);
|
|
173384
|
+
if (!memoryEmbedding || memoryEmbedding.modelId !== args.queryModelId)
|
|
173385
|
+
continue;
|
|
173386
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
171817
173387
|
}
|
|
171818
|
-
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
|
|
171819
173388
|
}
|
|
171820
173389
|
return semanticScores;
|
|
171821
173390
|
}
|
|
171822
173391
|
function getFtsMatches(args) {
|
|
171823
173392
|
try {
|
|
171824
|
-
return searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
173393
|
+
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);
|
|
171825
173394
|
} catch (error51) {
|
|
171826
173395
|
log(`[search] FTS query failed for "${args.query}": ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
171827
173396
|
return [];
|
|
@@ -171835,8 +173404,11 @@ function selectSemanticCandidates(args) {
|
|
|
171835
173404
|
return args.memories;
|
|
171836
173405
|
}
|
|
171837
173406
|
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
171838
|
-
const
|
|
171839
|
-
|
|
173407
|
+
const embeddingProjects = args.workspace?.isWorkspaced ? args.workspace.identities : [args.projectPath];
|
|
173408
|
+
for (const projectPath of embeddingProjects) {
|
|
173409
|
+
const cachedEmbeddings = peekProjectEmbeddings(projectPath);
|
|
173410
|
+
if (!cachedEmbeddings)
|
|
173411
|
+
continue;
|
|
171840
173412
|
for (const memoryId of cachedEmbeddings.keys()) {
|
|
171841
173413
|
candidateIds.add(memoryId);
|
|
171842
173414
|
}
|
|
@@ -171878,7 +173450,8 @@ function mergeMemoryResults(args) {
|
|
|
171878
173450
|
score,
|
|
171879
173451
|
memoryId: memory.id,
|
|
171880
173452
|
category: memory.category,
|
|
171881
|
-
matchType
|
|
173453
|
+
matchType,
|
|
173454
|
+
sourceName: args.sourceNameByMemoryId?.get(memory.id)
|
|
171882
173455
|
});
|
|
171883
173456
|
}
|
|
171884
173457
|
return results.sort((left, right) => {
|
|
@@ -171892,7 +173465,7 @@ async function searchMemories(args) {
|
|
|
171892
173465
|
if (!args.memoryEnabled) {
|
|
171893
173466
|
return [];
|
|
171894
173467
|
}
|
|
171895
|
-
const memories = getMemoriesByProject(args.db, args.projectPath);
|
|
173468
|
+
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);
|
|
171896
173469
|
if (memories.length === 0) {
|
|
171897
173470
|
return [];
|
|
171898
173471
|
}
|
|
@@ -171900,26 +173473,43 @@ async function searchMemories(args) {
|
|
|
171900
173473
|
db: args.db,
|
|
171901
173474
|
projectPath: args.projectPath,
|
|
171902
173475
|
query: args.query,
|
|
171903
|
-
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
173476
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT,
|
|
173477
|
+
workspace: args.workspace
|
|
171904
173478
|
});
|
|
171905
173479
|
const ftsScores = getFtsScores(ftsMatches);
|
|
171906
173480
|
const semanticCandidates = selectSemanticCandidates({
|
|
171907
173481
|
memories,
|
|
171908
173482
|
projectPath: args.projectPath,
|
|
171909
|
-
ftsMatches
|
|
173483
|
+
ftsMatches,
|
|
173484
|
+
workspace: args.workspace
|
|
171910
173485
|
});
|
|
171911
173486
|
const semanticScores = await getSemanticScores({
|
|
171912
173487
|
db: args.db,
|
|
171913
173488
|
projectPath: args.projectPath,
|
|
171914
173489
|
memories: semanticCandidates,
|
|
171915
|
-
queryEmbedding: args.queryEmbedding
|
|
173490
|
+
queryEmbedding: args.queryEmbedding,
|
|
173491
|
+
queryModelId: args.queryModelId,
|
|
173492
|
+
workspace: args.workspace
|
|
171916
173493
|
});
|
|
171917
173494
|
return mergeMemoryResults({
|
|
171918
173495
|
memories,
|
|
171919
173496
|
semanticScores,
|
|
171920
173497
|
ftsScores,
|
|
171921
173498
|
limit: args.limit,
|
|
171922
|
-
visibleMemoryIds: args.visibleMemoryIds
|
|
173499
|
+
visibleMemoryIds: args.visibleMemoryIds,
|
|
173500
|
+
sourceNameByMemoryId: sourceNamesForSearchMemories({
|
|
173501
|
+
memories,
|
|
173502
|
+
projectPath: args.projectPath,
|
|
173503
|
+
workspace: args.workspace ?? {
|
|
173504
|
+
identities: [args.projectPath],
|
|
173505
|
+
expandedIdentities: [args.projectPath],
|
|
173506
|
+
namesByIdentity: new Map,
|
|
173507
|
+
canonicalIdentityByStoredPath: new Map([[args.projectPath, args.projectPath]]),
|
|
173508
|
+
ownIdentities: [args.projectPath],
|
|
173509
|
+
shareCategories: null,
|
|
173510
|
+
isWorkspaced: false
|
|
173511
|
+
}
|
|
173512
|
+
})
|
|
171923
173513
|
});
|
|
171924
173514
|
}
|
|
171925
173515
|
function linearDecayScore(rank, total) {
|
|
@@ -171950,7 +173540,13 @@ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
|
|
|
171950
173540
|
return result;
|
|
171951
173541
|
}
|
|
171952
173542
|
var RRF_K = 60;
|
|
171953
|
-
var
|
|
173543
|
+
var VERBATIM_RANK_BONUS = 1 / RRF_K;
|
|
173544
|
+
var IDF_FALLOFF = 100;
|
|
173545
|
+
function probeDiscriminationWeight(df, corpusSize) {
|
|
173546
|
+
if (corpusSize <= 0 || df <= 0)
|
|
173547
|
+
return 1;
|
|
173548
|
+
return 1 / (1 + IDF_FALLOFF * df / corpusSize);
|
|
173549
|
+
}
|
|
171954
173550
|
function searchMessages(args) {
|
|
171955
173551
|
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
171956
173552
|
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
@@ -171967,20 +173563,31 @@ function searchMessages(args) {
|
|
|
171967
173563
|
role: row.role
|
|
171968
173564
|
}));
|
|
171969
173565
|
}
|
|
173566
|
+
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId);
|
|
171970
173567
|
const queryLists = [];
|
|
171971
173568
|
if (baseQuery.length > 0) {
|
|
171972
|
-
queryLists.push(
|
|
173569
|
+
queryLists.push({
|
|
173570
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff),
|
|
173571
|
+
weight: 1
|
|
173572
|
+
});
|
|
171973
173573
|
}
|
|
173574
|
+
const probeWeights = new Map;
|
|
171974
173575
|
for (const probe of probes) {
|
|
171975
173576
|
const probeQuery = sanitizeFtsQuery(probe);
|
|
171976
173577
|
if (probeQuery.length === 0)
|
|
171977
173578
|
continue;
|
|
171978
|
-
|
|
173579
|
+
const df = countSessionFtsMatches(args.db, args.sessionId, probeQuery);
|
|
173580
|
+
const weight = probeDiscriminationWeight(df, corpusSize);
|
|
173581
|
+
probeWeights.set(probe, weight);
|
|
173582
|
+
queryLists.push({
|
|
173583
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff),
|
|
173584
|
+
weight
|
|
173585
|
+
});
|
|
171979
173586
|
}
|
|
171980
173587
|
const fused = new Map;
|
|
171981
173588
|
for (const list of queryLists) {
|
|
171982
|
-
list.forEach((row, rank) => {
|
|
171983
|
-
const rrf =
|
|
173589
|
+
list.rows.forEach((row, rank) => {
|
|
173590
|
+
const rrf = list.weight / (RRF_K + rank);
|
|
171984
173591
|
const existing = fused.get(row.messageId);
|
|
171985
173592
|
if (existing) {
|
|
171986
173593
|
existing.score += rrf;
|
|
@@ -171990,26 +173597,107 @@ function searchMessages(args) {
|
|
|
171990
173597
|
});
|
|
171991
173598
|
}
|
|
171992
173599
|
for (const entry of fused.values()) {
|
|
171993
|
-
|
|
171994
|
-
|
|
173600
|
+
let best = 0;
|
|
173601
|
+
for (const probe of probes) {
|
|
173602
|
+
const weight = probeWeights.get(probe) ?? 0;
|
|
173603
|
+
if (weight > best && containsProbeVerbatim(entry.row.content, [probe])) {
|
|
173604
|
+
best = weight;
|
|
173605
|
+
}
|
|
173606
|
+
}
|
|
173607
|
+
if (best > 0) {
|
|
173608
|
+
entry.score += best * VERBATIM_RANK_BONUS;
|
|
171995
173609
|
}
|
|
171996
173610
|
}
|
|
171997
173611
|
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);
|
|
171998
|
-
|
|
171999
|
-
return ranked.map((entry) => ({
|
|
173612
|
+
return ranked.map((entry, rank) => ({
|
|
172000
173613
|
source: "message",
|
|
172001
173614
|
content: previewText(entry.row.content),
|
|
172002
|
-
score:
|
|
173615
|
+
score: linearDecayScore(rank, ranked.length),
|
|
172003
173616
|
messageOrdinal: entry.row.messageOrdinal,
|
|
172004
173617
|
messageId: entry.row.messageId,
|
|
172005
173618
|
role: entry.row.role
|
|
172006
173619
|
}));
|
|
172007
173620
|
}
|
|
173621
|
+
function searchCompartmentChunks(args) {
|
|
173622
|
+
if (!args.queryEmbedding || args.limit <= 0)
|
|
173623
|
+
return [];
|
|
173624
|
+
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
173625
|
+
const rows = loadCompartmentChunkEmbeddingsForSearch(args.db, args.sessionId, args.projectPath, args.modelId);
|
|
173626
|
+
if (rows.length === 0)
|
|
173627
|
+
return [];
|
|
173628
|
+
const byCompartment = new Map;
|
|
173629
|
+
for (const row of rows) {
|
|
173630
|
+
if (cutoff !== null && row.endOrdinal > cutoff) {
|
|
173631
|
+
continue;
|
|
173632
|
+
}
|
|
173633
|
+
const score = normalizeCosineScore(cosineSimilarity(args.queryEmbedding, row.vector));
|
|
173634
|
+
if (score <= 0)
|
|
173635
|
+
continue;
|
|
173636
|
+
const existing = byCompartment.get(row.compartmentId);
|
|
173637
|
+
if (!existing || score > existing.score) {
|
|
173638
|
+
byCompartment.set(row.compartmentId, { row, score });
|
|
173639
|
+
}
|
|
173640
|
+
}
|
|
173641
|
+
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 }) => ({
|
|
173642
|
+
source: "compartment",
|
|
173643
|
+
content: previewText(row.title),
|
|
173644
|
+
score: score * SINGLE_SOURCE_PENALTY,
|
|
173645
|
+
compartmentId: row.compartmentId,
|
|
173646
|
+
sessionId: row.sessionId,
|
|
173647
|
+
title: row.title,
|
|
173648
|
+
startOrdinal: row.startOrdinal,
|
|
173649
|
+
endOrdinal: row.endOrdinal,
|
|
173650
|
+
matchType: "semantic"
|
|
173651
|
+
}));
|
|
173652
|
+
}
|
|
173653
|
+
function mergeMessageAndCompartmentResults(args) {
|
|
173654
|
+
if (args.compartments.length === 0)
|
|
173655
|
+
return args.messages;
|
|
173656
|
+
if (args.messages.length === 0)
|
|
173657
|
+
return args.compartments;
|
|
173658
|
+
const fused = new Map;
|
|
173659
|
+
const add = (key, result, score, tieOrdinal) => {
|
|
173660
|
+
const existing = fused.get(key);
|
|
173661
|
+
if (existing) {
|
|
173662
|
+
existing.score += score;
|
|
173663
|
+
return existing;
|
|
173664
|
+
}
|
|
173665
|
+
const entry = { result, score, tieOrdinal, snippetScore: -1 };
|
|
173666
|
+
fused.set(key, entry);
|
|
173667
|
+
return entry;
|
|
173668
|
+
};
|
|
173669
|
+
args.compartments.forEach((compartment, rank) => {
|
|
173670
|
+
add(`compartment:${compartment.compartmentId}`, compartment, 1 / (RRF_K + rank), compartment.startOrdinal);
|
|
173671
|
+
});
|
|
173672
|
+
for (const [rank, message] of args.messages.entries()) {
|
|
173673
|
+
const containing = args.compartments.find((compartment) => message.messageOrdinal >= compartment.startOrdinal && message.messageOrdinal <= compartment.endOrdinal);
|
|
173674
|
+
const contribution = 1 / (RRF_K + rank);
|
|
173675
|
+
if (!containing) {
|
|
173676
|
+
add(`message:${message.messageId}`, message, contribution, message.messageOrdinal);
|
|
173677
|
+
continue;
|
|
173678
|
+
}
|
|
173679
|
+
const entry = add(`compartment:${containing.compartmentId}`, containing, contribution, containing.startOrdinal);
|
|
173680
|
+
if (message.score > entry.snippetScore && entry.result.source === "compartment") {
|
|
173681
|
+
entry.snippetScore = message.score;
|
|
173682
|
+
entry.result = {
|
|
173683
|
+
...entry.result,
|
|
173684
|
+
matchType: "hybrid",
|
|
173685
|
+
snippet: message.content
|
|
173686
|
+
};
|
|
173687
|
+
}
|
|
173688
|
+
}
|
|
173689
|
+
const ranked = [...fused.values()].sort((left, right) => right.score !== left.score ? right.score - left.score : left.tieOrdinal - right.tieOrdinal).slice(0, args.limit);
|
|
173690
|
+
return ranked.map((entry, rank) => ({
|
|
173691
|
+
...entry.result,
|
|
173692
|
+
score: linearDecayScore(rank, ranked.length)
|
|
173693
|
+
}));
|
|
173694
|
+
}
|
|
172008
173695
|
function getSourceBoost(result) {
|
|
172009
173696
|
switch (result.source) {
|
|
172010
173697
|
case "memory":
|
|
172011
173698
|
return MEMORY_SOURCE_BOOST;
|
|
172012
173699
|
case "message":
|
|
173700
|
+
case "compartment":
|
|
172013
173701
|
return MESSAGE_SOURCE_BOOST;
|
|
172014
173702
|
case "git_commit":
|
|
172015
173703
|
return GIT_COMMIT_SOURCE_BOOST;
|
|
@@ -172027,6 +173715,9 @@ function compareUnifiedResults(left, right) {
|
|
|
172027
173715
|
if (left.source === "message" && right.source === "message") {
|
|
172028
173716
|
return left.messageOrdinal - right.messageOrdinal;
|
|
172029
173717
|
}
|
|
173718
|
+
if (left.source === "compartment" && right.source === "compartment") {
|
|
173719
|
+
return left.startOrdinal - right.startOrdinal;
|
|
173720
|
+
}
|
|
172030
173721
|
if (left.source === "git_commit" && right.source === "git_commit") {
|
|
172031
173722
|
return right.committedAtMs - left.committedAtMs;
|
|
172032
173723
|
}
|
|
@@ -172077,10 +173768,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172077
173768
|
const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
|
|
172078
173769
|
const gitCommitsEnabled = options.gitCommitsEnabled ?? false;
|
|
172079
173770
|
const activeSources = resolveSources(options.sources);
|
|
172080
|
-
const
|
|
173771
|
+
const memoryFeatureEnabled = options.memoryEnabled ?? true;
|
|
173772
|
+
const runMemory = activeSources.has("memory") && memoryFeatureEnabled;
|
|
172081
173773
|
const runMessages = activeSources.has("message");
|
|
172082
173774
|
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
172083
|
-
const
|
|
173775
|
+
const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
|
|
173776
|
+
const needsEmbedding = (runMemory || runGitCommits || runCompartmentChunks) && embeddingEnabled && isEmbeddingRuntimeEnabled();
|
|
172084
173777
|
const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error51) => {
|
|
172085
173778
|
log(`[search] query embedding failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
172086
173779
|
return null;
|
|
@@ -172096,6 +173789,24 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172096
173789
|
probes: messageProbes
|
|
172097
173790
|
}) : [];
|
|
172098
173791
|
const queryEmbedding = await queryEmbeddingPromise;
|
|
173792
|
+
const workspace = resolveSearchWorkspaceContext(db, projectPath);
|
|
173793
|
+
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
173794
|
+
const embeddingModelId = embeddingSnapshot?.modelId;
|
|
173795
|
+
const chunkModelId = embeddingSnapshot?.chunkModelId;
|
|
173796
|
+
const compartmentResults = runCompartmentChunks ? searchCompartmentChunks({
|
|
173797
|
+
db,
|
|
173798
|
+
sessionId,
|
|
173799
|
+
projectPath,
|
|
173800
|
+
queryEmbedding,
|
|
173801
|
+
limit: tierLimit,
|
|
173802
|
+
maxOrdinal: options.maxMessageOrdinal,
|
|
173803
|
+
modelId: chunkModelId && chunkModelId !== "off" ? chunkModelId : null
|
|
173804
|
+
}) : [];
|
|
173805
|
+
const messageLikeResults = mergeMessageAndCompartmentResults({
|
|
173806
|
+
messages: messageResults,
|
|
173807
|
+
compartments: compartmentResults,
|
|
173808
|
+
limit: tierLimit
|
|
173809
|
+
});
|
|
172099
173810
|
const [memoryResults, gitCommitResults] = await Promise.all([
|
|
172100
173811
|
runMemory ? searchMemories({
|
|
172101
173812
|
db,
|
|
@@ -172104,6 +173815,8 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172104
173815
|
limit: tierLimit,
|
|
172105
173816
|
memoryEnabled: true,
|
|
172106
173817
|
queryEmbedding,
|
|
173818
|
+
queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null,
|
|
173819
|
+
workspace,
|
|
172107
173820
|
visibleMemoryIds: options.visibleMemoryIds
|
|
172108
173821
|
}) : Promise.resolve([]),
|
|
172109
173822
|
runGitCommits ? Promise.resolve(searchGitCommits({
|
|
@@ -172114,7 +173827,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172114
173827
|
queryEmbedding
|
|
172115
173828
|
})) : Promise.resolve([])
|
|
172116
173829
|
]);
|
|
172117
|
-
const results = [...memoryResults, ...
|
|
173830
|
+
const results = [...memoryResults, ...messageLikeResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
|
|
172118
173831
|
const countRetrievals = options.countRetrievals ?? true;
|
|
172119
173832
|
if (countRetrievals) {
|
|
172120
173833
|
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
@@ -172174,6 +173887,11 @@ function renderFragment(result, charCap) {
|
|
|
172174
173887
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
172175
173888
|
return truncate(compressed, charCap);
|
|
172176
173889
|
}
|
|
173890
|
+
case "compartment": {
|
|
173891
|
+
const source = result.snippet ?? result.title;
|
|
173892
|
+
const compressed = cavemanCompress(source, "ultra");
|
|
173893
|
+
return truncate(compressed, charCap);
|
|
173894
|
+
}
|
|
172177
173895
|
}
|
|
172178
173896
|
}
|
|
172179
173897
|
function buildAutoSearchHint(results, options = {}) {
|
|
@@ -173597,9 +175315,51 @@ function safeGetActiveUserMemoriesPi(db) {
|
|
|
173597
175315
|
function memoryProjectPath(state) {
|
|
173598
175316
|
return state.memoryEnabled === false ? undefined : state.projectIdentity;
|
|
173599
175317
|
}
|
|
175318
|
+
function resolveWorkspaceRenderContextPi(state, db) {
|
|
175319
|
+
const memPath = memoryProjectPath(state);
|
|
175320
|
+
if (!memPath) {
|
|
175321
|
+
return {
|
|
175322
|
+
identities: [],
|
|
175323
|
+
expandedIdentities: [],
|
|
175324
|
+
ownIdentities: [],
|
|
175325
|
+
shareCategories: null,
|
|
175326
|
+
namesByIdentity: new Map,
|
|
175327
|
+
canonicalIdentityByStoredPath: new Map,
|
|
175328
|
+
isWorkspaced: false
|
|
175329
|
+
};
|
|
175330
|
+
}
|
|
175331
|
+
const identitySet = resolveWorkspaceIdentitySet(db, memPath);
|
|
175332
|
+
const isWorkspaced = identitySet.identities.length > 1;
|
|
175333
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(db, identitySet.identities);
|
|
175334
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : identitySet.identities;
|
|
175335
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(identitySet.identities.map((identity) => [identity, identity]));
|
|
175336
|
+
let ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === memPath);
|
|
175337
|
+
if (ownIdentities.length === 0 && expandedIdentities.includes(memPath)) {
|
|
175338
|
+
ownIdentities = [memPath];
|
|
175339
|
+
}
|
|
175340
|
+
return {
|
|
175341
|
+
identities: identitySet.identities,
|
|
175342
|
+
expandedIdentities,
|
|
175343
|
+
ownIdentities,
|
|
175344
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(db, memPath) : null,
|
|
175345
|
+
namesByIdentity: identitySet.namesByIdentity,
|
|
175346
|
+
canonicalIdentityByStoredPath,
|
|
175347
|
+
isWorkspaced
|
|
175348
|
+
};
|
|
175349
|
+
}
|
|
175350
|
+
function sourceNamesForPiMemories(args) {
|
|
175351
|
+
if (!args.projectPath || !args.workspace.isWorkspaced)
|
|
175352
|
+
return;
|
|
175353
|
+
const names = new Map;
|
|
175354
|
+
for (const memory of args.memories) {
|
|
175355
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
175356
|
+
if (source)
|
|
175357
|
+
names.set(memory.id, source);
|
|
175358
|
+
}
|
|
175359
|
+
return names.size > 0 ? names : undefined;
|
|
175360
|
+
}
|
|
173600
175361
|
var EMPTY_PI_HARD_SIGNALS = {
|
|
173601
175362
|
systemHash: "",
|
|
173602
|
-
toolSetHash: "",
|
|
173603
175363
|
modelKey: "",
|
|
173604
175364
|
cacheExpired: false,
|
|
173605
175365
|
lastResponseTime: 0
|
|
@@ -173645,6 +175405,7 @@ function getCachedMarkers(db, state, compartmentsForNormalization) {
|
|
|
173645
175405
|
maxMutationId: meta3.cachedM0MaxMutationId,
|
|
173646
175406
|
maxMemoryMutationId: meta3.cachedM0MaxMemoryMutationId,
|
|
173647
175407
|
projectMemoryEpoch: meta3.cachedM0ProjectMemoryEpoch,
|
|
175408
|
+
workspaceFingerprint: meta3.cachedM0WorkspaceFingerprint,
|
|
173648
175409
|
projectUserProfileVersion: meta3.cachedM0ProjectUserProfileVersion,
|
|
173649
175410
|
projectDocsHash: meta3.cachedM0ProjectDocsHash,
|
|
173650
175411
|
sessionFactsVersion: meta3.cachedM0SessionFactsVersion,
|
|
@@ -173652,7 +175413,6 @@ function getCachedMarkers(db, state, compartmentsForNormalization) {
|
|
|
173652
175413
|
upgradeState: meta3.cachedM0UpgradeState,
|
|
173653
175414
|
lastBaselineEndMessageId: cachedBoundary,
|
|
173654
175415
|
systemHash: meta3.cachedM0SystemHash ?? "",
|
|
173655
|
-
toolSetHash: meta3.cachedM0ToolSetHash ?? "",
|
|
173656
175416
|
modelKey: meta3.cachedM0ModelKey ?? ""
|
|
173657
175417
|
};
|
|
173658
175418
|
}
|
|
@@ -173665,15 +175425,17 @@ function readCurrentMarkers(db, state, projectDocsHash) {
|
|
|
173665
175425
|
}
|
|
173666
175426
|
function readCurrentMarkersFromCompartments(db, state, compartments, projectDocsHash) {
|
|
173667
175427
|
const memPath = memoryProjectPath(state);
|
|
173668
|
-
const
|
|
175428
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
175429
|
+
const maxMemoryId = memPath ? workspace.isWorkspaced ? getMaxMemoryIdForProjects(db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryIdForProjects(db, [memPath]) : 0;
|
|
173669
175430
|
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
173670
175431
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
173671
175432
|
return {
|
|
173672
175433
|
maxCompartmentSeq: compartments.length > 0 ? compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ) : EMPTY_MAX_COMPARTMENT_SEQ,
|
|
173673
|
-
maxMemoryId
|
|
175434
|
+
maxMemoryId,
|
|
173674
175435
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
173675
|
-
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
175436
|
+
maxMemoryMutationId: memPath ? workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(db, workspace.expandedIdentities) ?? 0 : getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
173676
175437
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
175438
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(db, workspace.identities) : null,
|
|
173677
175439
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
173678
175440
|
projectDocsHash: projectDocsHash ?? readProjectDocsCanonical(state.projectDirectory).canonicalHash,
|
|
173679
175441
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
@@ -173681,7 +175443,6 @@ function readCurrentMarkersFromCompartments(db, state, compartments, projectDocs
|
|
|
173681
175443
|
upgradeState: `${PI_M0_UPGRADE_STATE}:${compartments.some((c) => c.legacy === 1) ? "legacy" : "ready"}`,
|
|
173682
175444
|
lastBaselineEndMessageId: lastBaselineEndMessageId(compartments),
|
|
173683
175445
|
systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
|
|
173684
|
-
toolSetHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).toolSetHash,
|
|
173685
175446
|
modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey
|
|
173686
175447
|
};
|
|
173687
175448
|
}
|
|
@@ -173706,19 +175467,17 @@ function mustMaterializePi(state, db, currentCompartmentsOverride) {
|
|
|
173706
175467
|
if (hard.systemHash !== "" && hard.systemHash !== (meta3.cachedM0SystemHash ?? "")) {
|
|
173707
175468
|
return { value: true, reason: "system_hash" };
|
|
173708
175469
|
}
|
|
173709
|
-
if (hard.toolSetHash !== "" && hard.toolSetHash !== (meta3.cachedM0ToolSetHash ?? "")) {
|
|
173710
|
-
return { value: true, reason: "tool_set_hash" };
|
|
173711
|
-
}
|
|
173712
175470
|
if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (meta3.cachedM0MaterializedAt ?? 0)) {
|
|
173713
175471
|
return { value: true, reason: "ttl_idle" };
|
|
173714
175472
|
}
|
|
173715
175473
|
if (meta3.cachedM0UpgradeState !== current.upgradeState) {
|
|
173716
175474
|
return { value: true, reason: "renderer_upgrade" };
|
|
173717
175475
|
}
|
|
173718
|
-
if (current.
|
|
173719
|
-
|
|
173720
|
-
|
|
173721
|
-
|
|
175476
|
+
if (current.workspaceFingerprint !== null || (meta3.cachedM0WorkspaceFingerprint ?? null) !== null) {
|
|
175477
|
+
if (current.workspaceFingerprint !== (meta3.cachedM0WorkspaceFingerprint ?? null)) {
|
|
175478
|
+
return { value: true, reason: "project_memory_change" };
|
|
175479
|
+
}
|
|
175480
|
+
} else if (current.projectMemoryEpoch !== (meta3.cachedM0ProjectMemoryEpoch ?? 0)) {
|
|
173722
175481
|
return { value: true, reason: "project_memory_change" };
|
|
173723
175482
|
}
|
|
173724
175483
|
if (current.maxMutationId !== (meta3.cachedM0MaxMutationId ?? 0)) {
|
|
@@ -173735,11 +175494,19 @@ ${memories.map((memory) => `- ${escapeXmlContent(memory.content)}`).join(`
|
|
|
173735
175494
|
`)}
|
|
173736
175495
|
</${wrapper}>`;
|
|
173737
175496
|
}
|
|
173738
|
-
function renderM0Pi(state, db, projectDocs = readProjectDocsCanonical(state.projectDirectory).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride) {
|
|
175497
|
+
function renderM0Pi(state, db, projectDocs = readProjectDocsCanonical(state.projectDirectory).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride, workspaceOverride) {
|
|
173739
175498
|
const memPath = memoryProjectPath(state);
|
|
173740
|
-
const
|
|
173741
|
-
const
|
|
173742
|
-
const
|
|
175499
|
+
const workspace = workspaceOverride ?? resolveWorkspaceRenderContextPi(state, db);
|
|
175500
|
+
const allMemories = memoriesOverride ?? (memPath ? workspace.isWorkspaced ? getMemoriesByProjects(db, workspace.expandedIdentities, ["active", "permanent"], Date.now(), workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(db, memPath, ["active", "permanent"]) : []);
|
|
175501
|
+
const memoryRenderOptions = {
|
|
175502
|
+
sourceNameByMemoryId: sourceNamesForPiMemories({
|
|
175503
|
+
memories: allMemories,
|
|
175504
|
+
projectPath: memPath,
|
|
175505
|
+
workspace
|
|
175506
|
+
})
|
|
175507
|
+
};
|
|
175508
|
+
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;
|
|
175509
|
+
const memoryBlock = memories.length > 0 ? renderMemoryBlockV2(memories, "project-memory", memoryRenderOptions) : undefined;
|
|
173743
175510
|
const baseHistoryBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173744
175511
|
const decayed = renderDecayedCompartments({
|
|
173745
175512
|
compartments: compartmentsOverride ?? getCompartments(db, state.sessionId),
|
|
@@ -173761,10 +175528,19 @@ ${decayed}
|
|
|
173761
175528
|
|
|
173762
175529
|
`).trim();
|
|
173763
175530
|
}
|
|
173764
|
-
function renderedMemoryIdsForPi(state, memories) {
|
|
175531
|
+
function renderedMemoryIdsForPi(state, memories, workspace, db) {
|
|
173765
175532
|
if (memories.length === 0)
|
|
173766
175533
|
return [];
|
|
173767
|
-
|
|
175534
|
+
const resolvedWorkspace = workspace ?? (db ? resolveWorkspaceRenderContextPi(state, db) : undefined);
|
|
175535
|
+
const renderOptions = resolvedWorkspace ? {
|
|
175536
|
+
sourceNameByMemoryId: sourceNamesForPiMemories({
|
|
175537
|
+
memories,
|
|
175538
|
+
projectPath: memoryProjectPath(state),
|
|
175539
|
+
workspace: resolvedWorkspace
|
|
175540
|
+
})
|
|
175541
|
+
} : {};
|
|
175542
|
+
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);
|
|
175543
|
+
return trimmed.renderOrder.map((memory) => memory.id);
|
|
173768
175544
|
}
|
|
173769
175545
|
function isTransientSqliteLockError(error51) {
|
|
173770
175546
|
if (!error51 || typeof error51 !== "object")
|
|
@@ -173789,17 +175565,19 @@ class PiMaterializeContentionError extends Error {
|
|
|
173789
175565
|
function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.projectDirectory), memoryCutoff) {
|
|
173790
175566
|
const memPath = memoryProjectPath(state);
|
|
173791
175567
|
const read = db.transaction(() => {
|
|
175568
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
173792
175569
|
const compartments = getCompartments(db, state.sessionId);
|
|
173793
|
-
const memories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], memoryCutoff) : [];
|
|
175570
|
+
const memories = memPath ? workspace.isWorkspaced ? getMemoriesByProjects(db, workspace.expandedIdentities, ["active", "permanent"], memoryCutoff, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(db, memPath, ["active", "permanent"], memoryCutoff) : [];
|
|
173794
175571
|
const userProfile = safeGetActiveUserMemoriesPi(db);
|
|
173795
175572
|
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
173796
175573
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
173797
175574
|
const markers = {
|
|
173798
175575
|
maxCompartmentSeq: compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ),
|
|
173799
|
-
maxMemoryId:
|
|
175576
|
+
maxMemoryId: memPath ? workspace.isWorkspaced ? getMaxMemoryIdForProjects(db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryIdForProjects(db, [memPath]) : 0,
|
|
173800
175577
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
173801
|
-
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
175578
|
+
maxMemoryMutationId: memPath ? workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(db, workspace.expandedIdentities) ?? 0 : getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
173802
175579
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
175580
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(db, workspace.identities) : null,
|
|
173803
175581
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
173804
175582
|
projectDocsHash: docs.canonicalHash,
|
|
173805
175583
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
@@ -173807,10 +175585,9 @@ function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.p
|
|
|
173807
175585
|
upgradeState: `${PI_M0_UPGRADE_STATE}:${compartments.some((c) => c.legacy === 1) ? "legacy" : "ready"}`,
|
|
173808
175586
|
lastBaselineEndMessageId: lastBaselineEndMessageId(compartments),
|
|
173809
175587
|
systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
|
|
173810
|
-
toolSetHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).toolSetHash,
|
|
173811
175588
|
modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey
|
|
173812
175589
|
};
|
|
173813
|
-
return { docs, markers, compartments, memories, userProfile };
|
|
175590
|
+
return { docs, markers, compartments, memories, userProfile, workspace };
|
|
173814
175591
|
});
|
|
173815
175592
|
return read();
|
|
173816
175593
|
}
|
|
@@ -173821,17 +175598,17 @@ function renderFreshM0PiNonPersisted(state, db) {
|
|
|
173821
175598
|
frozen.markers.materializedAt = cachedMaterializedAt;
|
|
173822
175599
|
const historyBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173823
175600
|
let dpm = 1;
|
|
173824
|
-
let m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile);
|
|
175601
|
+
let m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile, frozen.workspace);
|
|
173825
175602
|
let attempts = 0;
|
|
173826
175603
|
while (historyBudget > 0 && historySliceTokensPi(m0) > historyBudget * 1.05 && attempts < 3) {
|
|
173827
175604
|
dpm *= 1.15;
|
|
173828
|
-
m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile);
|
|
175605
|
+
m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile, frozen.workspace);
|
|
173829
175606
|
attempts += 1;
|
|
173830
175607
|
}
|
|
173831
175608
|
return {
|
|
173832
175609
|
m0,
|
|
173833
175610
|
snapshotMarkers: frozen.markers,
|
|
173834
|
-
renderedMemoryIds: renderedMemoryIdsForPi(state, frozen.memories)
|
|
175611
|
+
renderedMemoryIds: renderedMemoryIdsForPi(state, frozen.memories, frozen.workspace, db)
|
|
173835
175612
|
};
|
|
173836
175613
|
}
|
|
173837
175614
|
function materializeM0Pi(state, db) {
|
|
@@ -173841,14 +175618,14 @@ function materializeM0Pi(state, db) {
|
|
|
173841
175618
|
const snapshotMemories = frozen.memories;
|
|
173842
175619
|
const snapshotCompartments = frozen.compartments;
|
|
173843
175620
|
const snapshotUserProfile = frozen.userProfile;
|
|
173844
|
-
const renderedMemoryIds = renderedMemoryIdsForPi(state, snapshotMemories);
|
|
175621
|
+
const renderedMemoryIds = renderedMemoryIdsForPi(state, snapshotMemories, frozen.workspace, db);
|
|
173845
175622
|
let decayPressureMultiplier = 1;
|
|
173846
|
-
let m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile);
|
|
175623
|
+
let m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile, frozen.workspace);
|
|
173847
175624
|
const historyBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173848
175625
|
let attempts = 0;
|
|
173849
175626
|
while (historyBudget > 0 && historySliceTokensPi(m0) > historyBudget * 1.05 && attempts < 3) {
|
|
173850
175627
|
decayPressureMultiplier *= 1.15;
|
|
173851
|
-
m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile);
|
|
175628
|
+
m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile, frozen.workspace);
|
|
173852
175629
|
attempts += 1;
|
|
173853
175630
|
}
|
|
173854
175631
|
const m0Bytes = Buffer.from(m0, "utf8");
|
|
@@ -173864,7 +175641,8 @@ function materializeM0Pi(state, db) {
|
|
|
173864
175641
|
}
|
|
173865
175642
|
try {
|
|
173866
175643
|
const current = readCurrentMarkers(db, state, phase3ProjectDocsHash);
|
|
173867
|
-
const
|
|
175644
|
+
const memoryEpochStale = current.workspaceFingerprint !== null || snapshotMarkers.workspaceFingerprint !== null ? current.workspaceFingerprint !== snapshotMarkers.workspaceFingerprint : current.projectMemoryEpoch !== snapshotMarkers.projectMemoryEpoch;
|
|
175645
|
+
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;
|
|
173868
175646
|
if (stale) {
|
|
173869
175647
|
db.exec("ROLLBACK");
|
|
173870
175648
|
throw new PiMaterializeContentionError("snapshot changed before persist");
|
|
@@ -173875,6 +175653,7 @@ function materializeM0Pi(state, db) {
|
|
|
173875
175653
|
persistCachedM0(db, state.sessionId, {
|
|
173876
175654
|
m0Bytes,
|
|
173877
175655
|
projectMemoryEpoch: snapshotMarkers.projectMemoryEpoch,
|
|
175656
|
+
workspaceFingerprint: snapshotMarkers.workspaceFingerprint,
|
|
173878
175657
|
projectUserProfileVersion: snapshotMarkers.projectUserProfileVersion,
|
|
173879
175658
|
maxCompartmentSeq: snapshotMarkers.maxCompartmentSeq,
|
|
173880
175659
|
maxMemoryId: snapshotMarkers.maxMemoryId,
|
|
@@ -173886,7 +175665,6 @@ function materializeM0Pi(state, db) {
|
|
|
173886
175665
|
sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
|
|
173887
175666
|
upgradeState: snapshotMarkers.upgradeState,
|
|
173888
175667
|
systemHash: snapshotMarkers.systemHash,
|
|
173889
|
-
toolSetHash: snapshotMarkers.toolSetHash,
|
|
173890
175668
|
modelKey: snapshotMarkers.modelKey
|
|
173891
175669
|
});
|
|
173892
175670
|
db.prepare("UPDATE session_meta SET memory_block_count = ?, memory_block_ids = ? WHERE session_id = ?").run(renderedMemoryIds.length, JSON.stringify(renderedMemoryIds), state.sessionId);
|
|
@@ -173940,7 +175718,7 @@ function renderMemoryUpdatesBlockPi(args) {
|
|
|
173940
175718
|
if (args.renderedMemoryIds.length === 0)
|
|
173941
175719
|
return { block: "", count: 0 };
|
|
173942
175720
|
const renderedIds = new Set(args.renderedMemoryIds);
|
|
173943
|
-
const mutations = getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
175721
|
+
const mutations = args.workspace.isWorkspaced ? getMemoryMutationsForRenderByProjects(args.db, args.workspace.expandedIdentities, args.afterId, args.renderedMemoryIds) : getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
173944
175722
|
if (mutations.length === 0)
|
|
173945
175723
|
return { block: "", count: 0 };
|
|
173946
175724
|
const lines = [
|
|
@@ -173971,6 +175749,7 @@ ${lines.join(`
|
|
|
173971
175749
|
}
|
|
173972
175750
|
function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRenderedKeyFilesBlock, compartmentsOverride) {
|
|
173973
175751
|
const sections = [];
|
|
175752
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
173974
175753
|
const keyFiles = renderedKeyFilesBlockPi(state, db, preRenderedKeyFilesBlock);
|
|
173975
175754
|
if (keyFiles)
|
|
173976
175755
|
sections.push(keyFiles);
|
|
@@ -173978,6 +175757,7 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
|
|
|
173978
175757
|
const memoryUpdates = memPath ? renderMemoryUpdatesBlockPi({
|
|
173979
175758
|
db,
|
|
173980
175759
|
projectPath: memPath,
|
|
175760
|
+
workspace,
|
|
173981
175761
|
afterId: markers.maxMemoryMutationId,
|
|
173982
175762
|
renderedMemoryIds
|
|
173983
175763
|
}) : { block: undefined, count: 0 };
|
|
@@ -173992,11 +175772,18 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
|
|
|
173992
175772
|
${body}
|
|
173993
175773
|
</new-compartments>`);
|
|
173994
175774
|
}
|
|
173995
|
-
const newMemories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], markers.materializedAt).filter((memory) => memory.id > markers.maxMemoryId) : [];
|
|
175775
|
+
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) : [];
|
|
173996
175776
|
if (newMemories.length > 0) {
|
|
173997
175777
|
const memoryBudget = state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
173998
|
-
const
|
|
173999
|
-
|
|
175778
|
+
const memoryRenderOptions = {
|
|
175779
|
+
sourceNameByMemoryId: sourceNamesForPiMemories({
|
|
175780
|
+
memories: newMemories,
|
|
175781
|
+
projectPath: memPath,
|
|
175782
|
+
workspace
|
|
175783
|
+
})
|
|
175784
|
+
};
|
|
175785
|
+
const trimmedNewMemories = trimMemoriesToBudgetV2(state.sessionId, newMemories, Math.max(1, Math.floor(memoryBudget * 0.25)), memoryRenderOptions).renderOrder;
|
|
175786
|
+
const newMemoriesBlock = renderMemoryBlockV2(trimmedNewMemories, "new-memories", memoryRenderOptions);
|
|
174000
175787
|
if (newMemoriesBlock)
|
|
174001
175788
|
sections.push(newMemoriesBlock);
|
|
174002
175789
|
}
|
|
@@ -174045,6 +175832,7 @@ function parseMemoryBlockIds(raw) {
|
|
|
174045
175832
|
function readCachedPiM0M1Row(db, sessionId) {
|
|
174046
175833
|
return db.prepare(`SELECT cached_m0_bytes, cached_m1_bytes,
|
|
174047
175834
|
cached_m0_project_memory_epoch,
|
|
175835
|
+
cached_m0_workspace_fingerprint,
|
|
174048
175836
|
cached_m0_project_user_profile_version,
|
|
174049
175837
|
cached_m0_max_compartment_seq,
|
|
174050
175838
|
cached_m0_max_memory_id,
|
|
@@ -174055,7 +175843,6 @@ function readCachedPiM0M1Row(db, sessionId) {
|
|
|
174055
175843
|
cached_m0_session_facts_version,
|
|
174056
175844
|
cached_m0_upgrade_state,
|
|
174057
175845
|
cached_m0_system_hash,
|
|
174058
|
-
cached_m0_tool_set_hash,
|
|
174059
175846
|
cached_m0_model_key,
|
|
174060
175847
|
cached_m0_last_baseline_end_message_id,
|
|
174061
175848
|
memory_block_ids
|
|
@@ -174089,6 +175876,7 @@ function markersFromCachedPiRow(row, compartmentsForNormalization) {
|
|
|
174089
175876
|
maxMutationId: row.cached_m0_max_mutation_id,
|
|
174090
175877
|
maxMemoryMutationId: row.cached_m0_max_memory_mutation_id,
|
|
174091
175878
|
projectMemoryEpoch: row.cached_m0_project_memory_epoch,
|
|
175879
|
+
workspaceFingerprint: row.cached_m0_workspace_fingerprint,
|
|
174092
175880
|
projectUserProfileVersion: row.cached_m0_project_user_profile_version,
|
|
174093
175881
|
projectDocsHash: row.cached_m0_project_docs_hash ?? "",
|
|
174094
175882
|
materializedAt: row.cached_m0_materialized_at,
|
|
@@ -174096,7 +175884,6 @@ function markersFromCachedPiRow(row, compartmentsForNormalization) {
|
|
|
174096
175884
|
upgradeState: row.cached_m0_upgrade_state,
|
|
174097
175885
|
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,
|
|
174098
175886
|
systemHash: row.cached_m0_system_hash ?? "",
|
|
174099
|
-
toolSetHash: row.cached_m0_tool_set_hash ?? "",
|
|
174100
175887
|
modelKey: row.cached_m0_model_key ?? ""
|
|
174101
175888
|
};
|
|
174102
175889
|
}
|
|
@@ -174104,7 +175891,7 @@ function cachedPiRowMatchesSnapshot(args) {
|
|
|
174104
175891
|
const rowMarkers = markersFromCachedPiRow(args.row, args.compartmentsForNormalization);
|
|
174105
175892
|
if (!rowMarkers)
|
|
174106
175893
|
return false;
|
|
174107
|
-
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 &&
|
|
175894
|
+
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);
|
|
174108
175895
|
}
|
|
174109
175896
|
function decodeCachedM1(row, sessionId) {
|
|
174110
175897
|
if (!row.cached_m1_bytes) {
|
|
@@ -174315,14 +176102,14 @@ function injectM0M1Pi(state, db, piMessages, entryIds, recomputeM1ThisPass = fal
|
|
|
174315
176102
|
const skippedVisibleMessages = boundaryId ? trimPiMessagesToBoundary(piMessages, entryIds, boundaryId) : 0;
|
|
174316
176103
|
prependM0M1Messages(piMessages, m0, m1);
|
|
174317
176104
|
sessionLog(state.sessionId, `injected m[0]/m[1] into Pi messages (${m0.length} + ${m1.length} bytes, materialized=${materialized}${decision.reason ? ` reason=${decision.reason}` : ""})`);
|
|
176105
|
+
const memPath = memoryProjectPath(state);
|
|
176106
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
176107
|
+
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;
|
|
174318
176108
|
return {
|
|
174319
176109
|
injected: true,
|
|
174320
176110
|
compartmentCount: getCompartments(db, state.sessionId).length,
|
|
174321
176111
|
factCount: 0,
|
|
174322
|
-
memoryCount
|
|
174323
|
-
"active",
|
|
174324
|
-
"permanent"
|
|
174325
|
-
]).length : 0,
|
|
176112
|
+
memoryCount,
|
|
174326
176113
|
skippedVisibleMessages,
|
|
174327
176114
|
m0Materialized: materialized,
|
|
174328
176115
|
m0Reason: decision.reason,
|
|
@@ -174383,21 +176170,48 @@ import * as crypto2 from "node:crypto";
|
|
|
174383
176170
|
|
|
174384
176171
|
// ../plugin/src/features/magic-context/compartment-embedding.ts
|
|
174385
176172
|
init_logger();
|
|
174386
|
-
async function
|
|
176173
|
+
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
174387
176174
|
if (compartments.length === 0)
|
|
174388
176175
|
return;
|
|
174389
|
-
const
|
|
174390
|
-
for (const
|
|
174391
|
-
if (!c.p1 || c.p1.length === 0)
|
|
174392
|
-
continue;
|
|
176176
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
176177
|
+
for (const compartment of compartments) {
|
|
174393
176178
|
try {
|
|
174394
|
-
const
|
|
174395
|
-
|
|
174396
|
-
|
|
174397
|
-
|
|
176179
|
+
const fromMemory = compartment.sourceChunkText ? canonicalizeInMemoryChunkTextForEmbedding(compartment.sourceChunkText, compartment.startMessage, compartment.endMessage) : "";
|
|
176180
|
+
const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage);
|
|
176181
|
+
if (canonicalText.length === 0)
|
|
176182
|
+
continue;
|
|
176183
|
+
const windows = chunkCanonicalText(canonicalText, compartment.startMessage, compartment.endMessage, maxInputTokens);
|
|
176184
|
+
if (windows.length === 0)
|
|
176185
|
+
continue;
|
|
176186
|
+
const currentModelId = getProjectChunkEmbeddingModelId(projectPath);
|
|
176187
|
+
if (currentModelId !== "off" && chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
176188
|
+
continue;
|
|
176189
|
+
}
|
|
176190
|
+
const result = await embedBatchForProject(projectPath, windows.map((window) => window.text));
|
|
176191
|
+
if (!result)
|
|
176192
|
+
continue;
|
|
176193
|
+
if (chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
176194
|
+
continue;
|
|
176195
|
+
}
|
|
176196
|
+
const rows = [];
|
|
176197
|
+
for (const [index, window] of windows.entries()) {
|
|
176198
|
+
const vector = result.vectors[index];
|
|
176199
|
+
if (!vector)
|
|
176200
|
+
continue;
|
|
176201
|
+
rows.push({
|
|
176202
|
+
compartmentId: compartment.id,
|
|
176203
|
+
sessionId,
|
|
176204
|
+
projectPath,
|
|
176205
|
+
window,
|
|
176206
|
+
modelId: currentModelId,
|
|
176207
|
+
vector
|
|
176208
|
+
});
|
|
176209
|
+
}
|
|
176210
|
+
if (rows.length === windows.length) {
|
|
176211
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
174398
176212
|
}
|
|
174399
176213
|
} catch (error51) {
|
|
174400
|
-
sessionLog(sessionId, `compartment embedding failed for compartment ${
|
|
176214
|
+
sessionLog(sessionId, `compartment chunk embedding failed for compartment ${compartment.id}:`, error51);
|
|
174401
176215
|
}
|
|
174402
176216
|
}
|
|
174403
176217
|
}
|
|
@@ -177466,6 +179280,7 @@ async function runPiHistorian(deps) {
|
|
|
177466
179280
|
fallbackModels,
|
|
177467
179281
|
historianChunkTokens,
|
|
177468
179282
|
boundarySnapshot: providedBoundarySnapshot,
|
|
179283
|
+
refreshBoundarySnapshot,
|
|
177469
179284
|
currentContextLimit,
|
|
177470
179285
|
historianTimeoutMs = DEFAULT_HISTORIAN_TIMEOUT_MS2,
|
|
177471
179286
|
twoPass,
|
|
@@ -177519,16 +179334,29 @@ async function runPiHistorian(deps) {
|
|
|
177519
179334
|
return;
|
|
177520
179335
|
}
|
|
177521
179336
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
177522
|
-
|
|
179337
|
+
let boundarySnapshot = providedBoundarySnapshot ?? null;
|
|
177523
179338
|
if (!boundarySnapshot) {
|
|
177524
179339
|
sessionLog(sessionId, "historian no-op: missing protected-tail boundary snapshot from Pi trigger decision");
|
|
177525
179340
|
return;
|
|
177526
179341
|
}
|
|
177527
|
-
|
|
179342
|
+
let validation = boundarySnapshot.rawRangeFingerprint.length > 0 ? validateBoundarySnapshot({
|
|
177528
179343
|
db,
|
|
177529
179344
|
snapshot: boundarySnapshot,
|
|
177530
179345
|
currentContextLimit: currentContextLimit ?? boundarySnapshot.contextLimit
|
|
177531
179346
|
}) : { ok: true };
|
|
179347
|
+
if (!validation.ok && validation.reason === "stale_snapshot" && refreshBoundarySnapshot) {
|
|
179348
|
+
try {
|
|
179349
|
+
const refreshed = refreshBoundarySnapshot();
|
|
179350
|
+
if (hasRunnableCompartmentWindow(refreshed)) {
|
|
179351
|
+
sessionLog(sessionId, `historian: refreshed stale protected-tail snapshot at run time (was: ${validation.detail ?? "stale"}) — eligible head ${refreshed.offset}-${refreshed.eligibleEndOrdinal - 1}`);
|
|
179352
|
+
boundarySnapshot = refreshed;
|
|
179353
|
+
validation = { ok: true };
|
|
179354
|
+
}
|
|
179355
|
+
} catch (error51) {
|
|
179356
|
+
const desc = describeError(error51);
|
|
179357
|
+
sessionLog(sessionId, `historian: failed to refresh stale protected-tail snapshot at run time (${validation.detail ?? "stale"}): ${desc.brief}`);
|
|
179358
|
+
}
|
|
179359
|
+
}
|
|
177532
179360
|
if (!validation.ok) {
|
|
177533
179361
|
sessionLog(sessionId, `historian no-op: stale protected-tail snapshot (${validation.detail ?? validation.reason ?? "unknown"})`);
|
|
177534
179362
|
return;
|
|
@@ -177857,8 +179685,13 @@ ${chunkText}`,
|
|
|
177857
179685
|
}
|
|
177858
179686
|
}
|
|
177859
179687
|
if (embeddingActive) {
|
|
177860
|
-
const
|
|
177861
|
-
|
|
179688
|
+
const chunksToEmbed = newCompartments.map((c, i) => ({
|
|
179689
|
+
id: persistedIds[i],
|
|
179690
|
+
startMessage: c.startMessage,
|
|
179691
|
+
endMessage: c.endMessage,
|
|
179692
|
+
sourceChunkText: chunk.text
|
|
179693
|
+
})).filter((c) => typeof c.id === "number");
|
|
179694
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectPath, chunksToEmbed);
|
|
177862
179695
|
}
|
|
177863
179696
|
onPublished?.();
|
|
177864
179697
|
completedSuccessfully = true;
|
|
@@ -178406,7 +180239,7 @@ function stripPiDroppedPlaceholderMessages(args) {
|
|
|
178406
180239
|
}
|
|
178407
180240
|
|
|
178408
180241
|
// src/system-prompt.ts
|
|
178409
|
-
import { createHash as
|
|
180242
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
178410
180243
|
|
|
178411
180244
|
// ../plugin/src/agents/magic-context-prompt.ts
|
|
178412
180245
|
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
@@ -178557,7 +180390,7 @@ function processSystemPromptForCache(args) {
|
|
|
178557
180390
|
sessionLog(sessionId, `system prompt date frozen: real=${liveDate}, using=${stickyDate} (cache-stable pass)`);
|
|
178558
180391
|
}
|
|
178559
180392
|
}
|
|
178560
|
-
const currentHash =
|
|
180393
|
+
const currentHash = createHash11("md5").update(frozenPrompt).digest("hex");
|
|
178561
180394
|
const hashChanged = !isFirstHash && currentHash !== previousHash;
|
|
178562
180395
|
if (hashChanged) {
|
|
178563
180396
|
sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${frozenPrompt.length})`);
|
|
@@ -179184,6 +181017,19 @@ function extractStableId(msg, index, entryIds) {
|
|
|
179184
181017
|
// src/context-handler.ts
|
|
179185
181018
|
var FORCE_MATERIALIZATION_PERCENTAGE = 85;
|
|
179186
181019
|
var EMERGENCY_BLOCK_PERCENTAGE = 95;
|
|
181020
|
+
var FORWARD_PRESSURE_LIMIT_FACTOR = 0.85;
|
|
181021
|
+
function applyForwardPressureFloor(trailingPercentage, trailingInputTokens, piUsageTokens, correctedLimit) {
|
|
181022
|
+
const forwardTokens = typeof piUsageTokens === "number" && piUsageTokens > 0 ? piUsageTokens : 0;
|
|
181023
|
+
if (forwardTokens === 0 || !isSaneLimit(correctedLimit)) {
|
|
181024
|
+
return { percentage: trailingPercentage, inputTokens: trailingInputTokens };
|
|
181025
|
+
}
|
|
181026
|
+
const forwardPressureLimit = correctedLimit * FORWARD_PRESSURE_LIMIT_FACTOR;
|
|
181027
|
+
const forwardPercentage = forwardTokens / forwardPressureLimit * 100;
|
|
181028
|
+
return forwardPercentage > trailingPercentage ? {
|
|
181029
|
+
percentage: forwardPercentage,
|
|
181030
|
+
inputTokens: Math.max(trailingInputTokens, forwardTokens)
|
|
181031
|
+
} : { percentage: trailingPercentage, inputTokens: trailingInputTokens };
|
|
181032
|
+
}
|
|
179187
181033
|
var DEFAULT_CLEAR_REASONING_AGE = 50;
|
|
179188
181034
|
var PI_STABLE_ID_SCHEME = 1;
|
|
179189
181035
|
var lastEmergencyNotificationAtMs = new Map;
|
|
@@ -179268,7 +181114,7 @@ function trackSessionForProject(projectIdentity, sessionId) {
|
|
|
179268
181114
|
function isContextHandlerSessionActive(sessionId) {
|
|
179269
181115
|
return activeContextHandlerSessions.has(sessionId);
|
|
179270
181116
|
}
|
|
179271
|
-
function updateSessionProjectTracking(sessionId, projectIdentity) {
|
|
181117
|
+
function updateSessionProjectTracking(sessionId, projectIdentity, db) {
|
|
179272
181118
|
const prev = lastSeenProjectIdentityBySession.get(sessionId);
|
|
179273
181119
|
if (prev && prev !== projectIdentity) {
|
|
179274
181120
|
const prevSessions = sessionsByProject.get(prev);
|
|
@@ -179277,6 +181123,11 @@ function updateSessionProjectTracking(sessionId, projectIdentity) {
|
|
|
179277
181123
|
sessionsByProject.delete(prev);
|
|
179278
181124
|
clearPiSystemPromptSession(sessionId);
|
|
179279
181125
|
}
|
|
181126
|
+
if (db && prev !== projectIdentity) {
|
|
181127
|
+
try {
|
|
181128
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
181129
|
+
} catch {}
|
|
181130
|
+
}
|
|
179280
181131
|
trackSessionForProject(projectIdentity, sessionId);
|
|
179281
181132
|
lastSeenProjectIdentityBySession.set(sessionId, projectIdentity);
|
|
179282
181133
|
}
|
|
@@ -179557,7 +181408,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
179557
181408
|
const schedulerConfig = options.scheduler ?? DEFAULT_SCHEDULER_CONFIG;
|
|
179558
181409
|
const scheduler2 = schedulerFor(options);
|
|
179559
181410
|
const projectIdentity = resolveProjectIdentity(projectDirectory);
|
|
179560
|
-
updateSessionProjectTracking(sessionId, projectIdentity);
|
|
181411
|
+
updateSessionProjectTracking(sessionId, projectIdentity, options.db);
|
|
179561
181412
|
logTransformTiming(sessionId, "findSessionId", tFindSession, `messages=${event.messages.length}`);
|
|
179562
181413
|
const branchEntries = readPiBranchEntriesForContext(ctx, sessionId);
|
|
179563
181414
|
const rawMessageProvider = {
|
|
@@ -179666,9 +181517,10 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
179666
181517
|
if (!usedPersistedUsage && isSaneLimit(usageContextLimit) && usageInputTokens > 0) {
|
|
179667
181518
|
usagePercentage = usageInputTokens / usageContextLimit * 100;
|
|
179668
181519
|
}
|
|
181520
|
+
({ percentage: usagePercentage, inputTokens: usageInputTokens } = applyForwardPressureFloor(usagePercentage, usageInputTokens, piUsage?.tokens, usageContextLimit));
|
|
179669
181521
|
if (needsEmergencyBump) {
|
|
179670
181522
|
sessionLog(sessionId, `transform: overflow recovery flag set — bumping percentage to 95% (detectedLimit=${usageContextLimit ?? "unknown"})`);
|
|
179671
|
-
usagePercentage = 95;
|
|
181523
|
+
usagePercentage = Math.max(usagePercentage, 95);
|
|
179672
181524
|
}
|
|
179673
181525
|
let schedulerDecision;
|
|
179674
181526
|
const tScheduler = performance.now();
|
|
@@ -180052,6 +181904,7 @@ function spawnPiHistorianRun(args) {
|
|
|
180052
181904
|
provider: provider2,
|
|
180053
181905
|
unregister,
|
|
180054
181906
|
boundarySnapshot,
|
|
181907
|
+
refreshBoundarySnapshot,
|
|
180055
181908
|
currentContextLimit
|
|
180056
181909
|
} = args;
|
|
180057
181910
|
const holderId = crypto3.randomUUID();
|
|
@@ -180075,6 +181928,7 @@ function spawnPiHistorianRun(args) {
|
|
|
180075
181928
|
fallbackModels: historian.fallbackModels,
|
|
180076
181929
|
historianChunkTokens: historian.historianChunkTokens,
|
|
180077
181930
|
boundarySnapshot,
|
|
181931
|
+
refreshBoundarySnapshot,
|
|
180078
181932
|
currentContextLimit,
|
|
180079
181933
|
historianTimeoutMs: historian.timeoutMs,
|
|
180080
181934
|
twoPass: historian.twoPass,
|
|
@@ -180141,6 +181995,7 @@ function maybeFireHistorian(args) {
|
|
|
180141
181995
|
let usageContextLimit;
|
|
180142
181996
|
try {
|
|
180143
181997
|
const piUsage = ctx.getContextUsage?.();
|
|
181998
|
+
let usageSource;
|
|
180144
181999
|
usageContextLimit = isSaneLimit(piUsage?.contextWindow) ? piUsage.contextWindow : undefined;
|
|
180145
182000
|
if (usageContextLimit === undefined && isSaneLimit(ctx.model?.contextWindow)) {
|
|
180146
182001
|
usageContextLimit = ctx.model.contextWindow;
|
|
@@ -180157,7 +182012,7 @@ function maybeFireHistorian(args) {
|
|
|
180157
182012
|
percentage: sessionMetaForUsage.lastContextPercentage,
|
|
180158
182013
|
inputTokens: sessionMetaForUsage.lastInputTokens
|
|
180159
182014
|
};
|
|
180160
|
-
|
|
182015
|
+
usageSource = "session_meta";
|
|
180161
182016
|
} else {
|
|
180162
182017
|
if (!piUsage || piUsage.tokens === null || piUsage.percent === null || piUsage.contextWindow === 0) {
|
|
180163
182018
|
sessionLog(sessionId, `historian trigger eval: no usage info yet (tokens=${piUsage?.tokens ?? "<no piUsage>"}, percent=${piUsage?.percent ?? "<no piUsage>"}, contextWindow=${piUsage?.contextWindow ?? "<no piUsage>"})`);
|
|
@@ -180168,8 +182023,10 @@ function maybeFireHistorian(args) {
|
|
|
180168
182023
|
percentage: fallbackPercentage,
|
|
180169
182024
|
inputTokens: piUsage.tokens
|
|
180170
182025
|
};
|
|
180171
|
-
|
|
182026
|
+
usageSource = "piUsage fallback";
|
|
180172
182027
|
}
|
|
182028
|
+
usage = applyForwardPressureFloor(usage.percentage, usage.inputTokens, piUsage?.tokens, usageContextLimit);
|
|
182029
|
+
sessionLog(sessionId, `historian trigger eval: usage=${usage.percentage.toFixed(1)}% (${usage.inputTokens} tokens) [${usageSource}], checking trigger...`);
|
|
180173
182030
|
} catch (err) {
|
|
180174
182031
|
sessionLog(sessionId, `historian trigger eval: getContextUsage threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
180175
182032
|
return;
|
|
@@ -180200,10 +182057,14 @@ function maybeFireHistorian(args) {
|
|
|
180200
182057
|
cacheNamespace: `pi:${sessionId}`,
|
|
180201
182058
|
emergencyTailScale
|
|
180202
182059
|
}));
|
|
180203
|
-
|
|
180204
|
-
|
|
180205
|
-
|
|
180206
|
-
|
|
182060
|
+
const resolveRunnablePiBoundarySnapshot = () => {
|
|
182061
|
+
let snapshot = ensureRunnablePiBoundaryForTests(resolvePiBoundarySnapshot());
|
|
182062
|
+
if (!hasRunnableCompartmentWindow(snapshot) && usage.percentage >= 80) {
|
|
182063
|
+
snapshot = ensureRunnablePiBoundaryForTests(resolvePiBoundarySnapshot(usage.percentage >= 95 ? 0.25 : 0.5));
|
|
182064
|
+
}
|
|
182065
|
+
return snapshot;
|
|
182066
|
+
};
|
|
182067
|
+
const boundarySnapshot = resolveRunnablePiBoundarySnapshot();
|
|
180207
182068
|
let triggered = false;
|
|
180208
182069
|
try {
|
|
180209
182070
|
if (isFirstContextPassForSession) {
|
|
@@ -180228,6 +182089,7 @@ Historian previously failed ${failureState.failureCount} time(s), so Magic Conte
|
|
|
180228
182089
|
provider: provider2,
|
|
180229
182090
|
unregister,
|
|
180230
182091
|
boundarySnapshot,
|
|
182092
|
+
refreshBoundarySnapshot: resolveRunnablePiBoundarySnapshot,
|
|
180231
182093
|
currentContextLimit: boundaryContextLimit
|
|
180232
182094
|
});
|
|
180233
182095
|
return;
|
|
@@ -180251,6 +182113,7 @@ Historian previously failed ${failureState.failureCount} time(s), so Magic Conte
|
|
|
180251
182113
|
resolvedBoundarySnapshot: boundarySnapshot,
|
|
180252
182114
|
triggerBoundarySnapshot: trigger.boundarySnapshot
|
|
180253
182115
|
}),
|
|
182116
|
+
refreshBoundarySnapshot: resolveRunnablePiBoundarySnapshot,
|
|
180254
182117
|
currentContextLimit: boundaryContextLimit
|
|
180255
182118
|
});
|
|
180256
182119
|
} catch (err) {
|
|
@@ -180291,7 +182154,31 @@ async function runPipeline(args) {
|
|
|
180291
182154
|
const alreadyRanHeuristicsThisTurn = currentTurnId !== null && lastHeuristicsTurnIdBySession.get(args.sessionId) === currentTurnId;
|
|
180292
182155
|
const canConsumeDeferredLate = args.schedulerDecision === "execute" || args.forceMaterialization === true || args.contextUsage.percentage >= FORCE_MATERIALIZATION_PERCENTAGE;
|
|
180293
182156
|
const deferredMaterializeEligible = canConsumeDeferredLate && deferredMaterializationSessions.has(args.sessionId);
|
|
180294
|
-
const
|
|
182157
|
+
const piHardSignals = args.injection ? (() => {
|
|
182158
|
+
const hardMeta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
182159
|
+
let piTtlMs = 5 * 60 * 1000;
|
|
182160
|
+
try {
|
|
182161
|
+
piTtlMs = parseCacheTtl(hardMeta.cacheTtl);
|
|
182162
|
+
} catch {}
|
|
182163
|
+
return {
|
|
182164
|
+
systemHash: typeof hardMeta.systemPromptHash === "string" ? hardMeta.systemPromptHash : "",
|
|
182165
|
+
modelKey: liveModelBySession.get(args.sessionId) ?? "",
|
|
182166
|
+
cacheExpired: hardMeta.lastResponseTime > 0 && Date.now() - hardMeta.lastResponseTime >= piTtlMs,
|
|
182167
|
+
lastResponseTime: hardMeta.lastResponseTime
|
|
182168
|
+
};
|
|
182169
|
+
})() : undefined;
|
|
182170
|
+
const m0HardFoldThisPass = args.injection && piHardSignals ? mustMaterializePi({
|
|
182171
|
+
sessionId: args.sessionId,
|
|
182172
|
+
projectIdentity: args.projectIdentity,
|
|
182173
|
+
projectDirectory: args.projectDirectory,
|
|
182174
|
+
memoryEnabled: args.injection.memoryEnabled,
|
|
182175
|
+
injectionBudgetTokens: args.injection.injectionBudgetTokens,
|
|
182176
|
+
historyBudgetTokens: args.injection.historyBudgetTokens,
|
|
182177
|
+
keyFilesEnabled: args.injection.keyFilesEnabled,
|
|
182178
|
+
keyFilesTokenBudget: args.injection.keyFilesTokenBudget,
|
|
182179
|
+
hardSignals: piHardSignals
|
|
182180
|
+
}, args.db, getCompartments(args.db, args.sessionId)).value : false;
|
|
182181
|
+
const shouldRunHeuristics = args.heuristics !== undefined && (args.forceMaterialization === true || hasPendingMaterialization(args.sessionId) || deferredMaterializeEligible || m0HardFoldThisPass || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
|
|
180295
182182
|
const entryFingerprintByMessageId = buildEntryFingerprintMap(args.messages, stableIdResolver);
|
|
180296
182183
|
adoptPiFallbackTags(args.db, args.sessionId, args.tagger, entryFingerprintByMessageId);
|
|
180297
182184
|
const tTag = performance.now();
|
|
@@ -180318,12 +182205,12 @@ async function runPipeline(args) {
|
|
|
180318
182205
|
const deferredMaterializationWasPending = deferredMaterializationSessions.has(args.sessionId);
|
|
180319
182206
|
const deferredHistoryRefreshWasPending = deferredHistoryWasPendingAtPassStart;
|
|
180320
182207
|
const pendingOps = getPendingOps(args.db, args.sessionId);
|
|
180321
|
-
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal;
|
|
182208
|
+
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal || m0HardFoldThisPass;
|
|
180322
182209
|
const deferredMaterialize = canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
180323
182210
|
const deferredHistoryRefresh = canConsumeDeferredLate && deferredHistoryRefreshWasPending;
|
|
180324
182211
|
const shouldApplyPendingOps = baseShouldApplyPendingOps || deferredMaterialize;
|
|
180325
182212
|
if (shouldApplyPendingOps) {
|
|
180326
|
-
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
182213
|
+
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})`;
|
|
180327
182214
|
sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
|
|
180328
182215
|
try {
|
|
180329
182216
|
const tApplyPending = performance.now();
|
|
@@ -180394,7 +182281,7 @@ async function runPipeline(args) {
|
|
|
180394
182281
|
const activeTags = getActiveTagsBySession(args.db, args.sessionId);
|
|
180395
182282
|
logTransformTiming(args.sessionId, "getActiveTagsBySession", tActiveTags, `count=${activeTags.length}`);
|
|
180396
182283
|
if (shouldRunHeuristics) {
|
|
180397
|
-
const reason = args.forceMaterialization ? "force_materialization" : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
182284
|
+
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})`;
|
|
180398
182285
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=n/a`);
|
|
180399
182286
|
} else {
|
|
180400
182287
|
const reason = args.heuristics === undefined ? "disabled" : "scheduler_defer";
|
|
@@ -180482,18 +182369,6 @@ async function runPipeline(args) {
|
|
|
180482
182369
|
if (args.injection) {
|
|
180483
182370
|
try {
|
|
180484
182371
|
const tInjection = performance.now();
|
|
180485
|
-
const hardMeta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
180486
|
-
let piTtlMs = 5 * 60 * 1000;
|
|
180487
|
-
try {
|
|
180488
|
-
piTtlMs = parseCacheTtl(hardMeta.cacheTtl);
|
|
180489
|
-
} catch {}
|
|
180490
|
-
const piHardSignals = {
|
|
180491
|
-
systemHash: typeof hardMeta.systemPromptHash === "string" ? hardMeta.systemPromptHash : "",
|
|
180492
|
-
toolSetHash: "",
|
|
180493
|
-
modelKey: liveModelBySession.get(args.sessionId) ?? "",
|
|
180494
|
-
cacheExpired: hardMeta.lastResponseTime > 0 && Date.now() - hardMeta.lastResponseTime >= piTtlMs,
|
|
180495
|
-
lastResponseTime: hardMeta.lastResponseTime
|
|
180496
|
-
};
|
|
180497
182372
|
injectionResult = injectM0M1Pi({
|
|
180498
182373
|
sessionId: args.sessionId,
|
|
180499
182374
|
projectIdentity: args.projectIdentity,
|
|
@@ -181583,8 +183458,12 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
181583
183458
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181584
183459
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
181585
183460
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181586
|
-
const
|
|
181587
|
-
|
|
183461
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
183462
|
+
id: c.id,
|
|
183463
|
+
startMessage: c.startMessage,
|
|
183464
|
+
endMessage: c.endMessage
|
|
183465
|
+
}));
|
|
183466
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
181588
183467
|
}
|
|
181589
183468
|
const lastCompartmentEnd2 = promoted2.compartments[promoted2.compartments.length - 1]?.endMessage ?? 0;
|
|
181590
183469
|
if (lastCompartmentEnd2 > 0) {
|
|
@@ -181797,8 +183676,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
181797
183676
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181798
183677
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
181799
183678
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181800
|
-
const
|
|
181801
|
-
|
|
183679
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
183680
|
+
id: c.id,
|
|
183681
|
+
startMessage: c.startMessage,
|
|
183682
|
+
endMessage: c.endMessage
|
|
183683
|
+
}));
|
|
183684
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
181802
183685
|
}
|
|
181803
183686
|
if (lastCompartmentEnd > 0) {
|
|
181804
183687
|
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
@@ -181955,8 +183838,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
181955
183838
|
if (deps.memoryEnabled !== false) {
|
|
181956
183839
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181957
183840
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181958
|
-
const
|
|
181959
|
-
|
|
183841
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
183842
|
+
id: c.id,
|
|
183843
|
+
startMessage: c.startMessage,
|
|
183844
|
+
endMessage: c.endMessage
|
|
183845
|
+
}));
|
|
183846
|
+
Promise.resolve(deps.ensureProjectRegistered?.(sessionDirectory, db)).then(() => embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed));
|
|
181960
183847
|
}
|
|
181961
183848
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
181962
183849
|
if (lastEnd > 0) {
|
|
@@ -182402,7 +184289,7 @@ function renderStatusText(ctx, db, sessionId) {
|
|
|
182402
184289
|
const pct = typeof usage?.percent === "number" ? usage.percent : undefined;
|
|
182403
184290
|
const meta3 = readSessionMetaStatus(db, sessionId);
|
|
182404
184291
|
const state = renderHistorianState(meta3, recompSessions.has(sessionId));
|
|
182405
|
-
return `
|
|
184292
|
+
return `MC: ${inputTokens === undefined ? "--" : fmt(inputTokens)} (${pct === undefined ? "--" : `${Math.round(pct)}%`}) · ${state}`;
|
|
182406
184293
|
}
|
|
182407
184294
|
function renderHistorianState(meta3, recompActive) {
|
|
182408
184295
|
const failureCount = meta3?.historian_failure_count ?? 0;
|
|
@@ -182768,7 +184655,7 @@ function applyMemoryMigration(db, projectPath, result) {
|
|
|
182768
184655
|
inserted++;
|
|
182769
184656
|
}
|
|
182770
184657
|
if (removed > 0 || inserted > 0) {
|
|
182771
|
-
|
|
184658
|
+
bumpEpochsForWorkspaceMembers(db, projectPath);
|
|
182772
184659
|
}
|
|
182773
184660
|
})();
|
|
182774
184661
|
return { removed, inserted };
|
|
@@ -183244,7 +185131,7 @@ function formatThresholdPercent(value) {
|
|
|
183244
185131
|
// package.json
|
|
183245
185132
|
var package_default = {
|
|
183246
185133
|
name: "@wolfx/pi-magic-context",
|
|
183247
|
-
version: "0.
|
|
185134
|
+
version: "0.24.0",
|
|
183248
185135
|
type: "module",
|
|
183249
185136
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
183250
185137
|
main: "dist/index.js",
|
|
@@ -188135,6 +190022,23 @@ function createCtxMemoryTool(deps) {
|
|
|
188135
190022
|
}
|
|
188136
190023
|
const projectIdentity = resolveProjectIdentity(ctx.cwd);
|
|
188137
190024
|
await deps.ensureProjectRegistered?.(ctx.cwd, deps.db);
|
|
190025
|
+
const workspaceIdentitySet = resolveWorkspaceIdentitySet(deps.db, projectIdentity);
|
|
190026
|
+
const expandedWorkspace = expandWorkspaceIdentitySetWithAliases(deps.db, workspaceIdentitySet.identities);
|
|
190027
|
+
const workspaceVisibleIdentities = workspaceIdentitySet.identities.length > 1 ? expandedWorkspace.expandedIdentities : workspaceIdentitySet.identities;
|
|
190028
|
+
const targetIdentityForStoredPath = (rawProjectPath) => workspaceIdentitySet.identities.length > 1 ? resolveStoredPathWorkspaceIdentity(rawProjectPath, workspaceIdentitySet.identities, expandedWorkspace.canonicalIdentityByStoredPath) ?? normalizeStoredProjectPath(rawProjectPath) : normalizeStoredProjectPath(rawProjectPath);
|
|
190029
|
+
const toolShareCategories = workspaceIdentitySet.identities.length > 1 ? resolveWorkspaceShareCategories(deps.db, projectIdentity) : null;
|
|
190030
|
+
const memoryVisibleToTool = (memory2) => {
|
|
190031
|
+
if (workspaceIdentitySet.identities.length <= 1) {
|
|
190032
|
+
return storedPathBelongsToIdentity(memory2.projectPath, projectIdentity);
|
|
190033
|
+
}
|
|
190034
|
+
if (!storedPathBelongsToWorkspace(memory2.projectPath, workspaceIdentitySet.identities, workspaceVisibleIdentities, expandedWorkspace.canonicalIdentityByStoredPath)) {
|
|
190035
|
+
return false;
|
|
190036
|
+
}
|
|
190037
|
+
const isOwn = targetIdentityForStoredPath(memory2.projectPath) === projectIdentity;
|
|
190038
|
+
if (isOwn)
|
|
190039
|
+
return true;
|
|
190040
|
+
return toolShareCategories === null || toolShareCategories.includes(memory2.category);
|
|
190041
|
+
};
|
|
188138
190042
|
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
188139
190043
|
if (snapshot ? !snapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
188140
190044
|
return err2("Cross-session memory is disabled for this project.");
|
|
@@ -188181,28 +190085,34 @@ function createCtxMemoryTool(deps) {
|
|
|
188181
190085
|
return err2("Error: 'content' is required when action is 'update'.");
|
|
188182
190086
|
}
|
|
188183
190087
|
const memory2 = getMemoryById(deps.db, updateId);
|
|
188184
|
-
if (!memory2 || !
|
|
190088
|
+
if (!memory2 || !memoryVisibleToTool(memory2)) {
|
|
188185
190089
|
return err2(`Error: Memory with ID ${updateId} was not found.`);
|
|
188186
190090
|
}
|
|
188187
190091
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
188188
190092
|
return err2(inactiveMemoryError(updateId, "updating"));
|
|
188189
190093
|
}
|
|
188190
190094
|
const normalizedHash = computeNormalizedHash(content);
|
|
188191
|
-
const
|
|
190095
|
+
const targetIdentity = targetIdentityForStoredPath(memory2.projectPath);
|
|
190096
|
+
const duplicate = getMemoryByHash(deps.db, targetIdentity, memory2.category, normalizedHash);
|
|
188192
190097
|
if (duplicate && duplicate.id !== memory2.id) {
|
|
188193
190098
|
return err2(`Error: Memory content already exists as ID ${duplicate.id}; merge or archive duplicates instead.`);
|
|
188194
190099
|
}
|
|
188195
190100
|
deps.db.transaction(() => {
|
|
188196
190101
|
updateMemoryContent(deps.db, memory2.id, content, normalizedHash);
|
|
188197
190102
|
queueMemoryMutation(deps.db, {
|
|
188198
|
-
projectPath:
|
|
190103
|
+
projectPath: targetIdentity,
|
|
188199
190104
|
mutationType: "update",
|
|
188200
190105
|
targetMemoryId: memory2.id,
|
|
188201
190106
|
category: memory2.category,
|
|
188202
190107
|
newContent: content
|
|
188203
190108
|
});
|
|
188204
190109
|
})();
|
|
188205
|
-
queueEmbedding({
|
|
190110
|
+
queueEmbedding({
|
|
190111
|
+
deps,
|
|
190112
|
+
projectIdentity: targetIdentity,
|
|
190113
|
+
memoryId: memory2.id,
|
|
190114
|
+
content
|
|
190115
|
+
});
|
|
188206
190116
|
return ok2(`Updated memory [ID: ${memory2.id}] in ${memory2.category}.`);
|
|
188207
190117
|
}
|
|
188208
190118
|
if (params.action === "merge") {
|
|
@@ -188222,7 +190132,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188222
190132
|
return err2("Error: One or more source memories were not found.");
|
|
188223
190133
|
}
|
|
188224
190134
|
if (!dreamerAllowed) {
|
|
188225
|
-
const foreign = sourceMemories.find((memory2) => !
|
|
190135
|
+
const foreign = sourceMemories.find((memory2) => !memoryVisibleToTool(memory2));
|
|
188226
190136
|
if (foreign) {
|
|
188227
190137
|
return err2(`Error: Memory with ID ${foreign.id} was not found.`);
|
|
188228
190138
|
}
|
|
@@ -188311,26 +190221,36 @@ function createCtxMemoryTool(deps) {
|
|
|
188311
190221
|
return ok2(`Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`);
|
|
188312
190222
|
}
|
|
188313
190223
|
if (params.action === "archive") {
|
|
188314
|
-
const
|
|
188315
|
-
if (!
|
|
190224
|
+
const rawArchiveIds = params.ids;
|
|
190225
|
+
if (!rawArchiveIds || rawArchiveIds.length === 0 || !rawArchiveIds.every(Number.isInteger)) {
|
|
188316
190226
|
return err2("Error: 'ids' must contain at least one integer memory ID when action is 'archive'.");
|
|
188317
190227
|
}
|
|
190228
|
+
const archiveIds = [...new Set(rawArchiveIds)];
|
|
188318
190229
|
for (const memoryId of archiveIds) {
|
|
188319
190230
|
const memory2 = getMemoryById(deps.db, memoryId);
|
|
188320
|
-
if (!memory2 || !
|
|
190231
|
+
if (!memory2 || !memoryVisibleToTool(memory2)) {
|
|
188321
190232
|
return err2(`Error: Memory with ID ${memoryId} was not found.`);
|
|
188322
190233
|
}
|
|
188323
190234
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
188324
190235
|
return err2(inactiveMemoryError(memoryId, "archiving"));
|
|
188325
190236
|
}
|
|
188326
190237
|
}
|
|
190238
|
+
const targets = archiveIds.map((memoryId) => {
|
|
190239
|
+
const memory2 = getMemoryById(deps.db, memoryId);
|
|
190240
|
+
if (!memory2)
|
|
190241
|
+
throw new Error(`validated memory ${memoryId} disappeared`);
|
|
190242
|
+
return {
|
|
190243
|
+
memoryId,
|
|
190244
|
+
projectIdentity: targetIdentityForStoredPath(memory2.projectPath)
|
|
190245
|
+
};
|
|
190246
|
+
});
|
|
188327
190247
|
deps.db.transaction(() => {
|
|
188328
|
-
for (const
|
|
188329
|
-
archiveMemory(deps.db, memoryId, params.reason);
|
|
190248
|
+
for (const target2 of targets) {
|
|
190249
|
+
archiveMemory(deps.db, target2.memoryId, params.reason);
|
|
188330
190250
|
queueMemoryMutation(deps.db, {
|
|
188331
|
-
projectPath: projectIdentity,
|
|
190251
|
+
projectPath: target2.projectIdentity,
|
|
188332
190252
|
mutationType: "archive",
|
|
188333
|
-
targetMemoryId: memoryId
|
|
190253
|
+
targetMemoryId: target2.memoryId
|
|
188334
190254
|
});
|
|
188335
190255
|
}
|
|
188336
190256
|
})();
|
|
@@ -188838,8 +190758,9 @@ function formatAge2(committedAtMs) {
|
|
|
188838
190758
|
}
|
|
188839
190759
|
function formatResult(result, index) {
|
|
188840
190760
|
if (result.source === "memory") {
|
|
190761
|
+
const source = result.sourceName ? ` source=${result.sourceName}` : "";
|
|
188841
190762
|
return [
|
|
188842
|
-
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category} match=${result.matchType}`,
|
|
190763
|
+
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category}${source} match=${result.matchType}`,
|
|
188843
190764
|
result.content
|
|
188844
190765
|
].join(`
|
|
188845
190766
|
`);
|
|
@@ -188849,6 +190770,13 @@ function formatResult(result, index) {
|
|
|
188849
190770
|
`[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge2(result.committedAtMs)} match=${result.matchType}`,
|
|
188850
190771
|
result.content
|
|
188851
190772
|
].join(`
|
|
190773
|
+
`);
|
|
190774
|
+
}
|
|
190775
|
+
if (result.source === "compartment") {
|
|
190776
|
+
return [
|
|
190777
|
+
`[${index}] [message] score=${result.score.toFixed(2)} compartment_id=${result.compartmentId} range=${result.startOrdinal}-${result.endOrdinal} match=${result.matchType} title=${result.title}`,
|
|
190778
|
+
result.snippet ? `Snippet: ${result.snippet}` : result.content
|
|
190779
|
+
].join(`
|
|
188852
190780
|
`);
|
|
188853
190781
|
}
|
|
188854
190782
|
const expandStart = Math.max(1, result.messageOrdinal - 3);
|
|
@@ -188864,7 +190792,7 @@ function formatSearchResults(query, results) {
|
|
|
188864
190792
|
return `No results found for "${query}" across memories, git commits, or message history.`;
|
|
188865
190793
|
}
|
|
188866
190794
|
const bodyParts = results.map((result, index) => formatResult(result, index + 1));
|
|
188867
|
-
if (results.some((result) => result.source === "message")) {
|
|
190795
|
+
if (results.some((result) => result.source === "message" || result.source === "compartment")) {
|
|
188868
190796
|
bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
|
|
188869
190797
|
}
|
|
188870
190798
|
const body = bodyParts.join(`
|
|
@@ -189360,6 +191288,14 @@ async function src_default2(pi) {
|
|
|
189360
191288
|
onProjectSeen: (identity) => seenDreamerProjectIdentities.add(identity)
|
|
189361
191289
|
});
|
|
189362
191290
|
info("registered /ctx-dream");
|
|
191291
|
+
registerCtxEmbedHistoryCommand(pi, {
|
|
191292
|
+
db,
|
|
191293
|
+
projectDir,
|
|
191294
|
+
projectIdentity,
|
|
191295
|
+
memoryEnabled: config2.memory.enabled,
|
|
191296
|
+
resolveProject: resolveCurrentProject
|
|
191297
|
+
});
|
|
191298
|
+
info("registered /ctx-embed-history");
|
|
189363
191299
|
const dreamerConfig = resolveDreamerFromConfig(config2);
|
|
189364
191300
|
if (dreamerConfig) {
|
|
189365
191301
|
registerPiDreamerProject({
|