@wolfx/pi-magic-context 0.23.1 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +2327 -347
- package/dist/subagent-entry.js +2101 -413
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -141961,6 +141961,7 @@ var SESSION_META_SELECT_COLUMNS = [
|
|
|
141961
141961
|
"cached_m0_bytes",
|
|
141962
141962
|
"cached_m1_bytes",
|
|
141963
141963
|
"cached_m0_project_memory_epoch",
|
|
141964
|
+
"cached_m0_workspace_fingerprint",
|
|
141964
141965
|
"cached_m0_project_user_profile_version",
|
|
141965
141966
|
"cached_m0_max_compartment_seq",
|
|
141966
141967
|
"cached_m0_max_memory_id",
|
|
@@ -142008,6 +142009,7 @@ var META_COLUMNS = {
|
|
|
142008
142009
|
cachedM0Bytes: "cached_m0_bytes",
|
|
142009
142010
|
cachedM1Bytes: "cached_m1_bytes",
|
|
142010
142011
|
cachedM0ProjectMemoryEpoch: "cached_m0_project_memory_epoch",
|
|
142012
|
+
cachedM0WorkspaceFingerprint: "cached_m0_workspace_fingerprint",
|
|
142011
142013
|
cachedM0ProjectUserProfileVersion: "cached_m0_project_user_profile_version",
|
|
142012
142014
|
cachedM0MaxCompartmentSeq: "cached_m0_max_compartment_seq",
|
|
142013
142015
|
cachedM0MaxMemoryId: "cached_m0_max_memory_id",
|
|
@@ -142037,6 +142039,7 @@ var NULL_BIND_META_KEYS = new Set([
|
|
|
142037
142039
|
"cachedM0Bytes",
|
|
142038
142040
|
"cachedM1Bytes",
|
|
142039
142041
|
"cachedM0ProjectMemoryEpoch",
|
|
142042
|
+
"cachedM0WorkspaceFingerprint",
|
|
142040
142043
|
"cachedM0ProjectUserProfileVersion",
|
|
142041
142044
|
"cachedM0MaxCompartmentSeq",
|
|
142042
142045
|
"cachedM0MaxMemoryId",
|
|
@@ -142070,7 +142073,7 @@ function isSessionMetaRow(row) {
|
|
|
142070
142073
|
if (row === null || typeof row !== "object")
|
|
142071
142074
|
return false;
|
|
142072
142075
|
const r = row;
|
|
142073
|
-
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
142076
|
+
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isStringOrNull(r.cached_m0_workspace_fingerprint) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
142074
142077
|
}
|
|
142075
142078
|
function getDefaultSessionMeta(sessionId) {
|
|
142076
142079
|
return {
|
|
@@ -142097,6 +142100,7 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
142097
142100
|
cachedM0Bytes: null,
|
|
142098
142101
|
cachedM1Bytes: null,
|
|
142099
142102
|
cachedM0ProjectMemoryEpoch: null,
|
|
142103
|
+
cachedM0WorkspaceFingerprint: null,
|
|
142100
142104
|
cachedM0ProjectUserProfileVersion: null,
|
|
142101
142105
|
cachedM0MaxCompartmentSeq: null,
|
|
142102
142106
|
cachedM0MaxMemoryId: null,
|
|
@@ -142159,6 +142163,7 @@ function toSessionMeta(row) {
|
|
|
142159
142163
|
cachedM0Bytes: toBufferOrNull(row.cached_m0_bytes),
|
|
142160
142164
|
cachedM1Bytes: toBufferOrNull(row.cached_m1_bytes),
|
|
142161
142165
|
cachedM0ProjectMemoryEpoch: numOrNull(row.cached_m0_project_memory_epoch),
|
|
142166
|
+
cachedM0WorkspaceFingerprint: stringOrNull(row.cached_m0_workspace_fingerprint),
|
|
142162
142167
|
cachedM0ProjectUserProfileVersion: numOrNull(row.cached_m0_project_user_profile_version),
|
|
142163
142168
|
cachedM0MaxCompartmentSeq: numOrNull(row.cached_m0_max_compartment_seq),
|
|
142164
142169
|
cachedM0MaxMemoryId: numOrNull(row.cached_m0_max_memory_id),
|
|
@@ -142189,6 +142194,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
142189
142194
|
db.prepare(`UPDATE session_meta SET
|
|
142190
142195
|
cached_m0_bytes = ?,
|
|
142191
142196
|
cached_m0_project_memory_epoch = ?,
|
|
142197
|
+
cached_m0_workspace_fingerprint = ?,
|
|
142192
142198
|
cached_m0_project_user_profile_version = ?,
|
|
142193
142199
|
cached_m0_max_compartment_seq = ?,
|
|
142194
142200
|
cached_m0_max_memory_id = ?,
|
|
@@ -142201,7 +142207,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
142201
142207
|
cached_m0_upgrade_state = ?,
|
|
142202
142208
|
cached_m0_system_hash = ?,
|
|
142203
142209
|
cached_m0_model_key = ?
|
|
142204
|
-
WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.modelKey ?? "", sessionId);
|
|
142210
|
+
WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.workspaceFingerprint ?? null, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.modelKey ?? "", sessionId);
|
|
142205
142211
|
}
|
|
142206
142212
|
function clearCachedM0M1(db, sessionId) {
|
|
142207
142213
|
ensureSessionMetaRow(db, sessionId);
|
|
@@ -142210,6 +142216,7 @@ function clearCachedM0M1(db, sessionId) {
|
|
|
142210
142216
|
["cached_m0_bytes", null],
|
|
142211
142217
|
["cached_m1_bytes", null],
|
|
142212
142218
|
["cached_m0_project_memory_epoch", null],
|
|
142219
|
+
["cached_m0_workspace_fingerprint", null],
|
|
142213
142220
|
["cached_m0_project_user_profile_version", null],
|
|
142214
142221
|
["cached_m0_max_compartment_seq", null],
|
|
142215
142222
|
["cached_m0_max_memory_id", null],
|
|
@@ -142924,7 +142931,7 @@ var databases = new Map;
|
|
|
142924
142931
|
var persistenceByDatabase = new WeakMap;
|
|
142925
142932
|
var persistenceErrorByDatabase = new WeakMap;
|
|
142926
142933
|
var lastSchemaFenceRejection = null;
|
|
142927
|
-
var LATEST_SUPPORTED_VERSION =
|
|
142934
|
+
var LATEST_SUPPORTED_VERSION = 36;
|
|
142928
142935
|
function resolveDatabasePath(dbPathOverride) {
|
|
142929
142936
|
if (dbPathOverride) {
|
|
142930
142937
|
return { dbDir: dirname2(dbPathOverride), dbPath: dbPathOverride };
|
|
@@ -143090,6 +143097,35 @@ function initializeDatabase(db) {
|
|
|
143090
143097
|
);
|
|
143091
143098
|
CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
|
|
143092
143099
|
|
|
143100
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
143101
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143102
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
143103
|
+
session_id TEXT NOT NULL,
|
|
143104
|
+
project_path TEXT NOT NULL,
|
|
143105
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
143106
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
143107
|
+
start_ordinal INTEGER NOT NULL,
|
|
143108
|
+
end_ordinal INTEGER NOT NULL,
|
|
143109
|
+
chunk_hash TEXT NOT NULL,
|
|
143110
|
+
model_id TEXT NOT NULL,
|
|
143111
|
+
dims INTEGER NOT NULL,
|
|
143112
|
+
vector BLOB NOT NULL,
|
|
143113
|
+
created_at INTEGER NOT NULL,
|
|
143114
|
+
UNIQUE(compartment_id, window_index)
|
|
143115
|
+
);
|
|
143116
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session ON compartment_chunk_embeddings(session_id);
|
|
143117
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model ON compartment_chunk_embeddings(project_path, model_id);
|
|
143118
|
+
|
|
143119
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
143120
|
+
session_id TEXT NOT NULL,
|
|
143121
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
143122
|
+
project_path TEXT NOT NULL,
|
|
143123
|
+
updated_at INTEGER NOT NULL,
|
|
143124
|
+
PRIMARY KEY(session_id, harness)
|
|
143125
|
+
);
|
|
143126
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
143127
|
+
ON session_projects(project_path);
|
|
143128
|
+
|
|
143093
143129
|
CREATE TABLE IF NOT EXISTS compartment_events (
|
|
143094
143130
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143095
143131
|
session_id TEXT NOT NULL,
|
|
@@ -143275,6 +143311,25 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143275
143311
|
rekeyed_at INTEGER NOT NULL
|
|
143276
143312
|
);
|
|
143277
143313
|
|
|
143314
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
143315
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143316
|
+
name TEXT NOT NULL UNIQUE,
|
|
143317
|
+
created_at INTEGER NOT NULL,
|
|
143318
|
+
updated_at INTEGER NOT NULL,
|
|
143319
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
143320
|
+
);
|
|
143321
|
+
|
|
143322
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
143323
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
143324
|
+
project_path TEXT NOT NULL,
|
|
143325
|
+
display_name TEXT NOT NULL,
|
|
143326
|
+
display_path TEXT NOT NULL,
|
|
143327
|
+
added_at INTEGER NOT NULL,
|
|
143328
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
143329
|
+
);
|
|
143330
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
143331
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
143332
|
+
|
|
143278
143333
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
143279
143334
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143280
143335
|
table_name TEXT NOT NULL,
|
|
@@ -143386,6 +143441,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143386
143441
|
deferred_execute_state TEXT,
|
|
143387
143442
|
cached_m0_bytes BLOB,
|
|
143388
143443
|
cached_m0_project_memory_epoch INTEGER,
|
|
143444
|
+
cached_m0_workspace_fingerprint TEXT,
|
|
143389
143445
|
cached_m0_project_user_profile_version INTEGER,
|
|
143390
143446
|
cached_m0_max_compartment_seq INTEGER,
|
|
143391
143447
|
cached_m0_max_memory_id INTEGER,
|
|
@@ -143544,6 +143600,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143544
143600
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
143545
143601
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
143546
143602
|
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
143603
|
+
ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
|
|
143547
143604
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
143548
143605
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
143549
143606
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -143597,6 +143654,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143597
143654
|
ensureColumn(db, "memories", "importance", "INTEGER");
|
|
143598
143655
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
143599
143656
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
143657
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
143600
143658
|
ensureColumn(db, "session_meta", "cached_m0_project_user_profile_version", "INTEGER");
|
|
143601
143659
|
ensureColumn(db, "session_meta", "cached_m0_max_compartment_seq", "INTEGER");
|
|
143602
143660
|
ensureColumn(db, "session_meta", "cached_m0_max_memory_id", "INTEGER");
|
|
@@ -143628,6 +143686,15 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143628
143686
|
project_user_profile_version INTEGER NOT NULL DEFAULT 0,
|
|
143629
143687
|
updated_at INTEGER NOT NULL DEFAULT 0
|
|
143630
143688
|
);
|
|
143689
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
143690
|
+
session_id TEXT NOT NULL,
|
|
143691
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
143692
|
+
project_path TEXT NOT NULL,
|
|
143693
|
+
updated_at INTEGER NOT NULL,
|
|
143694
|
+
PRIMARY KEY(session_id, harness)
|
|
143695
|
+
);
|
|
143696
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
143697
|
+
ON session_projects(project_path);
|
|
143631
143698
|
CREATE TABLE IF NOT EXISTS m0_mutation_log (
|
|
143632
143699
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143633
143700
|
session_id TEXT NOT NULL,
|
|
@@ -143655,6 +143722,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143655
143722
|
new_project_path TEXT NOT NULL,
|
|
143656
143723
|
rekeyed_at INTEGER NOT NULL
|
|
143657
143724
|
);
|
|
143725
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
143726
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143727
|
+
name TEXT NOT NULL UNIQUE,
|
|
143728
|
+
created_at INTEGER NOT NULL,
|
|
143729
|
+
updated_at INTEGER NOT NULL,
|
|
143730
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
143731
|
+
);
|
|
143732
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
143733
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
143734
|
+
project_path TEXT NOT NULL,
|
|
143735
|
+
display_name TEXT NOT NULL,
|
|
143736
|
+
display_path TEXT NOT NULL,
|
|
143737
|
+
added_at INTEGER NOT NULL,
|
|
143738
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
143739
|
+
);
|
|
143740
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
143741
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
143658
143742
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
143659
143743
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
143660
143744
|
table_name TEXT NOT NULL,
|
|
@@ -143676,6 +143760,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143676
143760
|
ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
143677
143761
|
ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
143678
143762
|
ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
143763
|
+
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
143679
143764
|
}
|
|
143680
143765
|
function healAllNullColumns(db) {
|
|
143681
143766
|
healNullTextColumns(db);
|
|
@@ -143714,6 +143799,7 @@ function healNullTextColumns(db) {
|
|
|
143714
143799
|
["system_prompt_hash", ""],
|
|
143715
143800
|
["stripped_placeholder_ids", ""],
|
|
143716
143801
|
["stale_reduce_stripped_ids", ""],
|
|
143802
|
+
["processed_image_stripped_ids", ""],
|
|
143717
143803
|
["memory_block_cache", ""],
|
|
143718
143804
|
["memory_block_ids", ""],
|
|
143719
143805
|
["compaction_marker_state", ""],
|
|
@@ -143758,7 +143844,7 @@ function healNullIntegerColumns(db) {
|
|
|
143758
143844
|
}
|
|
143759
143845
|
}
|
|
143760
143846
|
function ensureColumn(db, table, column, definition) {
|
|
143761
|
-
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_'(),[\]\s]+$/i.test(definition)) {
|
|
143847
|
+
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_"'(),[\]\s]+$/i.test(definition)) {
|
|
143762
143848
|
throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
|
|
143763
143849
|
}
|
|
143764
143850
|
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
@@ -143835,10 +143921,291 @@ function openDatabase(dbPathOrOptions) {
|
|
|
143835
143921
|
}
|
|
143836
143922
|
}
|
|
143837
143923
|
|
|
143924
|
+
// ../plugin/src/features/magic-context/workspaces.ts
|
|
143925
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
143926
|
+
|
|
143927
|
+
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
143928
|
+
var V2_MEMORY_CATEGORIES = [
|
|
143929
|
+
"PROJECT_RULES",
|
|
143930
|
+
"ARCHITECTURE",
|
|
143931
|
+
"CONSTRAINTS",
|
|
143932
|
+
"CONFIG_VALUES",
|
|
143933
|
+
"NAMING"
|
|
143934
|
+
];
|
|
143935
|
+
var PROMOTABLE_CATEGORIES = [
|
|
143936
|
+
"PROJECT_RULES",
|
|
143937
|
+
"ARCHITECTURE",
|
|
143938
|
+
"CONSTRAINTS",
|
|
143939
|
+
"CONFIG_VALUES",
|
|
143940
|
+
"NAMING",
|
|
143941
|
+
"ARCHITECTURE_DECISIONS",
|
|
143942
|
+
"CONFIG_DEFAULTS",
|
|
143943
|
+
"USER_PREFERENCES",
|
|
143944
|
+
"USER_DIRECTIVES",
|
|
143945
|
+
"ENVIRONMENT",
|
|
143946
|
+
"WORKFLOW_RULES",
|
|
143947
|
+
"KNOWN_ISSUES"
|
|
143948
|
+
];
|
|
143949
|
+
var CATEGORY_PRIORITY = [
|
|
143950
|
+
"PROJECT_RULES",
|
|
143951
|
+
"ARCHITECTURE",
|
|
143952
|
+
"CONSTRAINTS",
|
|
143953
|
+
"CONFIG_VALUES",
|
|
143954
|
+
"NAMING",
|
|
143955
|
+
"USER_DIRECTIVES",
|
|
143956
|
+
"USER_PREFERENCES",
|
|
143957
|
+
"CONFIG_DEFAULTS",
|
|
143958
|
+
"ARCHITECTURE_DECISIONS",
|
|
143959
|
+
"ENVIRONMENT",
|
|
143960
|
+
"WORKFLOW_RULES",
|
|
143961
|
+
"KNOWN_ISSUES"
|
|
143962
|
+
];
|
|
143963
|
+
var MEMORY_CATEGORY_ORDER_UNKNOWN = 99;
|
|
143964
|
+
var MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
143965
|
+
acc[category] = index;
|
|
143966
|
+
return acc;
|
|
143967
|
+
}, {});
|
|
143968
|
+
var MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
143969
|
+
var CATEGORY_DEFAULT_TTL = {
|
|
143970
|
+
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
143971
|
+
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
143972
|
+
};
|
|
143973
|
+
// ../plugin/src/features/magic-context/workspaces.ts
|
|
143974
|
+
var VALID_SHARE_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
143975
|
+
function tableExists(db, tableName) {
|
|
143976
|
+
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ? LIMIT 1").get(tableName);
|
|
143977
|
+
return Boolean(row);
|
|
143978
|
+
}
|
|
143979
|
+
function columnExists(db, tableName, columnName) {
|
|
143980
|
+
const rows = db.prepare(`PRAGMA table_info(${tableName})`).all();
|
|
143981
|
+
return rows.some((row) => row.name === columnName);
|
|
143982
|
+
}
|
|
143983
|
+
function uniqueSorted(values) {
|
|
143984
|
+
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
143985
|
+
}
|
|
143986
|
+
function placeholders(values) {
|
|
143987
|
+
return values.map(() => "?").join(", ");
|
|
143988
|
+
}
|
|
143989
|
+
function normalizeShareCategories(raw) {
|
|
143990
|
+
if (raw === null || raw === undefined)
|
|
143991
|
+
return null;
|
|
143992
|
+
if (typeof raw !== "string")
|
|
143993
|
+
return null;
|
|
143994
|
+
let parsed;
|
|
143995
|
+
try {
|
|
143996
|
+
parsed = JSON.parse(raw);
|
|
143997
|
+
} catch {
|
|
143998
|
+
return null;
|
|
143999
|
+
}
|
|
144000
|
+
if (!Array.isArray(parsed))
|
|
144001
|
+
return null;
|
|
144002
|
+
const categories = [];
|
|
144003
|
+
for (const value of parsed) {
|
|
144004
|
+
if (typeof value !== "string" || !VALID_SHARE_CATEGORIES.has(value)) {
|
|
144005
|
+
return null;
|
|
144006
|
+
}
|
|
144007
|
+
if (!categories.includes(value))
|
|
144008
|
+
categories.push(value);
|
|
144009
|
+
}
|
|
144010
|
+
return categories.sort((left, right) => left.localeCompare(right));
|
|
144011
|
+
}
|
|
144012
|
+
function selectWorkspaceShareCategories(db, identities) {
|
|
144013
|
+
const candidates = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
144014
|
+
if (candidates.length === 0 || !tableExists(db, "workspace_members") || !tableExists(db, "workspaces") || !columnExists(db, "workspaces", "share_categories")) {
|
|
144015
|
+
return null;
|
|
144016
|
+
}
|
|
144017
|
+
const row = db.prepare(`SELECT workspace.share_categories AS shareCategories
|
|
144018
|
+
FROM workspace_members AS member
|
|
144019
|
+
JOIN workspaces AS workspace ON workspace.id = member.workspace_id
|
|
144020
|
+
WHERE member.project_path IN (${placeholders(candidates)})
|
|
144021
|
+
ORDER BY workspace.id ASC
|
|
144022
|
+
LIMIT 1`).get(...candidates);
|
|
144023
|
+
return normalizeShareCategories(row?.shareCategories ?? null);
|
|
144024
|
+
}
|
|
144025
|
+
function resolveWorkspaceShareCategories(db, projectIdentity) {
|
|
144026
|
+
return selectWorkspaceShareCategories(db, [projectIdentity]);
|
|
144027
|
+
}
|
|
144028
|
+
function resolveWorkspaceIdentitySet(db, projectIdentity) {
|
|
144029
|
+
if (!tableExists(db, "workspace_members")) {
|
|
144030
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
144031
|
+
}
|
|
144032
|
+
const rows = db.prepare(`SELECT member.project_path AS identity, member.display_name AS displayName
|
|
144033
|
+
FROM workspace_members AS anchor
|
|
144034
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
144035
|
+
WHERE anchor.project_path = ?
|
|
144036
|
+
ORDER BY member.display_name ASC, member.project_path ASC`).all(projectIdentity);
|
|
144037
|
+
if (rows.length === 0) {
|
|
144038
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
144039
|
+
}
|
|
144040
|
+
const namesByIdentity = new Map;
|
|
144041
|
+
const identities = [];
|
|
144042
|
+
for (const row of rows) {
|
|
144043
|
+
if (typeof row.identity !== "string" || row.identity.length === 0)
|
|
144044
|
+
continue;
|
|
144045
|
+
if (identities.includes(row.identity))
|
|
144046
|
+
continue;
|
|
144047
|
+
identities.push(row.identity);
|
|
144048
|
+
if (typeof row.displayName === "string" && row.displayName.length > 0) {
|
|
144049
|
+
namesByIdentity.set(row.identity, row.displayName);
|
|
144050
|
+
}
|
|
144051
|
+
}
|
|
144052
|
+
return identities.length > 0 ? { identities, namesByIdentity } : { identities: [projectIdentity], namesByIdentity: new Map };
|
|
144053
|
+
}
|
|
144054
|
+
function expandWorkspaceIdentitySetWithAliases(db, identities) {
|
|
144055
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
144056
|
+
const expanded = new Set(canonical);
|
|
144057
|
+
const canonicalIdentityByStoredPath = new Map;
|
|
144058
|
+
for (const identity of canonical) {
|
|
144059
|
+
canonicalIdentityByStoredPath.set(identity, identity);
|
|
144060
|
+
}
|
|
144061
|
+
if (canonical.length === 0 || !tableExists(db, "v22_identity_rekey_map")) {
|
|
144062
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
144063
|
+
}
|
|
144064
|
+
const rows = db.prepare(`SELECT old_project_path AS oldProjectPath, new_project_path AS newProjectPath
|
|
144065
|
+
FROM v22_identity_rekey_map
|
|
144066
|
+
WHERE new_project_path IN (${placeholders(canonical)})
|
|
144067
|
+
ORDER BY old_project_path ASC`).all(...canonical);
|
|
144068
|
+
for (const row of rows) {
|
|
144069
|
+
if (typeof row.oldProjectPath !== "string" || typeof row.newProjectPath !== "string") {
|
|
144070
|
+
continue;
|
|
144071
|
+
}
|
|
144072
|
+
if (!canonicalIdentityByStoredPath.has(row.newProjectPath))
|
|
144073
|
+
continue;
|
|
144074
|
+
expanded.add(row.oldProjectPath);
|
|
144075
|
+
canonicalIdentityByStoredPath.set(row.oldProjectPath, row.newProjectPath);
|
|
144076
|
+
}
|
|
144077
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
144078
|
+
}
|
|
144079
|
+
function resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) {
|
|
144080
|
+
const direct = canonicalIdentityByStoredPath.get(storedProjectPath);
|
|
144081
|
+
if (direct)
|
|
144082
|
+
return direct;
|
|
144083
|
+
const normalized = normalizeStoredProjectPath(storedProjectPath);
|
|
144084
|
+
const normalizedDirect = canonicalIdentityByStoredPath.get(normalized);
|
|
144085
|
+
if (normalizedDirect)
|
|
144086
|
+
return normalizedDirect;
|
|
144087
|
+
if (memberIdentities.includes(normalized))
|
|
144088
|
+
return normalized;
|
|
144089
|
+
for (const identity of memberIdentities) {
|
|
144090
|
+
if (storedPathBelongsToIdentity(storedProjectPath, identity)) {
|
|
144091
|
+
return identity;
|
|
144092
|
+
}
|
|
144093
|
+
}
|
|
144094
|
+
return null;
|
|
144095
|
+
}
|
|
144096
|
+
function storedPathBelongsToWorkspace(storedProjectPath, memberIdentities, expandedIdentities, canonicalIdentityByStoredPath) {
|
|
144097
|
+
if (expandedIdentities.includes(storedProjectPath))
|
|
144098
|
+
return true;
|
|
144099
|
+
return resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) !== null;
|
|
144100
|
+
}
|
|
144101
|
+
function sourceNameForMemory(storedProjectPath, ownIdentity, memberIdentities, namesByIdentity, canonicalIdentityByStoredPath) {
|
|
144102
|
+
const canonicalIdentity = resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath);
|
|
144103
|
+
if (!canonicalIdentity || canonicalIdentity === ownIdentity)
|
|
144104
|
+
return;
|
|
144105
|
+
return namesByIdentity.get(canonicalIdentity);
|
|
144106
|
+
}
|
|
144107
|
+
function getEpochMap(db, identities) {
|
|
144108
|
+
if (identities.length === 0)
|
|
144109
|
+
return new Map;
|
|
144110
|
+
const rows = db.prepare(`SELECT project_path AS projectPath, project_memory_epoch AS epoch
|
|
144111
|
+
FROM project_state
|
|
144112
|
+
WHERE project_path IN (${placeholders(identities)})`).all(...identities);
|
|
144113
|
+
const epochs = new Map;
|
|
144114
|
+
for (const row of rows) {
|
|
144115
|
+
if (typeof row.projectPath !== "string" || typeof row.epoch !== "number")
|
|
144116
|
+
continue;
|
|
144117
|
+
epochs.set(row.projectPath, row.epoch);
|
|
144118
|
+
}
|
|
144119
|
+
return epochs;
|
|
144120
|
+
}
|
|
144121
|
+
function computeWorkspaceEpochFingerprint(db, identities) {
|
|
144122
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
144123
|
+
const epochs = getEpochMap(db, canonical);
|
|
144124
|
+
const shareCategories = selectWorkspaceShareCategories(db, canonical);
|
|
144125
|
+
const hash = createHash3("sha256");
|
|
144126
|
+
hash.update("share_categories", "utf8");
|
|
144127
|
+
hash.update("\x00");
|
|
144128
|
+
hash.update(shareCategories === null ? "ALL" : JSON.stringify(shareCategories), "utf8");
|
|
144129
|
+
hash.update(`
|
|
144130
|
+
`);
|
|
144131
|
+
for (const identity of canonical) {
|
|
144132
|
+
hash.update(identity, "utf8");
|
|
144133
|
+
hash.update("\x00");
|
|
144134
|
+
hash.update(String(epochs.get(identity) ?? 0), "utf8");
|
|
144135
|
+
hash.update(`
|
|
144136
|
+
`);
|
|
144137
|
+
}
|
|
144138
|
+
return hash.digest("hex");
|
|
144139
|
+
}
|
|
144140
|
+
function isInTransaction(db) {
|
|
144141
|
+
const candidate = db;
|
|
144142
|
+
return candidate.inTransaction === true || candidate.isTransaction === true;
|
|
144143
|
+
}
|
|
144144
|
+
function workspaceMembersForIdentity(db, identity) {
|
|
144145
|
+
if (!tableExists(db, "workspace_members"))
|
|
144146
|
+
return [identity];
|
|
144147
|
+
const rows = db.prepare(`SELECT member.project_path AS identity
|
|
144148
|
+
FROM workspace_members AS anchor
|
|
144149
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
144150
|
+
WHERE anchor.project_path = ?
|
|
144151
|
+
ORDER BY member.project_path ASC`).all(identity);
|
|
144152
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((value) => value.length > 0);
|
|
144153
|
+
return identities.length > 0 ? uniqueSorted(identities) : [identity];
|
|
144154
|
+
}
|
|
144155
|
+
function bumpEpochRows(db, identities, now) {
|
|
144156
|
+
const stmt = db.prepare(`INSERT INTO project_state
|
|
144157
|
+
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
144158
|
+
VALUES (?, 1, 0, ?)
|
|
144159
|
+
ON CONFLICT(project_path) DO UPDATE SET
|
|
144160
|
+
project_memory_epoch = project_memory_epoch + 1,
|
|
144161
|
+
updated_at = excluded.updated_at`);
|
|
144162
|
+
for (const identity of uniqueSorted(identities)) {
|
|
144163
|
+
stmt.run(identity, now);
|
|
144164
|
+
}
|
|
144165
|
+
}
|
|
144166
|
+
function bumpEpochsForWorkspaceMembers(db, identity, now = Date.now()) {
|
|
144167
|
+
const run = () => bumpEpochRows(db, workspaceMembersForIdentity(db, identity), now);
|
|
144168
|
+
if (isInTransaction(db)) {
|
|
144169
|
+
run();
|
|
144170
|
+
return;
|
|
144171
|
+
}
|
|
144172
|
+
db.exec("BEGIN IMMEDIATE");
|
|
144173
|
+
try {
|
|
144174
|
+
run();
|
|
144175
|
+
db.exec("COMMIT");
|
|
144176
|
+
} catch (error) {
|
|
144177
|
+
try {
|
|
144178
|
+
db.exec("ROLLBACK");
|
|
144179
|
+
} catch {}
|
|
144180
|
+
throw error;
|
|
144181
|
+
}
|
|
144182
|
+
}
|
|
144183
|
+
function bumpEpochsForWorkspaceMemberSet(db, identities, now = Date.now()) {
|
|
144184
|
+
const run = () => bumpEpochRows(db, identities, now);
|
|
144185
|
+
if (isInTransaction(db)) {
|
|
144186
|
+
run();
|
|
144187
|
+
return;
|
|
144188
|
+
}
|
|
144189
|
+
db.exec("BEGIN IMMEDIATE");
|
|
144190
|
+
try {
|
|
144191
|
+
run();
|
|
144192
|
+
db.exec("COMMIT");
|
|
144193
|
+
} catch (error) {
|
|
144194
|
+
try {
|
|
144195
|
+
db.exec("ROLLBACK");
|
|
144196
|
+
} catch {}
|
|
144197
|
+
throw error;
|
|
144198
|
+
}
|
|
144199
|
+
}
|
|
144200
|
+
|
|
143838
144201
|
// ../plugin/src/features/magic-context/migrations.ts
|
|
143839
|
-
function
|
|
144202
|
+
function tableExists2(db, name2) {
|
|
143840
144203
|
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name2));
|
|
143841
144204
|
}
|
|
144205
|
+
function columnExists2(db, table, column) {
|
|
144206
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
144207
|
+
return rows.some((row) => row.name === column);
|
|
144208
|
+
}
|
|
143842
144209
|
var MIGRATIONS = [
|
|
143843
144210
|
{
|
|
143844
144211
|
version: 1,
|
|
@@ -144297,9 +144664,9 @@ var MIGRATIONS = [
|
|
|
144297
144664
|
version: 22,
|
|
144298
144665
|
description: "v2.0 cache architecture schema foundation",
|
|
144299
144666
|
up: (db) => {
|
|
144300
|
-
const hasSessionMetaTable =
|
|
144301
|
-
const hasCompartmentsTable =
|
|
144302
|
-
const hasMemoriesTable =
|
|
144667
|
+
const hasSessionMetaTable = tableExists2(db, "session_meta");
|
|
144668
|
+
const hasCompartmentsTable = tableExists2(db, "compartments");
|
|
144669
|
+
const hasMemoriesTable = tableExists2(db, "memories");
|
|
144303
144670
|
if (hasSessionMetaTable) {
|
|
144304
144671
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
144305
144672
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
@@ -144324,7 +144691,7 @@ var MIGRATIONS = [
|
|
|
144324
144691
|
ensureColumn(db, "compartments", "p1_embedding_model_id", "TEXT");
|
|
144325
144692
|
ensureColumn(db, "compartments", "legacy", "INTEGER NOT NULL DEFAULT 0");
|
|
144326
144693
|
}
|
|
144327
|
-
const hasRecompCompartmentsTable =
|
|
144694
|
+
const hasRecompCompartmentsTable = tableExists2(db, "recomp_compartments");
|
|
144328
144695
|
if (hasRecompCompartmentsTable) {
|
|
144329
144696
|
ensureColumn(db, "recomp_compartments", "p1", "TEXT");
|
|
144330
144697
|
ensureColumn(db, "recomp_compartments", "p2", "TEXT");
|
|
@@ -144635,6 +145002,156 @@ var MIGRATIONS = [
|
|
|
144635
145002
|
db.prepare("UPDATE session_meta SET force_emergency_bypass_used = 0 WHERE force_emergency_bypass_used IS NULL").run();
|
|
144636
145003
|
db.prepare("UPDATE session_meta SET last_usage_context_limit = 0 WHERE last_usage_context_limit IS NULL").run();
|
|
144637
145004
|
}
|
|
145005
|
+
},
|
|
145006
|
+
{
|
|
145007
|
+
version: 33,
|
|
145008
|
+
description: "Compartment chunk embeddings for semantic message-history search",
|
|
145009
|
+
up: (db) => {
|
|
145010
|
+
db.exec(`
|
|
145011
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
145012
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
145013
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
145014
|
+
session_id TEXT NOT NULL,
|
|
145015
|
+
project_path TEXT NOT NULL,
|
|
145016
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
145017
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
145018
|
+
start_ordinal INTEGER NOT NULL,
|
|
145019
|
+
end_ordinal INTEGER NOT NULL,
|
|
145020
|
+
chunk_hash TEXT NOT NULL,
|
|
145021
|
+
model_id TEXT NOT NULL,
|
|
145022
|
+
dims INTEGER NOT NULL,
|
|
145023
|
+
vector BLOB NOT NULL,
|
|
145024
|
+
created_at INTEGER NOT NULL,
|
|
145025
|
+
UNIQUE(compartment_id, window_index)
|
|
145026
|
+
);
|
|
145027
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session
|
|
145028
|
+
ON compartment_chunk_embeddings(session_id);
|
|
145029
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model
|
|
145030
|
+
ON compartment_chunk_embeddings(project_path, model_id);
|
|
145031
|
+
`);
|
|
145032
|
+
}
|
|
145033
|
+
},
|
|
145034
|
+
{
|
|
145035
|
+
version: 34,
|
|
145036
|
+
description: "workspace tables and m[0] workspace fingerprint cache reset",
|
|
145037
|
+
up: (db) => {
|
|
145038
|
+
db.exec(`
|
|
145039
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
145040
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
145041
|
+
name TEXT NOT NULL UNIQUE,
|
|
145042
|
+
created_at INTEGER NOT NULL,
|
|
145043
|
+
updated_at INTEGER NOT NULL
|
|
145044
|
+
);
|
|
145045
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
145046
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
145047
|
+
project_path TEXT NOT NULL,
|
|
145048
|
+
display_name TEXT NOT NULL,
|
|
145049
|
+
display_path TEXT NOT NULL,
|
|
145050
|
+
added_at INTEGER NOT NULL,
|
|
145051
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
145052
|
+
);
|
|
145053
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique
|
|
145054
|
+
ON workspace_members(project_path);
|
|
145055
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name
|
|
145056
|
+
ON workspace_members(workspace_id, display_name);
|
|
145057
|
+
`);
|
|
145058
|
+
const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
|
|
145059
|
+
if (!hasSessionMeta)
|
|
145060
|
+
return;
|
|
145061
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
145062
|
+
const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
|
|
145063
|
+
const clears = [
|
|
145064
|
+
["cached_m0_bytes", null],
|
|
145065
|
+
["cached_m1_bytes", null],
|
|
145066
|
+
["cached_m0_project_memory_epoch", null],
|
|
145067
|
+
["cached_m0_workspace_fingerprint", null],
|
|
145068
|
+
["cached_m0_project_user_profile_version", null],
|
|
145069
|
+
["cached_m0_max_compartment_seq", null],
|
|
145070
|
+
["cached_m0_max_memory_id", null],
|
|
145071
|
+
["cached_m0_max_mutation_id", null],
|
|
145072
|
+
["cached_m0_max_memory_mutation_id", null],
|
|
145073
|
+
["cached_m0_project_docs_hash", null],
|
|
145074
|
+
["cached_m0_materialized_at", null],
|
|
145075
|
+
["cached_m0_session_facts_version", null],
|
|
145076
|
+
["cached_m0_upgrade_state", null],
|
|
145077
|
+
["cached_m0_system_hash", null],
|
|
145078
|
+
["cached_m0_tool_set_hash", null],
|
|
145079
|
+
["cached_m0_model_key", null],
|
|
145080
|
+
["cached_m0_last_baseline_end_message_id", null],
|
|
145081
|
+
["memory_block_cache", ""],
|
|
145082
|
+
["memory_block_ids", ""],
|
|
145083
|
+
["memory_block_count", 0]
|
|
145084
|
+
];
|
|
145085
|
+
const setClauses = [];
|
|
145086
|
+
const values = [];
|
|
145087
|
+
for (const [column, value] of clears) {
|
|
145088
|
+
if (!columns.has(column))
|
|
145089
|
+
continue;
|
|
145090
|
+
setClauses.push(`${column} = ?`);
|
|
145091
|
+
values.push(value);
|
|
145092
|
+
}
|
|
145093
|
+
if (setClauses.length > 0) {
|
|
145094
|
+
db.prepare(`UPDATE session_meta SET ${setClauses.join(", ")}`).run(...values);
|
|
145095
|
+
}
|
|
145096
|
+
}
|
|
145097
|
+
},
|
|
145098
|
+
{
|
|
145099
|
+
version: 35,
|
|
145100
|
+
description: "workspace per-category share defaults and epoch refresh",
|
|
145101
|
+
up: (db) => {
|
|
145102
|
+
db.exec(`
|
|
145103
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
145104
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
145105
|
+
name TEXT NOT NULL UNIQUE,
|
|
145106
|
+
created_at INTEGER NOT NULL,
|
|
145107
|
+
updated_at INTEGER NOT NULL,
|
|
145108
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
145109
|
+
);
|
|
145110
|
+
`);
|
|
145111
|
+
if (!columnExists2(db, "workspaces", "share_categories")) {
|
|
145112
|
+
db.exec(`ALTER TABLE workspaces ADD COLUMN share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
145113
|
+
}
|
|
145114
|
+
db.prepare(`UPDATE workspaces
|
|
145115
|
+
SET share_categories = '["CONSTRAINTS"]'
|
|
145116
|
+
WHERE share_categories IS NULL OR share_categories = ''`).run();
|
|
145117
|
+
if (!tableExists2(db, "workspace_members"))
|
|
145118
|
+
return;
|
|
145119
|
+
const rows = db.prepare(`SELECT DISTINCT project_path AS identity
|
|
145120
|
+
FROM workspace_members
|
|
145121
|
+
WHERE project_path IS NOT NULL AND project_path <> ''
|
|
145122
|
+
ORDER BY project_path ASC`).all();
|
|
145123
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((identity) => identity.length > 0);
|
|
145124
|
+
if (identities.length > 0) {
|
|
145125
|
+
bumpEpochsForWorkspaceMemberSet(db, identities, Date.now());
|
|
145126
|
+
}
|
|
145127
|
+
}
|
|
145128
|
+
},
|
|
145129
|
+
{
|
|
145130
|
+
version: 36,
|
|
145131
|
+
description: "session project ownership map for compartment chunk backfill scoping",
|
|
145132
|
+
up: (db) => {
|
|
145133
|
+
db.exec(`
|
|
145134
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
145135
|
+
session_id TEXT NOT NULL,
|
|
145136
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
145137
|
+
project_path TEXT NOT NULL,
|
|
145138
|
+
updated_at INTEGER NOT NULL,
|
|
145139
|
+
PRIMARY KEY(session_id, harness)
|
|
145140
|
+
);
|
|
145141
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
145142
|
+
ON session_projects(project_path);
|
|
145143
|
+
`);
|
|
145144
|
+
const hasChunkTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='compartment_chunk_embeddings'").get();
|
|
145145
|
+
if (hasChunkTable) {
|
|
145146
|
+
db.exec(`
|
|
145147
|
+
INSERT OR IGNORE INTO session_projects (session_id, harness, project_path, updated_at)
|
|
145148
|
+
SELECT session_id, harness, MIN(project_path), 0
|
|
145149
|
+
FROM compartment_chunk_embeddings
|
|
145150
|
+
GROUP BY session_id, harness
|
|
145151
|
+
HAVING COUNT(DISTINCT project_path) = 1;
|
|
145152
|
+
`);
|
|
145153
|
+
}
|
|
145154
|
+
}
|
|
144638
145155
|
}
|
|
144639
145156
|
];
|
|
144640
145157
|
var LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
@@ -144704,7 +145221,7 @@ function runMigrations(db) {
|
|
|
144704
145221
|
log(`[migrations] schema version now: ${MIGRATIONS[MIGRATIONS.length - 1].version}`);
|
|
144705
145222
|
}
|
|
144706
145223
|
// ../plugin/src/features/magic-context/project-docs-hash.ts
|
|
144707
|
-
import { createHash as
|
|
145224
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
144708
145225
|
import { lstatSync, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
144709
145226
|
import path4 from "node:path";
|
|
144710
145227
|
var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
|
|
@@ -144802,7 +145319,7 @@ function hashCanonicalPieces(hashPieces) {
|
|
|
144802
145319
|
if (hashPieces.length === 0) {
|
|
144803
145320
|
return "";
|
|
144804
145321
|
}
|
|
144805
|
-
return
|
|
145322
|
+
return createHash4("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
|
|
144806
145323
|
}
|
|
144807
145324
|
function readProjectDocsCanonical(projectDirectory) {
|
|
144808
145325
|
const canonicalDirectory = path4.resolve(projectDirectory);
|
|
@@ -144908,18 +145425,13 @@ function getMemoryMutation(db, id) {
|
|
|
144908
145425
|
WHERE id = ?`).get(id);
|
|
144909
145426
|
return row ? toMemoryMutation(row) : null;
|
|
144910
145427
|
}
|
|
144911
|
-
function
|
|
144912
|
-
|
|
144913
|
-
|
|
144914
|
-
|
|
144915
|
-
|
|
144916
|
-
|
|
144917
|
-
|
|
144918
|
-
FROM memory_mutation_log
|
|
144919
|
-
WHERE project_path = ?
|
|
144920
|
-
AND id > ?
|
|
144921
|
-
AND target_memory_id IN (${placeholders})
|
|
144922
|
-
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
145428
|
+
function uniqueProjectPaths(projectPaths) {
|
|
145429
|
+
return [...new Set(projectPaths.filter((path5) => path5.length > 0))];
|
|
145430
|
+
}
|
|
145431
|
+
function placeholders2(values) {
|
|
145432
|
+
return values.map(() => "?").join(", ");
|
|
145433
|
+
}
|
|
145434
|
+
function coalesceMutations(rows) {
|
|
144923
145435
|
const chosenByTarget = new Map;
|
|
144924
145436
|
for (const dbRow of rows) {
|
|
144925
145437
|
const candidate = toMemoryMutation(dbRow);
|
|
@@ -144940,10 +145452,54 @@ function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds
|
|
|
144940
145452
|
}
|
|
144941
145453
|
return [...chosenByTarget.values()].sort((left, right) => left.id - right.id);
|
|
144942
145454
|
}
|
|
145455
|
+
function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds) {
|
|
145456
|
+
if (renderedMemoryIds.length === 0)
|
|
145457
|
+
return [];
|
|
145458
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
145459
|
+
const placeholders3 = uniqueIds.map(() => "?").join(", ");
|
|
145460
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
145461
|
+
superseded_by_id, category, new_content, queued_at
|
|
145462
|
+
FROM memory_mutation_log
|
|
145463
|
+
WHERE project_path = ?
|
|
145464
|
+
AND id > ?
|
|
145465
|
+
AND target_memory_id IN (${placeholders3})
|
|
145466
|
+
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
145467
|
+
return coalesceMutations(rows);
|
|
145468
|
+
}
|
|
145469
|
+
function getMemoryMutationsForRenderByProjects(db, projectPaths, afterId, renderedMemoryIds) {
|
|
145470
|
+
if (renderedMemoryIds.length === 0)
|
|
145471
|
+
return [];
|
|
145472
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
145473
|
+
if (identities.length === 0)
|
|
145474
|
+
return [];
|
|
145475
|
+
if (identities.length === 1) {
|
|
145476
|
+
return getMemoryMutationsForRender(db, identities[0], afterId, renderedMemoryIds);
|
|
145477
|
+
}
|
|
145478
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
145479
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
145480
|
+
superseded_by_id, category, new_content, queued_at
|
|
145481
|
+
FROM memory_mutation_log
|
|
145482
|
+
WHERE project_path IN (${placeholders2(identities)})
|
|
145483
|
+
AND id > ?
|
|
145484
|
+
AND target_memory_id IN (${placeholders2(uniqueIds)})
|
|
145485
|
+
ORDER BY id ASC`).all(...identities, afterId ?? 0, ...uniqueIds);
|
|
145486
|
+
return coalesceMutations(rows);
|
|
145487
|
+
}
|
|
144943
145488
|
function getMaxMemoryMutationId(db, projectPath) {
|
|
144944
145489
|
const row = db.prepare("SELECT MAX(id) AS max_id FROM memory_mutation_log WHERE project_path = ?").get(projectPath);
|
|
144945
145490
|
return row?.max_id ?? null;
|
|
144946
145491
|
}
|
|
145492
|
+
function getMaxMemoryMutationIdForProjects(db, projectPaths) {
|
|
145493
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
145494
|
+
if (identities.length === 0)
|
|
145495
|
+
return null;
|
|
145496
|
+
if (identities.length === 1)
|
|
145497
|
+
return getMaxMemoryMutationId(db, identities[0]);
|
|
145498
|
+
const row = db.prepare(`SELECT MAX(id) AS max_id
|
|
145499
|
+
FROM memory_mutation_log
|
|
145500
|
+
WHERE project_path IN (${placeholders2(identities)})`).get(...identities);
|
|
145501
|
+
return row?.max_id ?? null;
|
|
145502
|
+
}
|
|
144947
145503
|
// ../plugin/src/features/magic-context/storage-meta-persisted.ts
|
|
144948
145504
|
init_logger();
|
|
144949
145505
|
var CAS_RETRY_LIMIT = 5;
|
|
@@ -145789,9 +146345,9 @@ function buildStatusClause(status) {
|
|
|
145789
146345
|
if (statuses.length === 0) {
|
|
145790
146346
|
return null;
|
|
145791
146347
|
}
|
|
145792
|
-
const
|
|
146348
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
145793
146349
|
return {
|
|
145794
|
-
sql: `status IN (${
|
|
146350
|
+
sql: `status IN (${placeholders3})`,
|
|
145795
146351
|
params: statuses
|
|
145796
146352
|
};
|
|
145797
146353
|
}
|
|
@@ -145987,19 +146543,6 @@ function getProjectState(db, projectPath) {
|
|
|
145987
146543
|
WHERE project_path = ?`).get(projectPath);
|
|
145988
146544
|
return row ? toProjectState(row) : null;
|
|
145989
146545
|
}
|
|
145990
|
-
function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
|
|
145991
|
-
db.prepare(`INSERT INTO project_state
|
|
145992
|
-
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
145993
|
-
VALUES (?, 1, 0, ?)
|
|
145994
|
-
ON CONFLICT(project_path) DO UPDATE SET
|
|
145995
|
-
project_memory_epoch = project_memory_epoch + 1,
|
|
145996
|
-
updated_at = excluded.updated_at`).run(projectPath, now);
|
|
145997
|
-
const state = getProjectState(db, projectPath);
|
|
145998
|
-
if (!state) {
|
|
145999
|
-
throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
|
|
146000
|
-
}
|
|
146001
|
-
return state;
|
|
146002
|
-
}
|
|
146003
146546
|
function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PROJECT_PATH, now = Date.now()) {
|
|
146004
146547
|
db.prepare(`INSERT INTO project_state
|
|
146005
146548
|
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
@@ -146033,8 +146576,8 @@ function getSourceContents(db, sessionId, tagIds) {
|
|
|
146033
146576
|
if (tagIds.length === 0) {
|
|
146034
146577
|
return new Map;
|
|
146035
146578
|
}
|
|
146036
|
-
const
|
|
146037
|
-
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${
|
|
146579
|
+
const placeholders3 = tagIds.map(() => "?").join(", ");
|
|
146580
|
+
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${placeholders3})`).all(sessionId, ...tagIds).filter(isSourceContentRow);
|
|
146038
146581
|
const sources = new Map;
|
|
146039
146582
|
for (const row of rows) {
|
|
146040
146583
|
sources.set(row.tag_id, row.content);
|
|
@@ -146125,15 +146668,22 @@ function ownerMessageIdForTagRow(row) {
|
|
|
146125
146668
|
}
|
|
146126
146669
|
return row.message_id.replace(CONTENT_ID_SUFFIX, "");
|
|
146127
146670
|
}
|
|
146128
|
-
function getActiveTagTokenAggregate(db, sessionId) {
|
|
146129
|
-
const
|
|
146671
|
+
function getActiveTagTokenAggregate(db, sessionId, protectedTags = 0) {
|
|
146672
|
+
const toolOutputExpr = protectedTags > 0 ? `COALESCE(SUM(CASE WHEN type = 'tool' AND tag_number < (
|
|
146673
|
+
SELECT tag_number FROM tags
|
|
146674
|
+
WHERE session_id = ? AND status = 'active'
|
|
146675
|
+
ORDER BY tag_number DESC LIMIT 1 OFFSET ?
|
|
146676
|
+
) THEN COALESCE(token_count, 0) ELSE 0 END), 0)` : `COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0)`;
|
|
146677
|
+
const sql = `SELECT
|
|
146130
146678
|
COALESCE(SUM(CASE WHEN type != 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0)
|
|
146131
146679
|
+ COALESCE(SUM(COALESCE(reasoning_token_count, 0)), 0) AS conversation,
|
|
146132
146680
|
COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) + COALESCE(input_token_count, 0) ELSE 0 END), 0) AS tool_call,
|
|
146133
|
-
|
|
146681
|
+
${toolOutputExpr} AS tool_output,
|
|
146134
146682
|
COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
|
|
146135
146683
|
FROM tags
|
|
146136
|
-
WHERE session_id = ? AND status = 'active'
|
|
146684
|
+
WHERE session_id = ? AND status = 'active'`;
|
|
146685
|
+
const params = protectedTags > 0 ? [sessionId, protectedTags - 1, sessionId] : [sessionId];
|
|
146686
|
+
const row = db.prepare(sql).get(...params);
|
|
146137
146687
|
return {
|
|
146138
146688
|
conversation: row?.conversation ?? 0,
|
|
146139
146689
|
toolCall: row?.tool_call ?? 0,
|
|
@@ -146324,8 +146874,8 @@ function getTagsByNumbers(db, sessionId, tagNumbers) {
|
|
|
146324
146874
|
}
|
|
146325
146875
|
return all;
|
|
146326
146876
|
}
|
|
146327
|
-
const
|
|
146328
|
-
const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${
|
|
146877
|
+
const placeholders3 = tagNumbers.map(() => "?").join(",");
|
|
146878
|
+
const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${placeholders3}) ORDER BY tag_number ASC, id ASC`).all(sessionId, ...tagNumbers).filter(isTagRow);
|
|
146329
146879
|
return rows.map(toTagEntry);
|
|
146330
146880
|
}
|
|
146331
146881
|
var getToolTagNumberByOwnerStatements = new WeakMap;
|
|
@@ -146395,7 +146945,7 @@ var ERROR_CLASSES = new Set([
|
|
|
146395
146945
|
]);
|
|
146396
146946
|
// ../plugin/src/features/magic-context/v22-deferred-backfill.ts
|
|
146397
146947
|
init_logger();
|
|
146398
|
-
import { createHash as
|
|
146948
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
146399
146949
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
146400
146950
|
import path5 from "node:path";
|
|
146401
146951
|
var BATCH_SIZE = 25;
|
|
@@ -146449,7 +146999,7 @@ function computeLegacyRustDirIdentity(rawProjectPath) {
|
|
|
146449
146999
|
} catch {
|
|
146450
147000
|
canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
|
|
146451
147001
|
}
|
|
146452
|
-
return `dir:${
|
|
147002
|
+
return `dir:${createHash5("sha256").update(canonical, "utf8").digest("hex")}`;
|
|
146453
147003
|
}
|
|
146454
147004
|
function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
|
|
146455
147005
|
db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
|
|
@@ -147007,7 +147557,7 @@ function clearNoteNudgeTriggerOnly(db, sessionId) {
|
|
|
147007
147557
|
}
|
|
147008
147558
|
|
|
147009
147559
|
// ../plugin/src/hooks/magic-context/todo-view.ts
|
|
147010
|
-
import { createHash as
|
|
147560
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
147011
147561
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
147012
147562
|
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
147013
147563
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
@@ -147052,7 +147602,7 @@ function buildSyntheticTodoPart(stateJson) {
|
|
|
147052
147602
|
};
|
|
147053
147603
|
}
|
|
147054
147604
|
function computeSyntheticCallId(stateJson) {
|
|
147055
|
-
const hash =
|
|
147605
|
+
const hash = createHash6("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
147056
147606
|
return `${SYNTHETIC_CALL_ID_PREFIX}${hash}`;
|
|
147057
147607
|
}
|
|
147058
147608
|
function parseTodoState(stateJson) {
|
|
@@ -147193,13 +147743,13 @@ async function maybeSendUpgradeReminder(deps, sessionId) {
|
|
|
147193
147743
|
init_data_path();
|
|
147194
147744
|
import * as fs2 from "node:fs";
|
|
147195
147745
|
import * as path6 from "node:path";
|
|
147196
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
147746
|
+
var ANNOUNCEMENT_VERSION = "0.24.0";
|
|
147197
147747
|
var ANNOUNCEMENT_FEATURES = [
|
|
147198
|
-
"
|
|
147199
|
-
"
|
|
147200
|
-
"
|
|
147201
|
-
"
|
|
147202
|
-
"
|
|
147748
|
+
"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).",
|
|
147749
|
+
"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.",
|
|
147750
|
+
"Pi: fixed sessions overflowing the model context while still showing moderate usage — Pi now sheds context before a tool-heavy turn overflows.",
|
|
147751
|
+
"Fewer prompt-cache busts: doc edits, processed screenshots, and a rebuild-then-bust-again case no longer re-bill large prompt prefixes.",
|
|
147752
|
+
"Setup wizard now lists your actual models with type-ahead instead of fixed recommendations, and explains the historian/dreamer roles (issue #144). Plus a GitHub Copilot tool-pairing fix (#135)."
|
|
147203
147753
|
];
|
|
147204
147754
|
var ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU";
|
|
147205
147755
|
var STATE_FILENAME = "last_announced_version";
|
|
@@ -149082,7 +149632,7 @@ function isEmbeddingRow(row) {
|
|
|
149082
149632
|
if (row === null || typeof row !== "object")
|
|
149083
149633
|
return false;
|
|
149084
149634
|
const candidate = row;
|
|
149085
|
-
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding);
|
|
149635
|
+
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding) && (candidate.modelId === null || typeof candidate.modelId === "string");
|
|
149086
149636
|
}
|
|
149087
149637
|
function toFloat32Array(blob) {
|
|
149088
149638
|
if (blob instanceof Uint8Array) {
|
|
@@ -149102,7 +149652,7 @@ function getSaveEmbeddingStatement(db) {
|
|
|
149102
149652
|
function getLoadAllEmbeddingsStatement(db) {
|
|
149103
149653
|
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
149104
149654
|
if (!stmt) {
|
|
149105
|
-
stmt = db.prepare("SELECT memory_embeddings.memory_id AS memoryId, memory_embeddings.embedding AS embedding FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? ORDER BY memory_embeddings.memory_id ASC");
|
|
149655
|
+
stmt = db.prepare("SELECT memory_embeddings.memory_id AS memoryId, memory_embeddings.embedding AS embedding, memory_embeddings.model_id AS modelId FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? ORDER BY memory_embeddings.memory_id ASC");
|
|
149106
149656
|
loadAllEmbeddingsStatements.set(db, stmt);
|
|
149107
149657
|
}
|
|
149108
149658
|
return stmt;
|
|
@@ -149131,7 +149681,10 @@ function loadAllEmbeddings(db, projectPath) {
|
|
|
149131
149681
|
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath).filter(isEmbeddingRow);
|
|
149132
149682
|
const embeddings = new Map;
|
|
149133
149683
|
for (const row of rows) {
|
|
149134
|
-
embeddings.set(row.memoryId,
|
|
149684
|
+
embeddings.set(row.memoryId, {
|
|
149685
|
+
embedding: toFloat32Array(row.embedding),
|
|
149686
|
+
modelId: row.modelId
|
|
149687
|
+
});
|
|
149135
149688
|
}
|
|
149136
149689
|
return embeddings;
|
|
149137
149690
|
}
|
|
@@ -149182,13 +149735,13 @@ function invalidateMemory(projectPath, memoryId) {
|
|
|
149182
149735
|
}
|
|
149183
149736
|
|
|
149184
149737
|
// ../plugin/src/features/magic-context/memory/normalize-hash.ts
|
|
149185
|
-
import { createHash as
|
|
149738
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
149186
149739
|
function normalizeMemoryContent(content) {
|
|
149187
149740
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
149188
149741
|
}
|
|
149189
149742
|
function computeNormalizedHash(content) {
|
|
149190
149743
|
const normalized = normalizeMemoryContent(content);
|
|
149191
|
-
return
|
|
149744
|
+
return createHash7("md5").update(normalized).digest("hex");
|
|
149192
149745
|
}
|
|
149193
149746
|
|
|
149194
149747
|
// ../plugin/src/features/magic-context/memory/storage-memory.ts
|
|
@@ -149376,8 +149929,8 @@ function getMemoriesByProjectStatement(db, statuses) {
|
|
|
149376
149929
|
}
|
|
149377
149930
|
let stmt = statements.get(db);
|
|
149378
149931
|
if (!stmt) {
|
|
149379
|
-
const
|
|
149380
|
-
stmt = db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories WHERE project_path = ? AND status IN (${
|
|
149932
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
149933
|
+
stmt = db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories WHERE project_path = ? AND status IN (${placeholders3}) AND (expires_at IS NULL OR expires_at > ?) ORDER BY category ASC, updated_at DESC, id ASC`);
|
|
149381
149934
|
statements.set(db, stmt);
|
|
149382
149935
|
}
|
|
149383
149936
|
return stmt;
|
|
@@ -149522,6 +150075,97 @@ function getMemoriesByProject(db, projectPath, statuses = ["active", "permanent"
|
|
|
149522
150075
|
const rows = getMemoriesByProjectStatement(db, statuses).all(projectPath, ...statuses, expiryCutoff).filter(isMemoryRow);
|
|
149523
150076
|
return rows.map(toMemory);
|
|
149524
150077
|
}
|
|
150078
|
+
function sqlPlaceholders(values) {
|
|
150079
|
+
return values.map(() => "?").join(", ");
|
|
150080
|
+
}
|
|
150081
|
+
function uniqueValues(values) {
|
|
150082
|
+
return [...new Set(values.filter((value) => value.length > 0))];
|
|
150083
|
+
}
|
|
150084
|
+
function buildWorkspaceMemorySqlFilter(args) {
|
|
150085
|
+
if (args.shareCategories === null || args.shareCategories === undefined) {
|
|
150086
|
+
return { clause: "", params: [], active: false };
|
|
150087
|
+
}
|
|
150088
|
+
const identities = uniqueValues(args.identities);
|
|
150089
|
+
const identitySet = new Set(identities);
|
|
150090
|
+
const ownSet = new Set(uniqueValues(args.ownIdentities ?? []).filter((identity) => identitySet.has(identity)));
|
|
150091
|
+
const foreignIdentities = identities.filter((identity) => !ownSet.has(identity));
|
|
150092
|
+
if (foreignIdentities.length === 0) {
|
|
150093
|
+
return { clause: "", params: [], active: false };
|
|
150094
|
+
}
|
|
150095
|
+
const ownIdentities = identities.filter((identity) => ownSet.has(identity));
|
|
150096
|
+
const shareCategories = uniqueValues([...args.shareCategories]);
|
|
150097
|
+
const qualifier = args.tableName ? `${args.tableName}.` : "";
|
|
150098
|
+
const predicates = [];
|
|
150099
|
+
const params = [];
|
|
150100
|
+
if (ownIdentities.length > 0) {
|
|
150101
|
+
predicates.push(`${qualifier}project_path IN (${sqlPlaceholders(ownIdentities)})`);
|
|
150102
|
+
params.push(...ownIdentities);
|
|
150103
|
+
}
|
|
150104
|
+
if (foreignIdentities.length > 0 && shareCategories.length > 0) {
|
|
150105
|
+
predicates.push(`(${qualifier}project_path IN (${sqlPlaceholders(foreignIdentities)}) AND ${qualifier}category IN (${sqlPlaceholders(shareCategories)}))`);
|
|
150106
|
+
params.push(...foreignIdentities, ...shareCategories);
|
|
150107
|
+
}
|
|
150108
|
+
if (predicates.length === 0) {
|
|
150109
|
+
return { clause: " AND 0 = 1", params: [], active: true };
|
|
150110
|
+
}
|
|
150111
|
+
return { clause: ` AND (${predicates.join(" OR ")})`, params, active: true };
|
|
150112
|
+
}
|
|
150113
|
+
function getMemoriesByProjects(db, projectPaths, statuses = ["active", "permanent"], expiryCutoff = Date.now(), ownIdentities, shareCategories) {
|
|
150114
|
+
const identities = uniqueValues(projectPaths);
|
|
150115
|
+
if (identities.length === 0 || statuses.length === 0)
|
|
150116
|
+
return [];
|
|
150117
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
150118
|
+
identities,
|
|
150119
|
+
ownIdentities,
|
|
150120
|
+
shareCategories
|
|
150121
|
+
});
|
|
150122
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
150123
|
+
return getMemoriesByProject(db, identities[0], statuses, expiryCutoff);
|
|
150124
|
+
}
|
|
150125
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
150126
|
+
FROM memories
|
|
150127
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
150128
|
+
AND status IN (${sqlPlaceholders(statuses)})
|
|
150129
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
150130
|
+
ORDER BY category ASC, updated_at DESC, id ASC`).all(...identities, ...statuses, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
150131
|
+
return rows.map(toMemory);
|
|
150132
|
+
}
|
|
150133
|
+
function getMaxMemoryIdForProjects(db, projectPaths, ownIdentities, shareCategories) {
|
|
150134
|
+
const identities = uniqueValues(projectPaths);
|
|
150135
|
+
if (identities.length === 0)
|
|
150136
|
+
return 0;
|
|
150137
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
150138
|
+
identities,
|
|
150139
|
+
ownIdentities,
|
|
150140
|
+
shareCategories
|
|
150141
|
+
});
|
|
150142
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
150143
|
+
const row2 = db.prepare("SELECT COALESCE(MAX(id), 0) AS max_id FROM memories WHERE project_path = ?").get(identities[0]);
|
|
150144
|
+
return typeof row2?.max_id === "number" ? row2.max_id : 0;
|
|
150145
|
+
}
|
|
150146
|
+
const row = db.prepare(`SELECT COALESCE(MAX(id), 0) AS max_id
|
|
150147
|
+
FROM memories
|
|
150148
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})${sharingFilter.clause}`).get(...identities, ...sharingFilter.params);
|
|
150149
|
+
return typeof row?.max_id === "number" ? row.max_id : 0;
|
|
150150
|
+
}
|
|
150151
|
+
function readNewMemoriesForM1Union(db, projectPaths, afterId, expiryCutoff, ownIdentities, shareCategories) {
|
|
150152
|
+
const identities = uniqueValues(projectPaths);
|
|
150153
|
+
if (identities.length === 0)
|
|
150154
|
+
return [];
|
|
150155
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
150156
|
+
identities,
|
|
150157
|
+
ownIdentities,
|
|
150158
|
+
shareCategories
|
|
150159
|
+
});
|
|
150160
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
150161
|
+
FROM memories
|
|
150162
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
150163
|
+
AND id > ?
|
|
150164
|
+
AND status IN ('active', 'permanent')
|
|
150165
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
150166
|
+
ORDER BY ${MEMORY_CATEGORY_ORDER_SQL}, id ASC`).all(...identities, afterId, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
150167
|
+
return rows.map(toMemory);
|
|
150168
|
+
}
|
|
149525
150169
|
function getAllActiveMemoriesForMigration(db, projectPath) {
|
|
149526
150170
|
const rows = getActiveMemoriesNoExpiryStatement(db).all(projectPath).filter(isMemoryRow);
|
|
149527
150171
|
return rows.map(toMemory);
|
|
@@ -150043,8 +150687,8 @@ function getUserMemoryCandidates(db) {
|
|
|
150043
150687
|
function deleteUserMemoryCandidates(db, ids) {
|
|
150044
150688
|
if (ids.length === 0)
|
|
150045
150689
|
return;
|
|
150046
|
-
const
|
|
150047
|
-
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${
|
|
150690
|
+
const placeholders3 = ids.map(() => "?").join(",");
|
|
150691
|
+
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${placeholders3})`).run(...ids);
|
|
150048
150692
|
}
|
|
150049
150693
|
function insertUserMemory(db, content, sourceCandidateIds) {
|
|
150050
150694
|
const now = Date.now();
|
|
@@ -165534,7 +166178,8 @@ var BaseEmbeddingConfigSchema = exports_external.object({
|
|
|
165534
166178
|
endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
|
|
165535
166179
|
api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
|
|
165536
166180
|
input_type: exports_external.string().optional().describe("Optional input_type sent in the embedding request body. Required by some openai-compatible providers (e.g. NVIDIA NIM expects 'query' or 'passage'). Omitted from the request when unset."),
|
|
165537
|
-
truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset.")
|
|
166181
|
+
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."),
|
|
166182
|
+
max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
|
|
165538
166183
|
}).superRefine((data, ctx) => {
|
|
165539
166184
|
if (data.provider === "openai-compatible" && !data.endpoint?.trim()) {
|
|
165540
166185
|
ctx.addIssue({
|
|
@@ -165555,7 +166200,8 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
|
|
|
165555
166200
|
if (data.provider === "local") {
|
|
165556
166201
|
return {
|
|
165557
166202
|
provider: "local",
|
|
165558
|
-
model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
166203
|
+
model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
166204
|
+
...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
|
|
165559
166205
|
};
|
|
165560
166206
|
}
|
|
165561
166207
|
if (data.provider === "openai-compatible") {
|
|
@@ -165568,7 +166214,8 @@ var EmbeddingConfigSchema = BaseEmbeddingConfigSchema.transform((data) => {
|
|
|
165568
166214
|
endpoint: data.endpoint?.trim() ?? "",
|
|
165569
166215
|
...apiKey ? { api_key: apiKey } : {},
|
|
165570
166216
|
...inputType ? { input_type: inputType } : {},
|
|
165571
|
-
...truncate ? { truncate } : {}
|
|
166217
|
+
...truncate ? { truncate } : {},
|
|
166218
|
+
...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
|
|
165572
166219
|
};
|
|
165573
166220
|
}
|
|
165574
166221
|
return { provider: "off" };
|
|
@@ -165653,6 +166300,443 @@ var MagicContextConfigSchema = exports_external.object({
|
|
|
165653
166300
|
// ../plugin/src/features/magic-context/memory/embedding.ts
|
|
165654
166301
|
init_logger();
|
|
165655
166302
|
|
|
166303
|
+
// ../plugin/src/features/magic-context/compartment-chunk-embedding.ts
|
|
166304
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
166305
|
+
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512;
|
|
166306
|
+
var CHUNK_WINDOW_SAFETY_RATIO = 0.9;
|
|
166307
|
+
var loadFtsRowsStatements = new WeakMap;
|
|
166308
|
+
var existingHashStatements = new WeakMap;
|
|
166309
|
+
var existingHashByProjectStatements = new WeakMap;
|
|
166310
|
+
var deleteByCompartmentStatements = new WeakMap;
|
|
166311
|
+
var insertEmbeddingStatements = new WeakMap;
|
|
166312
|
+
var distinctModelStatements = new WeakMap;
|
|
166313
|
+
var clearProjectStatements = new WeakMap;
|
|
166314
|
+
var clearProjectModelStatements = new WeakMap;
|
|
166315
|
+
var searchRowsStatements = new WeakMap;
|
|
166316
|
+
var searchRowsByModelStatements = new WeakMap;
|
|
166317
|
+
var backfillCandidateStatements = new WeakMap;
|
|
166318
|
+
function getLoadFtsRowsStatement(db) {
|
|
166319
|
+
let stmt = loadFtsRowsStatements.get(db);
|
|
166320
|
+
if (!stmt) {
|
|
166321
|
+
stmt = db.prepare(`SELECT message_ordinal AS messageOrdinal, role, content
|
|
166322
|
+
FROM message_history_fts
|
|
166323
|
+
WHERE session_id = ?
|
|
166324
|
+
AND message_ordinal >= ?
|
|
166325
|
+
AND message_ordinal <= ?
|
|
166326
|
+
AND role IN ('user', 'assistant')
|
|
166327
|
+
ORDER BY message_ordinal ASC`);
|
|
166328
|
+
loadFtsRowsStatements.set(db, stmt);
|
|
166329
|
+
}
|
|
166330
|
+
return stmt;
|
|
166331
|
+
}
|
|
166332
|
+
function getExistingHashStatement(db, scopedToProject) {
|
|
166333
|
+
const map2 = scopedToProject ? existingHashByProjectStatements : existingHashStatements;
|
|
166334
|
+
let stmt = map2.get(db);
|
|
166335
|
+
if (!stmt) {
|
|
166336
|
+
stmt = db.prepare(`SELECT window_index AS windowIndex, chunk_hash AS chunkHash
|
|
166337
|
+
FROM compartment_chunk_embeddings
|
|
166338
|
+
WHERE compartment_id = ?
|
|
166339
|
+
AND model_id = ?
|
|
166340
|
+
${scopedToProject ? "AND project_path = ?" : ""}
|
|
166341
|
+
ORDER BY window_index ASC`);
|
|
166342
|
+
map2.set(db, stmt);
|
|
166343
|
+
}
|
|
166344
|
+
return stmt;
|
|
166345
|
+
}
|
|
166346
|
+
function getDeleteByCompartmentStatement(db) {
|
|
166347
|
+
let stmt = deleteByCompartmentStatements.get(db);
|
|
166348
|
+
if (!stmt) {
|
|
166349
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE compartment_id = ?");
|
|
166350
|
+
deleteByCompartmentStatements.set(db, stmt);
|
|
166351
|
+
}
|
|
166352
|
+
return stmt;
|
|
166353
|
+
}
|
|
166354
|
+
function getInsertEmbeddingStatement(db) {
|
|
166355
|
+
let stmt = insertEmbeddingStatements.get(db);
|
|
166356
|
+
if (!stmt) {
|
|
166357
|
+
stmt = db.prepare(`INSERT INTO compartment_chunk_embeddings (
|
|
166358
|
+
compartment_id, session_id, project_path, harness, window_index,
|
|
166359
|
+
start_ordinal, end_ordinal, chunk_hash, model_id, dims, vector, created_at
|
|
166360
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
166361
|
+
insertEmbeddingStatements.set(db, stmt);
|
|
166362
|
+
}
|
|
166363
|
+
return stmt;
|
|
166364
|
+
}
|
|
166365
|
+
function getDistinctModelStatement(db) {
|
|
166366
|
+
let stmt = distinctModelStatements.get(db);
|
|
166367
|
+
if (!stmt) {
|
|
166368
|
+
stmt = db.prepare(`SELECT DISTINCT model_id AS modelId
|
|
166369
|
+
FROM compartment_chunk_embeddings
|
|
166370
|
+
WHERE project_path = ?`);
|
|
166371
|
+
distinctModelStatements.set(db, stmt);
|
|
166372
|
+
}
|
|
166373
|
+
return stmt;
|
|
166374
|
+
}
|
|
166375
|
+
function getClearProjectStatement(db) {
|
|
166376
|
+
let stmt = clearProjectStatements.get(db);
|
|
166377
|
+
if (!stmt) {
|
|
166378
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ?");
|
|
166379
|
+
clearProjectStatements.set(db, stmt);
|
|
166380
|
+
}
|
|
166381
|
+
return stmt;
|
|
166382
|
+
}
|
|
166383
|
+
function getClearProjectModelStatement(db) {
|
|
166384
|
+
let stmt = clearProjectModelStatements.get(db);
|
|
166385
|
+
if (!stmt) {
|
|
166386
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ? AND model_id = ?");
|
|
166387
|
+
clearProjectModelStatements.set(db, stmt);
|
|
166388
|
+
}
|
|
166389
|
+
return stmt;
|
|
166390
|
+
}
|
|
166391
|
+
function getSearchRowsStatement(db, withModel) {
|
|
166392
|
+
const map2 = withModel ? searchRowsByModelStatements : searchRowsStatements;
|
|
166393
|
+
let stmt = map2.get(db);
|
|
166394
|
+
if (!stmt) {
|
|
166395
|
+
stmt = db.prepare(`SELECT e.compartment_id AS compartmentId,
|
|
166396
|
+
e.session_id AS sessionId,
|
|
166397
|
+
c.title AS title,
|
|
166398
|
+
c.start_message AS compartmentStart,
|
|
166399
|
+
c.end_message AS compartmentEnd,
|
|
166400
|
+
e.window_index AS windowIndex,
|
|
166401
|
+
e.start_ordinal AS windowStart,
|
|
166402
|
+
e.end_ordinal AS windowEnd,
|
|
166403
|
+
e.chunk_hash AS chunkHash,
|
|
166404
|
+
e.model_id AS modelId,
|
|
166405
|
+
e.dims AS dims,
|
|
166406
|
+
e.vector AS vector
|
|
166407
|
+
FROM compartment_chunk_embeddings e
|
|
166408
|
+
JOIN compartments c ON c.id = e.compartment_id
|
|
166409
|
+
WHERE e.session_id = ?
|
|
166410
|
+
AND e.project_path = ?
|
|
166411
|
+
${withModel ? "AND e.model_id = ?" : ""}
|
|
166412
|
+
ORDER BY e.compartment_id ASC, e.window_index ASC`);
|
|
166413
|
+
map2.set(db, stmt);
|
|
166414
|
+
}
|
|
166415
|
+
return stmt;
|
|
166416
|
+
}
|
|
166417
|
+
function isFinitePositiveInteger(value) {
|
|
166418
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
166419
|
+
}
|
|
166420
|
+
function normalizeCompartmentChunkMaxInputTokens(value) {
|
|
166421
|
+
if (!isFinitePositiveInteger(value)) {
|
|
166422
|
+
return DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS;
|
|
166423
|
+
}
|
|
166424
|
+
return Math.max(1, Math.floor(value));
|
|
166425
|
+
}
|
|
166426
|
+
function normalizeContent(text) {
|
|
166427
|
+
return text.replace(/\s+/g, " ").trim();
|
|
166428
|
+
}
|
|
166429
|
+
function formatOrdinalRange(start, end) {
|
|
166430
|
+
return start === end ? `[${start}]` : `[${start}-${end}]`;
|
|
166431
|
+
}
|
|
166432
|
+
function rolePrefix(role) {
|
|
166433
|
+
if (role === "user")
|
|
166434
|
+
return "U";
|
|
166435
|
+
if (role === "assistant")
|
|
166436
|
+
return "A";
|
|
166437
|
+
return null;
|
|
166438
|
+
}
|
|
166439
|
+
function parseOrdinal(value) {
|
|
166440
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
166441
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
166442
|
+
}
|
|
166443
|
+
function parseCanonicalLineRange(line) {
|
|
166444
|
+
const match = /^\[(\d+)(?:-(\d+))?\]\s+[UA]:/.exec(line.trim());
|
|
166445
|
+
if (!match)
|
|
166446
|
+
return null;
|
|
166447
|
+
const start = Number.parseInt(match[1], 10);
|
|
166448
|
+
const end = match[2] ? Number.parseInt(match[2], 10) : start;
|
|
166449
|
+
if (!Number.isFinite(start) || !Number.isFinite(end))
|
|
166450
|
+
return null;
|
|
166451
|
+
return { start, end };
|
|
166452
|
+
}
|
|
166453
|
+
function hashChunkText(text) {
|
|
166454
|
+
return createHash8("sha256").update(text).digest("hex");
|
|
166455
|
+
}
|
|
166456
|
+
function vectorBlob(vector) {
|
|
166457
|
+
return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
|
|
166458
|
+
}
|
|
166459
|
+
function toFloat32Array2(blob) {
|
|
166460
|
+
if (blob instanceof Uint8Array) {
|
|
166461
|
+
const buffer2 = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
166462
|
+
return new Float32Array(buffer2);
|
|
166463
|
+
}
|
|
166464
|
+
return new Float32Array(blob.slice(0));
|
|
166465
|
+
}
|
|
166466
|
+
function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal) {
|
|
166467
|
+
if (endOrdinal < startOrdinal)
|
|
166468
|
+
return "";
|
|
166469
|
+
const rows = getLoadFtsRowsStatement(db).all(sessionId, startOrdinal, endOrdinal).map((row) => row);
|
|
166470
|
+
const lines = [];
|
|
166471
|
+
let current = null;
|
|
166472
|
+
const flush2 = () => {
|
|
166473
|
+
if (!current || current.parts.length === 0)
|
|
166474
|
+
return;
|
|
166475
|
+
lines.push(`${formatOrdinalRange(current.start, current.end)} ${current.role}: ${current.parts.join(" / ")}`);
|
|
166476
|
+
current = null;
|
|
166477
|
+
};
|
|
166478
|
+
for (const row of rows) {
|
|
166479
|
+
const ordinal = parseOrdinal(row.messageOrdinal);
|
|
166480
|
+
const prefix = rolePrefix(row.role);
|
|
166481
|
+
const content = typeof row.content === "string" ? normalizeContent(row.content) : "";
|
|
166482
|
+
if (ordinal === null || prefix === null || content.length === 0)
|
|
166483
|
+
continue;
|
|
166484
|
+
if (current && current.role === prefix) {
|
|
166485
|
+
current.end = ordinal;
|
|
166486
|
+
current.parts.push(content);
|
|
166487
|
+
continue;
|
|
166488
|
+
}
|
|
166489
|
+
flush2();
|
|
166490
|
+
current = { role: prefix, start: ordinal, end: ordinal, parts: [content] };
|
|
166491
|
+
}
|
|
166492
|
+
flush2();
|
|
166493
|
+
return lines.join(`
|
|
166494
|
+
`);
|
|
166495
|
+
}
|
|
166496
|
+
function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
|
|
166497
|
+
const lines = [];
|
|
166498
|
+
for (const rawLine of chunkText.split(/\r?\n/)) {
|
|
166499
|
+
const line = rawLine.trim();
|
|
166500
|
+
const match = /^(\[(\d+)(?:-(\d+))?\]\s+[UA]:)\s*(.*)$/.exec(line);
|
|
166501
|
+
if (!match)
|
|
166502
|
+
continue;
|
|
166503
|
+
const lineStart = Number.parseInt(match[2], 10);
|
|
166504
|
+
const lineEnd = match[3] ? Number.parseInt(match[3], 10) : lineStart;
|
|
166505
|
+
if (startOrdinal != null && lineEnd < startOrdinal)
|
|
166506
|
+
continue;
|
|
166507
|
+
if (endOrdinal != null && lineStart > endOrdinal)
|
|
166508
|
+
continue;
|
|
166509
|
+
const rawParts = match[4].split(" / ").map((part) => normalizeContent(part)).filter((part) => part.length > 0);
|
|
166510
|
+
const ordinalSpan = lineEnd - lineStart + 1;
|
|
166511
|
+
const roleLabel = match[1].slice(match[1].indexOf("]") + 2);
|
|
166512
|
+
if (ordinalSpan === rawParts.length) {
|
|
166513
|
+
const retained = rawParts.map((part, index) => ({ ordinal: lineStart + index, part })).filter(({ ordinal, part }) => {
|
|
166514
|
+
if (part.startsWith("TC:"))
|
|
166515
|
+
return false;
|
|
166516
|
+
if (startOrdinal != null && ordinal < startOrdinal)
|
|
166517
|
+
return false;
|
|
166518
|
+
if (endOrdinal != null && ordinal > endOrdinal)
|
|
166519
|
+
return false;
|
|
166520
|
+
return true;
|
|
166521
|
+
});
|
|
166522
|
+
if (retained.length === 0)
|
|
166523
|
+
continue;
|
|
166524
|
+
const retainedStart = retained[0].ordinal;
|
|
166525
|
+
const retainedEnd = retained[retained.length - 1].ordinal;
|
|
166526
|
+
lines.push(`${formatOrdinalRange(retainedStart, retainedEnd)} ${roleLabel} ${retained.map(({ part }) => part).join(" / ")}`);
|
|
166527
|
+
continue;
|
|
166528
|
+
}
|
|
166529
|
+
const parts = rawParts.filter((part) => !part.startsWith("TC:"));
|
|
166530
|
+
if (parts.length === 0)
|
|
166531
|
+
continue;
|
|
166532
|
+
lines.push(`${match[1]} ${parts.join(" / ")}`);
|
|
166533
|
+
}
|
|
166534
|
+
return lines.join(`
|
|
166535
|
+
`);
|
|
166536
|
+
}
|
|
166537
|
+
function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTokens) {
|
|
166538
|
+
const lines = canonicalText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
166539
|
+
if (lines.length === 0 || endOrdinal < startOrdinal)
|
|
166540
|
+
return [];
|
|
166541
|
+
const normalizedMax = normalizeCompartmentChunkMaxInputTokens(maxInputTokens);
|
|
166542
|
+
const effectiveMax = Math.max(1, Math.floor(normalizedMax * CHUNK_WINDOW_SAFETY_RATIO));
|
|
166543
|
+
const fullText = lines.join(`
|
|
166544
|
+
`);
|
|
166545
|
+
if (estimateTokens(fullText) <= effectiveMax) {
|
|
166546
|
+
return [
|
|
166547
|
+
{
|
|
166548
|
+
windowIndex: 0,
|
|
166549
|
+
startOrdinal,
|
|
166550
|
+
endOrdinal,
|
|
166551
|
+
text: fullText,
|
|
166552
|
+
chunkHash: hashChunkText(fullText)
|
|
166553
|
+
}
|
|
166554
|
+
];
|
|
166555
|
+
}
|
|
166556
|
+
const windows = [];
|
|
166557
|
+
let currentLines = [];
|
|
166558
|
+
let currentStart = null;
|
|
166559
|
+
let currentEnd = null;
|
|
166560
|
+
let currentTokens = 0;
|
|
166561
|
+
const flush2 = () => {
|
|
166562
|
+
if (currentLines.length === 0 || currentStart === null || currentEnd === null)
|
|
166563
|
+
return;
|
|
166564
|
+
const text = currentLines.join(`
|
|
166565
|
+
`);
|
|
166566
|
+
windows.push({
|
|
166567
|
+
windowIndex: windows.length + 1,
|
|
166568
|
+
startOrdinal: currentStart,
|
|
166569
|
+
endOrdinal: currentEnd,
|
|
166570
|
+
text,
|
|
166571
|
+
chunkHash: hashChunkText(text)
|
|
166572
|
+
});
|
|
166573
|
+
currentLines = [];
|
|
166574
|
+
currentStart = null;
|
|
166575
|
+
currentEnd = null;
|
|
166576
|
+
currentTokens = 0;
|
|
166577
|
+
};
|
|
166578
|
+
for (const line of lines) {
|
|
166579
|
+
const range = parseCanonicalLineRange(line);
|
|
166580
|
+
const lineStart = range?.start ?? startOrdinal;
|
|
166581
|
+
const lineEnd = range?.end ?? lineStart;
|
|
166582
|
+
const lineTokens = estimateTokens(line);
|
|
166583
|
+
if (currentLines.length > 0 && currentTokens + lineTokens > effectiveMax) {
|
|
166584
|
+
flush2();
|
|
166585
|
+
}
|
|
166586
|
+
if (currentLines.length === 0) {
|
|
166587
|
+
currentStart = lineStart;
|
|
166588
|
+
}
|
|
166589
|
+
currentLines.push(line);
|
|
166590
|
+
currentEnd = lineEnd;
|
|
166591
|
+
currentTokens += lineTokens;
|
|
166592
|
+
}
|
|
166593
|
+
flush2();
|
|
166594
|
+
return windows;
|
|
166595
|
+
}
|
|
166596
|
+
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
166597
|
+
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
166598
|
+
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
166599
|
+
return new Map(rows.filter((row) => typeof row.windowIndex === "number" && typeof row.chunkHash === "string").map((row) => [row.windowIndex, row.chunkHash]));
|
|
166600
|
+
}
|
|
166601
|
+
function chunkEmbeddingWindowsAreCurrent(db, compartmentId, modelId, windows, projectPath) {
|
|
166602
|
+
const existing = getExistingChunkHashes(db, compartmentId, modelId, projectPath);
|
|
166603
|
+
if (existing.size !== windows.length)
|
|
166604
|
+
return false;
|
|
166605
|
+
return windows.every((window) => existing.get(window.windowIndex) === window.chunkHash);
|
|
166606
|
+
}
|
|
166607
|
+
function replaceCompartmentChunkEmbeddings(db, rows) {
|
|
166608
|
+
if (rows.length === 0)
|
|
166609
|
+
return;
|
|
166610
|
+
const compartmentId = rows[0].compartmentId;
|
|
166611
|
+
const now = Date.now();
|
|
166612
|
+
db.transaction(() => {
|
|
166613
|
+
getDeleteByCompartmentStatement(db).run(compartmentId);
|
|
166614
|
+
const insert = getInsertEmbeddingStatement(db);
|
|
166615
|
+
for (const row of rows) {
|
|
166616
|
+
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);
|
|
166617
|
+
}
|
|
166618
|
+
})();
|
|
166619
|
+
}
|
|
166620
|
+
function getDistinctChunkEmbeddingModelIds(db, projectPath) {
|
|
166621
|
+
const rows = getDistinctModelStatement(db).all(projectPath);
|
|
166622
|
+
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
166623
|
+
}
|
|
166624
|
+
function clearChunkEmbeddingsForProject(db, projectPath, modelId) {
|
|
166625
|
+
if (modelId) {
|
|
166626
|
+
return getClearProjectModelStatement(db).run(projectPath, modelId).changes;
|
|
166627
|
+
}
|
|
166628
|
+
return getClearProjectStatement(db).run(projectPath).changes;
|
|
166629
|
+
}
|
|
166630
|
+
function loadCompartmentChunkEmbeddingsForSearch(db, sessionId, projectPath, modelId) {
|
|
166631
|
+
const rows = modelId ? getSearchRowsStatement(db, true).all(sessionId, projectPath, modelId) : getSearchRowsStatement(db, false).all(sessionId, projectPath);
|
|
166632
|
+
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) => ({
|
|
166633
|
+
compartmentId: row.compartmentId,
|
|
166634
|
+
sessionId: row.sessionId,
|
|
166635
|
+
title: row.title,
|
|
166636
|
+
startOrdinal: row.compartmentStart,
|
|
166637
|
+
endOrdinal: row.compartmentEnd,
|
|
166638
|
+
windowIndex: row.windowIndex,
|
|
166639
|
+
windowStartOrdinal: row.windowStart,
|
|
166640
|
+
windowEndOrdinal: row.windowEnd,
|
|
166641
|
+
chunkHash: row.chunkHash,
|
|
166642
|
+
modelId: row.modelId,
|
|
166643
|
+
dims: row.dims,
|
|
166644
|
+
vector: toFloat32Array2(row.vector)
|
|
166645
|
+
}));
|
|
166646
|
+
}
|
|
166647
|
+
function mapBackfillCandidateRows(rows) {
|
|
166648
|
+
return rows.filter((row) => {
|
|
166649
|
+
if (row === null || typeof row !== "object")
|
|
166650
|
+
return false;
|
|
166651
|
+
const candidate = row;
|
|
166652
|
+
return typeof candidate.id === "number" && typeof candidate.sessionId === "string" && typeof candidate.startMessage === "number" && typeof candidate.endMessage === "number" && typeof candidate.title === "string";
|
|
166653
|
+
}).map((row) => ({
|
|
166654
|
+
id: row.id,
|
|
166655
|
+
sessionId: row.sessionId,
|
|
166656
|
+
startMessage: row.startMessage,
|
|
166657
|
+
endMessage: row.endMessage,
|
|
166658
|
+
title: row.title
|
|
166659
|
+
}));
|
|
166660
|
+
}
|
|
166661
|
+
var sessionBackfillCandidateStatements = new WeakMap;
|
|
166662
|
+
function loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelId, limit, excludeIds) {
|
|
166663
|
+
if (excludeIds && excludeIds.length > 0) {
|
|
166664
|
+
const placeholders3 = excludeIds.map(() => "?").join(", ");
|
|
166665
|
+
const stmt2 = db.prepare(`SELECT c.id AS id,
|
|
166666
|
+
c.session_id AS sessionId,
|
|
166667
|
+
c.start_message AS startMessage,
|
|
166668
|
+
c.end_message AS endMessage,
|
|
166669
|
+
c.title AS title
|
|
166670
|
+
FROM compartments c
|
|
166671
|
+
JOIN session_projects sp
|
|
166672
|
+
ON sp.session_id = c.session_id
|
|
166673
|
+
AND sp.harness = c.harness
|
|
166674
|
+
AND sp.project_path = ?
|
|
166675
|
+
WHERE c.session_id = ?
|
|
166676
|
+
AND c.start_message IS NOT NULL
|
|
166677
|
+
AND c.end_message IS NOT NULL
|
|
166678
|
+
AND c.id NOT IN (${placeholders3})
|
|
166679
|
+
AND NOT EXISTS (
|
|
166680
|
+
SELECT 1
|
|
166681
|
+
FROM compartment_chunk_embeddings current
|
|
166682
|
+
WHERE current.compartment_id = c.id
|
|
166683
|
+
AND current.project_path = ?
|
|
166684
|
+
AND current.model_id = ?
|
|
166685
|
+
)
|
|
166686
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
166687
|
+
LIMIT ?`);
|
|
166688
|
+
const rows2 = stmt2.all(projectPath, sessionId, ...excludeIds, projectPath, modelId, Math.max(1, limit));
|
|
166689
|
+
return mapBackfillCandidateRows(rows2);
|
|
166690
|
+
}
|
|
166691
|
+
let stmt = sessionBackfillCandidateStatements.get(db);
|
|
166692
|
+
if (!stmt) {
|
|
166693
|
+
stmt = db.prepare(`SELECT c.id AS id,
|
|
166694
|
+
c.session_id AS sessionId,
|
|
166695
|
+
c.start_message AS startMessage,
|
|
166696
|
+
c.end_message AS endMessage,
|
|
166697
|
+
c.title AS title
|
|
166698
|
+
FROM compartments c
|
|
166699
|
+
JOIN session_projects sp
|
|
166700
|
+
ON sp.session_id = c.session_id
|
|
166701
|
+
AND sp.harness = c.harness
|
|
166702
|
+
AND sp.project_path = ?
|
|
166703
|
+
WHERE c.session_id = ?
|
|
166704
|
+
AND c.start_message IS NOT NULL
|
|
166705
|
+
AND c.end_message IS NOT NULL
|
|
166706
|
+
AND NOT EXISTS (
|
|
166707
|
+
SELECT 1
|
|
166708
|
+
FROM compartment_chunk_embeddings current
|
|
166709
|
+
WHERE current.compartment_id = c.id
|
|
166710
|
+
AND current.project_path = ?
|
|
166711
|
+
AND current.model_id = ?
|
|
166712
|
+
)
|
|
166713
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
166714
|
+
LIMIT ?`);
|
|
166715
|
+
sessionBackfillCandidateStatements.set(db, stmt);
|
|
166716
|
+
}
|
|
166717
|
+
const rows = stmt.all(projectPath, sessionId, projectPath, modelId, Math.max(1, limit));
|
|
166718
|
+
return mapBackfillCandidateRows(rows);
|
|
166719
|
+
}
|
|
166720
|
+
function countUnembeddedSessionCompartments(db, projectPath, sessionId, modelId) {
|
|
166721
|
+
const row = db.prepare(`SELECT COUNT(*) AS n
|
|
166722
|
+
FROM compartments c
|
|
166723
|
+
JOIN session_projects sp
|
|
166724
|
+
ON sp.session_id = c.session_id
|
|
166725
|
+
AND sp.harness = c.harness
|
|
166726
|
+
AND sp.project_path = ?
|
|
166727
|
+
WHERE c.session_id = ?
|
|
166728
|
+
AND c.start_message IS NOT NULL
|
|
166729
|
+
AND c.end_message IS NOT NULL
|
|
166730
|
+
AND NOT EXISTS (
|
|
166731
|
+
SELECT 1
|
|
166732
|
+
FROM compartment_chunk_embeddings current
|
|
166733
|
+
WHERE current.compartment_id = c.id
|
|
166734
|
+
AND current.project_path = ?
|
|
166735
|
+
AND current.model_id = ?
|
|
166736
|
+
)`).get(projectPath, sessionId, projectPath, modelId);
|
|
166737
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
166738
|
+
}
|
|
166739
|
+
|
|
165656
166740
|
// ../plugin/src/features/magic-context/memory/cosine-similarity.ts
|
|
165657
166741
|
function cosineSimilarity(a, b) {
|
|
165658
166742
|
if (a.length !== b.length) {
|
|
@@ -165811,19 +166895,19 @@ function isArrayLikeNumber(value) {
|
|
|
165811
166895
|
}
|
|
165812
166896
|
return arr.length === 0 || typeof arr[0] === "number";
|
|
165813
166897
|
}
|
|
165814
|
-
function
|
|
166898
|
+
function toFloat32Array3(values) {
|
|
165815
166899
|
return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
|
|
165816
166900
|
}
|
|
165817
166901
|
function extractBatchEmbeddings(result, expectedCount) {
|
|
165818
166902
|
const { data } = result;
|
|
165819
166903
|
if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
|
|
165820
|
-
return data.map((entry) =>
|
|
166904
|
+
return data.map((entry) => toFloat32Array3(entry));
|
|
165821
166905
|
}
|
|
165822
166906
|
if (!isArrayLikeNumber(data)) {
|
|
165823
166907
|
log("[magic-context] embedding batch returned unexpected data shape");
|
|
165824
166908
|
return Array.from({ length: expectedCount }, () => null);
|
|
165825
166909
|
}
|
|
165826
|
-
const flatData =
|
|
166910
|
+
const flatData = toFloat32Array3(data);
|
|
165827
166911
|
const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
|
|
165828
166912
|
if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
|
|
165829
166913
|
log("[magic-context] embedding batch returned invalid dimensions");
|
|
@@ -165838,6 +166922,7 @@ function extractBatchEmbeddings(result, expectedCount) {
|
|
|
165838
166922
|
|
|
165839
166923
|
class LocalEmbeddingProvider {
|
|
165840
166924
|
modelId;
|
|
166925
|
+
maxInputTokens;
|
|
165841
166926
|
model;
|
|
165842
166927
|
pipeline = null;
|
|
165843
166928
|
initPromise = null;
|
|
@@ -165845,8 +166930,9 @@ class LocalEmbeddingProvider {
|
|
|
165845
166930
|
disposing = false;
|
|
165846
166931
|
disposePromise = null;
|
|
165847
166932
|
inFlightWaiters = [];
|
|
165848
|
-
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
166933
|
+
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
|
|
165849
166934
|
this.model = model;
|
|
166935
|
+
this.maxInputTokens = maxInputTokens;
|
|
165850
166936
|
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
165851
166937
|
}
|
|
165852
166938
|
async initialize() {
|
|
@@ -166094,6 +167180,13 @@ function blockedEmbeddingEndpointReason(endpoint) {
|
|
|
166094
167180
|
function normalizeEndpoint2(endpoint) {
|
|
166095
167181
|
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
166096
167182
|
}
|
|
167183
|
+
function embeddingModelsMatch(served, requested) {
|
|
167184
|
+
const a = served.trim().toLowerCase();
|
|
167185
|
+
const b = requested.trim().toLowerCase();
|
|
167186
|
+
if (a.length === 0 || b.length === 0)
|
|
167187
|
+
return true;
|
|
167188
|
+
return a === b || a.includes(b) || b.includes(a);
|
|
167189
|
+
}
|
|
166097
167190
|
var FAILURE_THRESHOLD = 3;
|
|
166098
167191
|
var FAILURE_WINDOW_MS = 60000;
|
|
166099
167192
|
var OPEN_DURATION_MS = 5 * 60000;
|
|
@@ -166101,6 +167194,7 @@ var FETCH_TIMEOUT_MS = 30000;
|
|
|
166101
167194
|
|
|
166102
167195
|
class OpenAICompatibleEmbeddingProvider {
|
|
166103
167196
|
modelId;
|
|
167197
|
+
maxInputTokens;
|
|
166104
167198
|
endpoint;
|
|
166105
167199
|
model;
|
|
166106
167200
|
apiKey;
|
|
@@ -166110,6 +167204,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166110
167204
|
failureTimes = [];
|
|
166111
167205
|
circuitOpenUntil = 0;
|
|
166112
167206
|
openLogged = false;
|
|
167207
|
+
modelMismatchLogged = false;
|
|
166113
167208
|
halfOpenProbeInFlight = false;
|
|
166114
167209
|
constructor(options) {
|
|
166115
167210
|
this.endpoint = normalizeEndpoint2(options.endpoint);
|
|
@@ -166117,11 +167212,13 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166117
167212
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
166118
167213
|
this.inputType = options.inputType?.trim() ?? "";
|
|
166119
167214
|
this.truncate = options.truncate?.trim() ?? "";
|
|
167215
|
+
this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
|
|
166120
167216
|
this.modelId = getEmbeddingProviderIdentity({
|
|
166121
167217
|
provider: "openai-compatible",
|
|
166122
167218
|
endpoint: this.endpoint,
|
|
166123
167219
|
model: this.model,
|
|
166124
|
-
...this.apiKey ? { api_key: this.apiKey } : {}
|
|
167220
|
+
...this.apiKey ? { api_key: this.apiKey } : {},
|
|
167221
|
+
...this.inputType ? { input_type: this.inputType } : {}
|
|
166125
167222
|
});
|
|
166126
167223
|
}
|
|
166127
167224
|
async initialize() {
|
|
@@ -166206,6 +167303,15 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166206
167303
|
this.recordFailure(isProbe);
|
|
166207
167304
|
return Array.from({ length: texts.length }, () => null);
|
|
166208
167305
|
}
|
|
167306
|
+
const servedModel = typeof body.model === "string" ? body.model : "";
|
|
167307
|
+
if (this.model && servedModel && !embeddingModelsMatch(servedModel, this.model)) {
|
|
167308
|
+
if (!this.modelMismatchLogged) {
|
|
167309
|
+
log(`[magic-context] embedding endpoint served a DIFFERENT model than requested — refusing the substituted vectors (they have the wrong dimensions/space). requested="${this.model}" served="${servedModel}". The endpoint likely substituted a loaded model; load/select "${this.model}" on the endpoint, or set embedding.model to the served model.`);
|
|
167310
|
+
this.modelMismatchLogged = true;
|
|
167311
|
+
}
|
|
167312
|
+
this.recordFailure(isProbe);
|
|
167313
|
+
return Array.from({ length: texts.length }, () => null);
|
|
167314
|
+
}
|
|
166209
167315
|
const items = Array.isArray(body.data) ? body.data : [];
|
|
166210
167316
|
const results = Array.from({ length: texts.length }, (_, index) => {
|
|
166211
167317
|
const embedding = items[index]?.embedding;
|
|
@@ -166312,7 +167418,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
166312
167418
|
}
|
|
166313
167419
|
|
|
166314
167420
|
// ../plugin/src/features/magic-context/project-embedding-registry.ts
|
|
166315
|
-
import { createHash as
|
|
167421
|
+
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
166316
167422
|
init_logger();
|
|
166317
167423
|
|
|
166318
167424
|
// ../plugin/src/features/magic-context/git-commits/storage-git-commit-embeddings.ts
|
|
@@ -166320,7 +167426,7 @@ var saveStatements = new WeakMap;
|
|
|
166320
167426
|
var loadProjectStatements = new WeakMap;
|
|
166321
167427
|
var loadUnembeddedStatements = new WeakMap;
|
|
166322
167428
|
var countEmbeddedStatements = new WeakMap;
|
|
166323
|
-
var
|
|
167429
|
+
var clearProjectStatements2 = new WeakMap;
|
|
166324
167430
|
var distinctModelIdStatements = new WeakMap;
|
|
166325
167431
|
function getSaveStatement(db) {
|
|
166326
167432
|
let stmt = saveStatements.get(db);
|
|
@@ -166368,12 +167474,12 @@ function getCountEmbeddedStatement(db) {
|
|
|
166368
167474
|
}
|
|
166369
167475
|
return stmt;
|
|
166370
167476
|
}
|
|
166371
|
-
function
|
|
166372
|
-
let stmt =
|
|
167477
|
+
function getClearProjectStatement2(db) {
|
|
167478
|
+
let stmt = clearProjectStatements2.get(db);
|
|
166373
167479
|
if (!stmt) {
|
|
166374
167480
|
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
166375
167481
|
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
166376
|
-
|
|
167482
|
+
clearProjectStatements2.set(db, stmt);
|
|
166377
167483
|
}
|
|
166378
167484
|
return stmt;
|
|
166379
167485
|
}
|
|
@@ -166409,7 +167515,7 @@ function countEmbeddedCommits(db, projectPath) {
|
|
|
166409
167515
|
return row?.count ?? 0;
|
|
166410
167516
|
}
|
|
166411
167517
|
function clearProjectCommitEmbeddings(db, projectPath) {
|
|
166412
|
-
return
|
|
167518
|
+
return getClearProjectStatement2(db).run(projectPath).changes;
|
|
166413
167519
|
}
|
|
166414
167520
|
function getDistinctCommitEmbeddingModelIds(db, projectPath) {
|
|
166415
167521
|
const rows = getDistinctModelIdStatement(db).all(projectPath);
|
|
@@ -166535,9 +167641,83 @@ function releaseGitSweepLease(db, projectPath, holderId) {
|
|
|
166535
167641
|
});
|
|
166536
167642
|
}
|
|
166537
167643
|
|
|
167644
|
+
// ../plugin/src/features/magic-context/session-project-storage.ts
|
|
167645
|
+
var upsertSessionProjectStatements = new WeakMap;
|
|
167646
|
+
var repairSessionChunkProjectStatements = new WeakMap;
|
|
167647
|
+
var repairProjectChunkProjectStatements = new WeakMap;
|
|
167648
|
+
function getUpsertSessionProjectStatement(db) {
|
|
167649
|
+
let stmt = upsertSessionProjectStatements.get(db);
|
|
167650
|
+
if (!stmt) {
|
|
167651
|
+
stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
|
|
167652
|
+
VALUES (?, ?, ?, ?)
|
|
167653
|
+
ON CONFLICT(session_id, harness) DO UPDATE SET
|
|
167654
|
+
project_path = excluded.project_path,
|
|
167655
|
+
updated_at = excluded.updated_at
|
|
167656
|
+
WHERE session_projects.project_path <> excluded.project_path`);
|
|
167657
|
+
upsertSessionProjectStatements.set(db, stmt);
|
|
167658
|
+
}
|
|
167659
|
+
return stmt;
|
|
167660
|
+
}
|
|
167661
|
+
function getRepairSessionChunkProjectStatement(db) {
|
|
167662
|
+
let stmt = repairSessionChunkProjectStatements.get(db);
|
|
167663
|
+
if (!stmt) {
|
|
167664
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
167665
|
+
SET project_path = ?
|
|
167666
|
+
WHERE session_id = ?
|
|
167667
|
+
AND harness = ?
|
|
167668
|
+
AND project_path <> ?`);
|
|
167669
|
+
repairSessionChunkProjectStatements.set(db, stmt);
|
|
167670
|
+
}
|
|
167671
|
+
return stmt;
|
|
167672
|
+
}
|
|
167673
|
+
function getRepairProjectChunkProjectStatement(db) {
|
|
167674
|
+
let stmt = repairProjectChunkProjectStatements.get(db);
|
|
167675
|
+
if (!stmt) {
|
|
167676
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
167677
|
+
SET project_path = (
|
|
167678
|
+
SELECT sp.project_path
|
|
167679
|
+
FROM session_projects sp
|
|
167680
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
167681
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
167682
|
+
LIMIT 1
|
|
167683
|
+
)
|
|
167684
|
+
WHERE EXISTS (
|
|
167685
|
+
SELECT 1
|
|
167686
|
+
FROM session_projects sp
|
|
167687
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
167688
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
167689
|
+
AND sp.project_path <> compartment_chunk_embeddings.project_path
|
|
167690
|
+
AND (
|
|
167691
|
+
sp.project_path = ?
|
|
167692
|
+
OR compartment_chunk_embeddings.project_path = ?
|
|
167693
|
+
)
|
|
167694
|
+
)`);
|
|
167695
|
+
repairProjectChunkProjectStatements.set(db, stmt);
|
|
167696
|
+
}
|
|
167697
|
+
return stmt;
|
|
167698
|
+
}
|
|
167699
|
+
function recordSessionProjectIdentity(db, sessionId, projectPath) {
|
|
167700
|
+
if (!sessionId || !projectPath)
|
|
167701
|
+
return;
|
|
167702
|
+
const harness = getHarness();
|
|
167703
|
+
const now = Date.now();
|
|
167704
|
+
db.transaction(() => {
|
|
167705
|
+
getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
|
|
167706
|
+
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
|
|
167707
|
+
})();
|
|
167708
|
+
}
|
|
167709
|
+
function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
167710
|
+
if (!projectPath)
|
|
167711
|
+
return 0;
|
|
167712
|
+
return getRepairProjectChunkProjectStatement(db).run(projectPath, projectPath).changes;
|
|
167713
|
+
}
|
|
167714
|
+
|
|
166538
167715
|
// ../plugin/src/features/magic-context/project-embedding-registry.ts
|
|
166539
167716
|
var OFF_PROVIDER_IDENTITY = "embedding-provider:off";
|
|
166540
167717
|
var SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
167718
|
+
var CHUNK_DRAIN_BATCH_SIZE = 8;
|
|
167719
|
+
var MAX_WINDOWS_PER_EMBED_CALL = 16;
|
|
167720
|
+
var SESSION_EMBED_LEASE_RENEWAL_MS = 60 * 1000;
|
|
166541
167721
|
var projectRegistrations = new Map;
|
|
166542
167722
|
var loadUnembeddedMemoriesStatements = new WeakMap;
|
|
166543
167723
|
var globalRegistrationGeneration = 0;
|
|
@@ -166546,7 +167726,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
166546
167726
|
if (!config2 || config2.provider === "local") {
|
|
166547
167727
|
return {
|
|
166548
167728
|
provider: "local",
|
|
166549
|
-
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
167729
|
+
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
167730
|
+
...config2?.max_input_tokens ? {
|
|
167731
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
167732
|
+
} : {}
|
|
166550
167733
|
};
|
|
166551
167734
|
}
|
|
166552
167735
|
if (config2.provider === "openai-compatible") {
|
|
@@ -166559,7 +167742,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
166559
167742
|
endpoint: config2.endpoint.trim(),
|
|
166560
167743
|
...apiKey ? { api_key: apiKey } : {},
|
|
166561
167744
|
...inputType ? { input_type: inputType } : {},
|
|
166562
|
-
...truncate ? { truncate } : {}
|
|
167745
|
+
...truncate ? { truncate } : {},
|
|
167746
|
+
...config2.max_input_tokens ? {
|
|
167747
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
167748
|
+
} : {}
|
|
166563
167749
|
};
|
|
166564
167750
|
}
|
|
166565
167751
|
return { provider: "off" };
|
|
@@ -166577,10 +167763,11 @@ function createProvider(config2) {
|
|
|
166577
167763
|
model: config2.model,
|
|
166578
167764
|
apiKey: config2.api_key,
|
|
166579
167765
|
inputType: config2.input_type,
|
|
166580
|
-
truncate: config2.truncate
|
|
167766
|
+
truncate: config2.truncate,
|
|
167767
|
+
maxInputTokens: config2.max_input_tokens
|
|
166581
167768
|
});
|
|
166582
167769
|
}
|
|
166583
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
167770
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
166584
167771
|
}
|
|
166585
167772
|
function stableStringify2(value) {
|
|
166586
167773
|
if (Array.isArray(value)) {
|
|
@@ -166593,7 +167780,7 @@ function stableStringify2(value) {
|
|
|
166593
167780
|
return JSON.stringify(value);
|
|
166594
167781
|
}
|
|
166595
167782
|
function sha256Prefix(value, length = 16) {
|
|
166596
|
-
return
|
|
167783
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, length);
|
|
166597
167784
|
}
|
|
166598
167785
|
function getRuntimeFingerprint(config2) {
|
|
166599
167786
|
if (config2.provider === "off") {
|
|
@@ -166601,6 +167788,18 @@ function getRuntimeFingerprint(config2) {
|
|
|
166601
167788
|
}
|
|
166602
167789
|
return `${getEmbeddingProviderIdentity(config2)}:${sha256Prefix(stableStringify2(config2))}`;
|
|
166603
167790
|
}
|
|
167791
|
+
function getChunkEmbeddingModelId(config2, providerIdentity) {
|
|
167792
|
+
if (config2.provider === "off") {
|
|
167793
|
+
return OFF_PROVIDER_IDENTITY;
|
|
167794
|
+
}
|
|
167795
|
+
const chunkIdentity = {
|
|
167796
|
+
providerIdentity,
|
|
167797
|
+
chunkerVersion: 2,
|
|
167798
|
+
maxInputTokens: normalizeCompartmentChunkMaxInputTokens("max_input_tokens" in config2 ? config2.max_input_tokens : undefined),
|
|
167799
|
+
truncate: config2.provider === "openai-compatible" ? config2.truncate ?? "" : ""
|
|
167800
|
+
};
|
|
167801
|
+
return `${providerIdentity}:chunk:${sha256Prefix(stableStringify2(chunkIdentity))}`;
|
|
167802
|
+
}
|
|
166604
167803
|
function sameFeatures(a, b) {
|
|
166605
167804
|
return a.memoryEnabled === b.memoryEnabled && a.gitCommitEnabled === b.gitCommitEnabled;
|
|
166606
167805
|
}
|
|
@@ -166617,7 +167816,8 @@ function snapshotFor(registration) {
|
|
|
166617
167816
|
features: { ...registration.features },
|
|
166618
167817
|
enabled,
|
|
166619
167818
|
gitCommitEnabled,
|
|
166620
|
-
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId
|
|
167819
|
+
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
|
|
167820
|
+
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId
|
|
166621
167821
|
};
|
|
166622
167822
|
}
|
|
166623
167823
|
function disposeProvider(provider) {
|
|
@@ -166637,7 +167837,7 @@ function anyStoredModelIdIsStale(storedIds, currentId) {
|
|
|
166637
167837
|
}
|
|
166638
167838
|
return false;
|
|
166639
167839
|
}
|
|
166640
|
-
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, features) {
|
|
167840
|
+
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, currentChunkIdentity, features) {
|
|
166641
167841
|
if (currentProviderIdentity === OFF_PROVIDER_IDENTITY) {
|
|
166642
167842
|
return false;
|
|
166643
167843
|
}
|
|
@@ -166658,6 +167858,14 @@ function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity,
|
|
|
166658
167858
|
wiped = true;
|
|
166659
167859
|
}
|
|
166660
167860
|
}
|
|
167861
|
+
if (features.memoryEnabled) {
|
|
167862
|
+
repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectIdentity);
|
|
167863
|
+
const chunkIds = getDistinctChunkEmbeddingModelIds(db, projectIdentity);
|
|
167864
|
+
if (anyStoredModelIdIsStale(chunkIds, currentChunkIdentity)) {
|
|
167865
|
+
clearChunkEmbeddingsForProject(db, projectIdentity);
|
|
167866
|
+
wiped = true;
|
|
167867
|
+
}
|
|
167868
|
+
}
|
|
166661
167869
|
})();
|
|
166662
167870
|
return wiped;
|
|
166663
167871
|
}
|
|
@@ -166665,10 +167873,11 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
166665
167873
|
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
166666
167874
|
const providerIdentity = getEmbeddingProviderIdentity(resolvedConfig);
|
|
166667
167875
|
const runtimeFingerprint = getRuntimeFingerprint(resolvedConfig);
|
|
167876
|
+
const chunkModelId = getChunkEmbeddingModelId(resolvedConfig, providerIdentity);
|
|
166668
167877
|
const prior = projectRegistrations.get(projectIdentity);
|
|
166669
167878
|
const canReuseProvider = prior !== undefined && !prior.observationMode && prior.runtimeFingerprint === runtimeFingerprint && prior.providerIdentity === providerIdentity;
|
|
166670
|
-
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, features);
|
|
166671
|
-
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || !sameFeatures(prior.features, features) || wiped;
|
|
167879
|
+
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, chunkModelId, features);
|
|
167880
|
+
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || prior.chunkModelId !== chunkModelId || !sameFeatures(prior.features, features) || wiped;
|
|
166672
167881
|
const generation = generationChanged ? ++globalRegistrationGeneration : prior.generation;
|
|
166673
167882
|
const registration = {
|
|
166674
167883
|
projectIdentity,
|
|
@@ -166680,6 +167889,7 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
166680
167889
|
generation,
|
|
166681
167890
|
features: { ...features },
|
|
166682
167891
|
modelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : providerIdentity,
|
|
167892
|
+
chunkModelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : chunkModelId,
|
|
166683
167893
|
observationMode: false
|
|
166684
167894
|
};
|
|
166685
167895
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -166702,6 +167912,7 @@ function registerProjectInObservationMode(db, projectIdentity, sourceDirectory,
|
|
|
166702
167912
|
generation,
|
|
166703
167913
|
features: { memoryEnabled: false, gitCommitEnabled: false },
|
|
166704
167914
|
modelId: "off",
|
|
167915
|
+
chunkModelId: "off",
|
|
166705
167916
|
observationMode: true
|
|
166706
167917
|
};
|
|
166707
167918
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -166712,6 +167923,15 @@ function getProjectEmbeddingSnapshot(projectIdentity) {
|
|
|
166712
167923
|
const registration = projectRegistrations.get(projectIdentity);
|
|
166713
167924
|
return registration ? snapshotFor(registration) : null;
|
|
166714
167925
|
}
|
|
167926
|
+
function getProjectChunkEmbeddingModelId(projectIdentity) {
|
|
167927
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
167928
|
+
return registration && !registration.observationMode ? registration.chunkModelId : "off";
|
|
167929
|
+
}
|
|
167930
|
+
function getProjectEmbeddingMaxInputTokens(projectIdentity) {
|
|
167931
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
167932
|
+
const configMax = registration?.config && "max_input_tokens" in registration.config ? registration.config.max_input_tokens : undefined;
|
|
167933
|
+
return normalizeCompartmentChunkMaxInputTokens(registration?.provider?.maxInputTokens ?? configMax);
|
|
167934
|
+
}
|
|
166715
167935
|
function getOrCreateProjectProvider(registration) {
|
|
166716
167936
|
if (registration.providerIdentity === OFF_PROVIDER_IDENTITY || registration.observationMode) {
|
|
166717
167937
|
return null;
|
|
@@ -166806,6 +168026,131 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
166806
168026
|
return 0;
|
|
166807
168027
|
}
|
|
166808
168028
|
}
|
|
168029
|
+
async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal) {
|
|
168030
|
+
const noWork = [];
|
|
168031
|
+
if (candidates.length === 0)
|
|
168032
|
+
return { embedded: 0, noWork };
|
|
168033
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
|
|
168034
|
+
const prepared = [];
|
|
168035
|
+
for (const candidate of candidates) {
|
|
168036
|
+
const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
|
|
168037
|
+
if (canonicalText.length === 0) {
|
|
168038
|
+
noWork.push(candidate.id);
|
|
168039
|
+
continue;
|
|
168040
|
+
}
|
|
168041
|
+
const windows = chunkCanonicalText(canonicalText, candidate.startMessage, candidate.endMessage, maxInputTokens);
|
|
168042
|
+
if (windows.length === 0 || chunkEmbeddingWindowsAreCurrent(db, candidate.id, modelId, windows, projectIdentity)) {
|
|
168043
|
+
noWork.push(candidate.id);
|
|
168044
|
+
continue;
|
|
168045
|
+
}
|
|
168046
|
+
prepared.push({ candidate, windows });
|
|
168047
|
+
}
|
|
168048
|
+
if (prepared.length === 0)
|
|
168049
|
+
return { embedded: 0, noWork };
|
|
168050
|
+
let embedded = 0;
|
|
168051
|
+
let i = 0;
|
|
168052
|
+
while (i < prepared.length) {
|
|
168053
|
+
if (signal?.aborted)
|
|
168054
|
+
break;
|
|
168055
|
+
const slice = [];
|
|
168056
|
+
let windowCount = 0;
|
|
168057
|
+
do {
|
|
168058
|
+
const item = prepared[i];
|
|
168059
|
+
slice.push(item);
|
|
168060
|
+
windowCount += item.windows.length;
|
|
168061
|
+
i += 1;
|
|
168062
|
+
} while (i < prepared.length && windowCount + prepared[i].windows.length <= MAX_WINDOWS_PER_EMBED_CALL);
|
|
168063
|
+
const texts = [];
|
|
168064
|
+
for (const item of slice)
|
|
168065
|
+
texts.push(...item.windows.map((w) => w.text));
|
|
168066
|
+
try {
|
|
168067
|
+
const result = await embedBatchForProject(projectIdentity, texts, signal);
|
|
168068
|
+
if (!result)
|
|
168069
|
+
continue;
|
|
168070
|
+
if (signal?.aborted)
|
|
168071
|
+
break;
|
|
168072
|
+
let offset = 0;
|
|
168073
|
+
for (const item of slice) {
|
|
168074
|
+
const vectors = result.vectors.slice(offset, offset + item.windows.length);
|
|
168075
|
+
offset += item.windows.length;
|
|
168076
|
+
if (vectors.length !== item.windows.length || vectors.some((v) => !v)) {
|
|
168077
|
+
continue;
|
|
168078
|
+
}
|
|
168079
|
+
const rows = item.windows.map((window, index) => ({
|
|
168080
|
+
compartmentId: item.candidate.id,
|
|
168081
|
+
sessionId: item.candidate.sessionId,
|
|
168082
|
+
projectPath: projectIdentity,
|
|
168083
|
+
window,
|
|
168084
|
+
modelId,
|
|
168085
|
+
vector: vectors[index]
|
|
168086
|
+
}));
|
|
168087
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
168088
|
+
embedded += 1;
|
|
168089
|
+
}
|
|
168090
|
+
} catch (error51) {
|
|
168091
|
+
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
168092
|
+
}
|
|
168093
|
+
}
|
|
168094
|
+
return { embedded, noWork };
|
|
168095
|
+
}
|
|
168096
|
+
async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, options) {
|
|
168097
|
+
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
168098
|
+
if (!snapshot?.enabled || snapshot.chunkModelId === "off") {
|
|
168099
|
+
return { status: "disabled", embedded: 0, total: 0 };
|
|
168100
|
+
}
|
|
168101
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
168102
|
+
const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId);
|
|
168103
|
+
if (total === 0)
|
|
168104
|
+
return { status: "nothing", embedded: 0, total: 0 };
|
|
168105
|
+
const holderId = `session-embed-${randomUUID()}`;
|
|
168106
|
+
const lease2 = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
|
|
168107
|
+
if (!lease2.acquired)
|
|
168108
|
+
return { status: "busy", embedded: 0, total };
|
|
168109
|
+
const renewal = setInterval(() => {
|
|
168110
|
+
try {
|
|
168111
|
+
renewGitSweepLease(db, projectIdentity, holderId);
|
|
168112
|
+
} catch {}
|
|
168113
|
+
}, SESSION_EMBED_LEASE_RENEWAL_MS);
|
|
168114
|
+
renewal.unref?.();
|
|
168115
|
+
const batchSize = Math.max(1, options?.batchSize ?? CHUNK_DRAIN_BATCH_SIZE);
|
|
168116
|
+
const skipIds = [];
|
|
168117
|
+
let embedded = 0;
|
|
168118
|
+
let aborted2 = false;
|
|
168119
|
+
let providerStalled = false;
|
|
168120
|
+
try {
|
|
168121
|
+
options?.onProgress?.({ embedded, total });
|
|
168122
|
+
for (;; ) {
|
|
168123
|
+
if (options?.signal?.aborted) {
|
|
168124
|
+
aborted2 = true;
|
|
168125
|
+
break;
|
|
168126
|
+
}
|
|
168127
|
+
const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, skipIds);
|
|
168128
|
+
if (candidates.length === 0)
|
|
168129
|
+
break;
|
|
168130
|
+
const { embedded: n, noWork } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, options?.signal);
|
|
168131
|
+
for (const id of noWork)
|
|
168132
|
+
skipIds.push(id);
|
|
168133
|
+
if (n === 0 && noWork.length === 0) {
|
|
168134
|
+
providerStalled = true;
|
|
168135
|
+
break;
|
|
168136
|
+
}
|
|
168137
|
+
embedded += n;
|
|
168138
|
+
options?.onProgress?.({ embedded: Math.min(embedded, total), total });
|
|
168139
|
+
await new Promise((resolve4) => setTimeout(resolve4, 0));
|
|
168140
|
+
}
|
|
168141
|
+
} finally {
|
|
168142
|
+
clearInterval(renewal);
|
|
168143
|
+
releaseGitSweepLease(db, projectIdentity, holderId);
|
|
168144
|
+
}
|
|
168145
|
+
if (aborted2)
|
|
168146
|
+
return { status: "aborted", embedded, total };
|
|
168147
|
+
if (providerStalled) {
|
|
168148
|
+
const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId) - skipIds.length);
|
|
168149
|
+
if (remaining > 0)
|
|
168150
|
+
return { status: "stalled", embedded, total, remaining };
|
|
168151
|
+
}
|
|
168152
|
+
return { status: "done", embedded, total };
|
|
168153
|
+
}
|
|
166809
168154
|
|
|
166810
168155
|
// ../plugin/src/features/magic-context/memory/embedding.ts
|
|
166811
168156
|
var DEFAULT_EMBEDDING_CONFIG = {
|
|
@@ -166825,10 +168170,11 @@ function createProvider2(config2) {
|
|
|
166825
168170
|
model: config2.model,
|
|
166826
168171
|
apiKey: config2.api_key,
|
|
166827
168172
|
inputType: config2.input_type,
|
|
166828
|
-
truncate: config2.truncate
|
|
168173
|
+
truncate: config2.truncate,
|
|
168174
|
+
maxInputTokens: config2.max_input_tokens
|
|
166829
168175
|
});
|
|
166830
168176
|
}
|
|
166831
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
168177
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
166832
168178
|
}
|
|
166833
168179
|
function getOrCreateProvider() {
|
|
166834
168180
|
if (provider) {
|
|
@@ -167071,6 +168417,7 @@ init_logger();
|
|
|
167071
168417
|
// ../plugin/src/features/magic-context/memory/storage-memory-fts.ts
|
|
167072
168418
|
var DEFAULT_SEARCH_LIMIT = 10;
|
|
167073
168419
|
var searchStatements = new WeakMap;
|
|
168420
|
+
var unionSearchStatements = new Map;
|
|
167074
168421
|
function getSearchStatement(db) {
|
|
167075
168422
|
let stmt = searchStatements.get(db);
|
|
167076
168423
|
if (!stmt) {
|
|
@@ -167079,6 +168426,23 @@ function getSearchStatement(db) {
|
|
|
167079
168426
|
}
|
|
167080
168427
|
return stmt;
|
|
167081
168428
|
}
|
|
168429
|
+
function getUnionSearchStatement(db, arity) {
|
|
168430
|
+
let statements = unionSearchStatements.get(arity);
|
|
168431
|
+
if (!statements) {
|
|
168432
|
+
statements = new WeakMap;
|
|
168433
|
+
unionSearchStatements.set(arity, statements);
|
|
168434
|
+
}
|
|
168435
|
+
let stmt = statements.get(db);
|
|
168436
|
+
if (!stmt) {
|
|
168437
|
+
const placeholders3 = Array.from({ length: arity }, () => "?").join(", ");
|
|
168438
|
+
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 ?`);
|
|
168439
|
+
statements.set(db, stmt);
|
|
168440
|
+
}
|
|
168441
|
+
return stmt;
|
|
168442
|
+
}
|
|
168443
|
+
function uniqueProjectPaths2(projectPaths) {
|
|
168444
|
+
return [...new Set(projectPaths.filter((path7) => path7.length > 0))];
|
|
168445
|
+
}
|
|
167082
168446
|
function sanitizeFtsQuery(query) {
|
|
167083
168447
|
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
167084
168448
|
if (tokens.length === 0)
|
|
@@ -167097,6 +168461,28 @@ function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT)
|
|
|
167097
168461
|
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
167098
168462
|
return rows.map(toMemory);
|
|
167099
168463
|
}
|
|
168464
|
+
function searchMemoriesFTSUnion(db, projectPaths, query, limit = DEFAULT_SEARCH_LIMIT, ownIdentities, shareCategories) {
|
|
168465
|
+
const identities = uniqueProjectPaths2(projectPaths);
|
|
168466
|
+
if (identities.length === 0)
|
|
168467
|
+
return [];
|
|
168468
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
168469
|
+
identities,
|
|
168470
|
+
ownIdentities,
|
|
168471
|
+
shareCategories,
|
|
168472
|
+
tableName: "memories"
|
|
168473
|
+
});
|
|
168474
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
168475
|
+
return searchMemoriesFTS(db, identities[0], query, limit);
|
|
168476
|
+
}
|
|
168477
|
+
const trimmedQuery = query.trim();
|
|
168478
|
+
if (trimmedQuery.length === 0 || limit <= 0)
|
|
168479
|
+
return [];
|
|
168480
|
+
const sanitized = sanitizeFtsQuery(trimmedQuery);
|
|
168481
|
+
if (sanitized.length === 0)
|
|
168482
|
+
return [];
|
|
168483
|
+
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);
|
|
168484
|
+
return rows.map(toMemory);
|
|
168485
|
+
}
|
|
167100
168486
|
|
|
167101
168487
|
// ../plugin/src/features/magic-context/git-commits/search-git-commits.ts
|
|
167102
168488
|
var ftsStatements = new WeakMap;
|
|
@@ -167389,7 +168775,7 @@ async function sweepGitCommits(args) {
|
|
|
167389
168775
|
}
|
|
167390
168776
|
|
|
167391
168777
|
// ../plugin/src/plugin/embedding-bootstrap-helpers.ts
|
|
167392
|
-
import { createHash as
|
|
168778
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
167393
168779
|
init_logger();
|
|
167394
168780
|
var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
167395
168781
|
"embedding.api_key",
|
|
@@ -167411,7 +168797,7 @@ var EMBEDDING_WARNING_TERMS = [
|
|
|
167411
168797
|
];
|
|
167412
168798
|
var loggedFailureSignatures = new Map;
|
|
167413
168799
|
function sha256Prefix2(value, length = 16) {
|
|
167414
|
-
return
|
|
168800
|
+
return createHash10("sha256").update(value).digest("hex").slice(0, length);
|
|
167415
168801
|
}
|
|
167416
168802
|
function warningLooksEmbeddingRelated(message) {
|
|
167417
168803
|
const lower = message.toLowerCase();
|
|
@@ -168457,6 +169843,88 @@ function registerCtxDreamCommand(pi, deps) {
|
|
|
168457
169843
|
});
|
|
168458
169844
|
}
|
|
168459
169845
|
|
|
169846
|
+
// src/commands/ctx-embed-history.ts
|
|
169847
|
+
function registerCtxEmbedHistoryCommand(pi, deps) {
|
|
169848
|
+
pi.registerCommand("ctx-embed-history", {
|
|
169849
|
+
description: "Embed all of this session's history compartments for semantic search, in one pass",
|
|
169850
|
+
handler: async (_args, ctx) => {
|
|
169851
|
+
const sessionId = resolveSessionId(ctx);
|
|
169852
|
+
if (!sessionId) {
|
|
169853
|
+
sendCtxStatusMessage(pi, {
|
|
169854
|
+
title: "/ctx-embed-history",
|
|
169855
|
+
text: `## /ctx-embed-history
|
|
169856
|
+
|
|
169857
|
+
No active Pi session is available.`,
|
|
169858
|
+
level: "error"
|
|
169859
|
+
});
|
|
169860
|
+
return;
|
|
169861
|
+
}
|
|
169862
|
+
if (deps.memoryEnabled === false) {
|
|
169863
|
+
sendCtxStatusMessage(pi, {
|
|
169864
|
+
title: "/ctx-embed-history",
|
|
169865
|
+
text: `## /ctx-embed-history
|
|
169866
|
+
|
|
169867
|
+
Memory is disabled for this project, so there is no semantic embedding to backfill.`,
|
|
169868
|
+
level: "info"
|
|
169869
|
+
});
|
|
169870
|
+
return;
|
|
169871
|
+
}
|
|
169872
|
+
const project = deps.resolveProject?.(ctx) ?? {
|
|
169873
|
+
projectDir: deps.projectDir,
|
|
169874
|
+
projectIdentity: deps.projectIdentity
|
|
169875
|
+
};
|
|
169876
|
+
await ensureProjectRegisteredFromPiDirectory(project.projectDir, deps.db);
|
|
169877
|
+
const outcome = await embedSessionCompartmentChunks(deps.db, project.projectIdentity, sessionId);
|
|
169878
|
+
const { text, level } = (() => {
|
|
169879
|
+
switch (outcome.status) {
|
|
169880
|
+
case "nothing":
|
|
169881
|
+
return {
|
|
169882
|
+
text: `## /ctx-embed-history
|
|
169883
|
+
|
|
169884
|
+
All of this session's history is already embedded.`,
|
|
169885
|
+
level: "info"
|
|
169886
|
+
};
|
|
169887
|
+
case "disabled":
|
|
169888
|
+
return {
|
|
169889
|
+
text: `## /ctx-embed-history
|
|
169890
|
+
|
|
169891
|
+
No embedding provider is configured, so there is nothing to embed.`,
|
|
169892
|
+
level: "info"
|
|
169893
|
+
};
|
|
169894
|
+
case "busy":
|
|
169895
|
+
return {
|
|
169896
|
+
text: `## /ctx-embed-history
|
|
169897
|
+
|
|
169898
|
+
Embedding is already running for this project — ${outcome.total} compartment${outcome.total === 1 ? "" : "s"} still pending. Try again shortly.`,
|
|
169899
|
+
level: "info"
|
|
169900
|
+
};
|
|
169901
|
+
case "stalled":
|
|
169902
|
+
return {
|
|
169903
|
+
text: `## /ctx-embed-history
|
|
169904
|
+
|
|
169905
|
+
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.`,
|
|
169906
|
+
level: "info"
|
|
169907
|
+
};
|
|
169908
|
+
default:
|
|
169909
|
+
return {
|
|
169910
|
+
text: `## /ctx-embed-history
|
|
169911
|
+
|
|
169912
|
+
Embedded ${outcome.embedded} compartment${outcome.embedded === 1 ? "" : "s"} of history for semantic search.`,
|
|
169913
|
+
level: "success"
|
|
169914
|
+
};
|
|
169915
|
+
}
|
|
169916
|
+
})();
|
|
169917
|
+
sendCtxStatusMessage(pi, { title: "/ctx-embed-history", text, level }, {
|
|
169918
|
+
sessionId,
|
|
169919
|
+
projectIdentity: project.projectIdentity,
|
|
169920
|
+
status: outcome.status,
|
|
169921
|
+
embedded: outcome.embedded,
|
|
169922
|
+
total: outcome.total
|
|
169923
|
+
});
|
|
169924
|
+
}
|
|
169925
|
+
});
|
|
169926
|
+
}
|
|
169927
|
+
|
|
168460
169928
|
// ../plugin/src/hooks/magic-context/execute-flush.ts
|
|
168461
169929
|
init_logger();
|
|
168462
169930
|
function executeFlush(db, sessionId) {
|
|
@@ -168870,6 +170338,51 @@ function computePiWorkMetrics(sessionEntries) {
|
|
|
168870
170338
|
return { newWorkTokens, totalInputTokens };
|
|
168871
170339
|
}
|
|
168872
170340
|
|
|
170341
|
+
// ../plugin/src/hooks/magic-context/system-injection-stripper.ts
|
|
170342
|
+
var SYSTEM_INJECTION_MARKERS = [
|
|
170343
|
+
"<!-- OMO_INTERNAL_INITIATOR -->",
|
|
170344
|
+
"[SYSTEM DIRECTIVE: MAGIC-CONTEXT",
|
|
170345
|
+
"[SYSTEM DIRECTIVE: OH-MY-OPENCODE",
|
|
170346
|
+
"[Category+Skill Reminder]",
|
|
170347
|
+
"[EDIT ERROR - IMMEDIATE ACTION REQUIRED]",
|
|
170348
|
+
"[task CALL FAILED - IMMEDIATE RETRY REQUIRED]",
|
|
170349
|
+
"[EMERGENCY CONTEXT WINDOW WARNING]",
|
|
170350
|
+
"Unstable background agent appears idle",
|
|
170351
|
+
"**THE SUBAGENT JUST CLAIMED THIS TASK IS DONE."
|
|
170352
|
+
];
|
|
170353
|
+
var SYSTEM_REMINDER_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
170354
|
+
var OMO_MARKER_REGEX = /<!-- OMO_INTERNAL_INITIATOR -->/g;
|
|
170355
|
+
function stripSystemInjection(text) {
|
|
170356
|
+
let hasInjection = false;
|
|
170357
|
+
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
170358
|
+
if (text.includes(marker)) {
|
|
170359
|
+
hasInjection = true;
|
|
170360
|
+
break;
|
|
170361
|
+
}
|
|
170362
|
+
}
|
|
170363
|
+
if (SYSTEM_REMINDER_REGEX.test(text))
|
|
170364
|
+
hasInjection = true;
|
|
170365
|
+
SYSTEM_REMINDER_REGEX.lastIndex = 0;
|
|
170366
|
+
if (!hasInjection)
|
|
170367
|
+
return null;
|
|
170368
|
+
let cleaned = text;
|
|
170369
|
+
cleaned = cleaned.replace(SYSTEM_REMINDER_REGEX, "");
|
|
170370
|
+
cleaned = cleaned.replace(OMO_MARKER_REGEX, "");
|
|
170371
|
+
cleaned = cleaned.replace(/\[SYSTEM DIRECTIVE: OH-MY-(?:OPENCODE|CLAUDE)[^\]]*\][\s\S]*?(?=\n\n(?!\s*[-*])|$)/g, "");
|
|
170372
|
+
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
170373
|
+
if (marker.startsWith("<!-- ") || marker.startsWith("[SYSTEM DIRECTIVE"))
|
|
170374
|
+
continue;
|
|
170375
|
+
const idx = cleaned.indexOf(marker);
|
|
170376
|
+
if (idx === -1)
|
|
170377
|
+
continue;
|
|
170378
|
+
const blockEnd = cleaned.indexOf(`
|
|
170379
|
+
|
|
170380
|
+
`, idx + marker.length);
|
|
170381
|
+
cleaned = blockEnd !== -1 ? cleaned.slice(0, idx) + cleaned.slice(blockEnd) : cleaned.slice(0, idx);
|
|
170382
|
+
}
|
|
170383
|
+
return cleaned.trim();
|
|
170384
|
+
}
|
|
170385
|
+
|
|
168873
170386
|
// ../plugin/src/hooks/magic-context/apply-operations.ts
|
|
168874
170387
|
var USER_DROP_PREVIEW_CHARS = 250;
|
|
168875
170388
|
var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
@@ -168879,6 +170392,10 @@ function buildReplacementContent(tagId, target) {
|
|
|
168879
170392
|
return `[dropped §${tagId}§]`;
|
|
168880
170393
|
}
|
|
168881
170394
|
const currentContent = target.getContent?.() ?? "";
|
|
170395
|
+
const strippedInjection = stripSystemInjection(currentContent);
|
|
170396
|
+
if (strippedInjection !== null && stripTagPrefix(strippedInjection).trim().length === 0) {
|
|
170397
|
+
return `[dropped §${tagId}§]`;
|
|
170398
|
+
}
|
|
168882
170399
|
const originalText = stripTagPrefix(currentContent);
|
|
168883
170400
|
if (originalText.length <= USER_DROP_PREVIEW_CHARS) {
|
|
168884
170401
|
return `[truncated §${tagId}§]
|
|
@@ -170487,8 +172004,8 @@ var CHANNEL1_SENTINEL = "<system-reminder>";
|
|
|
170487
172004
|
var TOKENS_PER_BYTE = 0.25;
|
|
170488
172005
|
var CHANNEL1_FLOOR_TOKENS = 1e4;
|
|
170489
172006
|
var CHANNEL1_REFIRE_FLOOR_TOKENS = 1e4;
|
|
170490
|
-
function channel1RefireTokens(
|
|
170491
|
-
const scaled = Math.round(0.05 * Math.max(0,
|
|
172007
|
+
function channel1RefireTokens(workingWindowTokens) {
|
|
172008
|
+
const scaled = Math.round(0.05 * Math.max(0, workingWindowTokens));
|
|
170492
172009
|
return Math.max(CHANNEL1_REFIRE_FLOOR_TOKENS, scaled);
|
|
170493
172010
|
}
|
|
170494
172011
|
var S_GENTLE = 0.2;
|
|
@@ -170504,7 +172021,7 @@ function toolOutputTokens(output) {
|
|
|
170504
172021
|
return Math.round(byteSize(output) * TOKENS_PER_BYTE);
|
|
170505
172022
|
}
|
|
170506
172023
|
function decideChannel1(input) {
|
|
170507
|
-
const { undroppedTokens, pressure,
|
|
172024
|
+
const { undroppedTokens, pressure, workingWindowTokens, hasRecentReduce } = input;
|
|
170508
172025
|
const resetCycle = hasRecentReduce || undroppedTokens < input.lastNudgeUndropped;
|
|
170509
172026
|
const lastNudge = resetCycle ? 0 : input.lastNudgeUndropped;
|
|
170510
172027
|
const lastLevel = resetCycle ? "" : input.lastNudgeLevel;
|
|
@@ -170519,7 +172036,7 @@ function decideChannel1(input) {
|
|
|
170519
172036
|
return quiet();
|
|
170520
172037
|
if (undroppedTokens < CHANNEL1_FLOOR_TOKENS)
|
|
170521
172038
|
return quiet();
|
|
170522
|
-
const budget =
|
|
172039
|
+
const budget = workingWindowTokens > 0 ? workingWindowTokens : undroppedTokens || 1;
|
|
170523
172040
|
const severity = undroppedTokens / budget * pressure;
|
|
170524
172041
|
if (severity < S_GENTLE)
|
|
170525
172042
|
return quiet();
|
|
@@ -170531,7 +172048,7 @@ function decideChannel1(input) {
|
|
|
170531
172048
|
else
|
|
170532
172049
|
level = "gentle";
|
|
170533
172050
|
if (lastLevel === "") {
|
|
170534
|
-
if (undroppedTokens < lastNudge + channel1RefireTokens(
|
|
172051
|
+
if (undroppedTokens < lastNudge + channel1RefireTokens(workingWindowTokens)) {
|
|
170535
172052
|
return quiet();
|
|
170536
172053
|
}
|
|
170537
172054
|
} else if (LEVEL_RANK[level] <= LEVEL_RANK[lastLevel]) {
|
|
@@ -170576,13 +172093,13 @@ function buildChannel1Reminder(level, undroppedTokens) {
|
|
|
170576
172093
|
let body;
|
|
170577
172094
|
switch (level) {
|
|
170578
172095
|
case "gentle":
|
|
170579
|
-
body = `You have ~${amount} tokens of tool output you have not reduced. ` + `
|
|
172096
|
+
body = `You have ~${amount} tokens of tool output you have not reduced. ` + `When you are done with earlier outputs, dropping them with ctx_reduce keeps context lean.`;
|
|
170580
172097
|
break;
|
|
170581
172098
|
case "firm":
|
|
170582
|
-
body = `~${amount} tokens of unreduced tool output
|
|
172099
|
+
body = `~${amount} tokens of unreduced tool output has built up. ` + `At your next natural stopping point, consider dropping what you have already processed with ctx_reduce.`;
|
|
170583
172100
|
break;
|
|
170584
172101
|
case "urgent":
|
|
170585
|
-
body = `~${amount} tokens of unreduced tool output remain
|
|
172102
|
+
body = `~${amount} tokens of unreduced tool output remain, and a large span of this session will be comparted before long. ` + `Consider dropping spent outputs with ctx_reduce so the archived span is the part that matters.`;
|
|
170586
172103
|
break;
|
|
170587
172104
|
}
|
|
170588
172105
|
return `
|
|
@@ -170592,53 +172109,6 @@ ${body}
|
|
|
170592
172109
|
</system-reminder>`;
|
|
170593
172110
|
}
|
|
170594
172111
|
|
|
170595
|
-
// ../plugin/src/features/magic-context/memory/constants.ts
|
|
170596
|
-
var V2_MEMORY_CATEGORIES = [
|
|
170597
|
-
"PROJECT_RULES",
|
|
170598
|
-
"ARCHITECTURE",
|
|
170599
|
-
"CONSTRAINTS",
|
|
170600
|
-
"CONFIG_VALUES",
|
|
170601
|
-
"NAMING"
|
|
170602
|
-
];
|
|
170603
|
-
var PROMOTABLE_CATEGORIES = [
|
|
170604
|
-
"PROJECT_RULES",
|
|
170605
|
-
"ARCHITECTURE",
|
|
170606
|
-
"CONSTRAINTS",
|
|
170607
|
-
"CONFIG_VALUES",
|
|
170608
|
-
"NAMING",
|
|
170609
|
-
"ARCHITECTURE_DECISIONS",
|
|
170610
|
-
"CONFIG_DEFAULTS",
|
|
170611
|
-
"USER_PREFERENCES",
|
|
170612
|
-
"USER_DIRECTIVES",
|
|
170613
|
-
"ENVIRONMENT",
|
|
170614
|
-
"WORKFLOW_RULES",
|
|
170615
|
-
"KNOWN_ISSUES"
|
|
170616
|
-
];
|
|
170617
|
-
var CATEGORY_PRIORITY = [
|
|
170618
|
-
"PROJECT_RULES",
|
|
170619
|
-
"ARCHITECTURE",
|
|
170620
|
-
"CONSTRAINTS",
|
|
170621
|
-
"CONFIG_VALUES",
|
|
170622
|
-
"NAMING",
|
|
170623
|
-
"USER_DIRECTIVES",
|
|
170624
|
-
"USER_PREFERENCES",
|
|
170625
|
-
"CONFIG_DEFAULTS",
|
|
170626
|
-
"ARCHITECTURE_DECISIONS",
|
|
170627
|
-
"ENVIRONMENT",
|
|
170628
|
-
"WORKFLOW_RULES",
|
|
170629
|
-
"KNOWN_ISSUES"
|
|
170630
|
-
];
|
|
170631
|
-
var MEMORY_CATEGORY_ORDER_UNKNOWN = 99;
|
|
170632
|
-
var MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
170633
|
-
acc[category] = index;
|
|
170634
|
-
return acc;
|
|
170635
|
-
}, {});
|
|
170636
|
-
var MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
170637
|
-
var CATEGORY_DEFAULT_TTL = {
|
|
170638
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
170639
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
170640
|
-
};
|
|
170641
|
-
|
|
170642
172112
|
// ../plugin/src/shared/bounded-session-map.ts
|
|
170643
172113
|
class BoundedSessionMap {
|
|
170644
172114
|
maxEntries;
|
|
@@ -171049,26 +172519,40 @@ ${sections.join(`
|
|
|
171049
172519
|
var DEFAULT_MEMORY_BUDGET_TOKENS = 8000;
|
|
171050
172520
|
var MEMORY_BLOCK_WRAPPER_TOKENS = 6;
|
|
171051
172521
|
var DEFAULT_USER_PROFILE_BUDGET_TOKENS = 4000;
|
|
172522
|
+
function memoryCanonicalIdentity(memory, workspace) {
|
|
172523
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
172524
|
+
}
|
|
172525
|
+
function memorySelectionOrder(left, right) {
|
|
172526
|
+
if (left.status === "permanent" && right.status !== "permanent")
|
|
172527
|
+
return -1;
|
|
172528
|
+
if (right.status === "permanent" && left.status !== "permanent")
|
|
172529
|
+
return 1;
|
|
172530
|
+
const leftImportance = left.importance ?? Number.NEGATIVE_INFINITY;
|
|
172531
|
+
const rightImportance = right.importance ?? Number.NEGATIVE_INFINITY;
|
|
172532
|
+
const importanceDiff = rightImportance - leftImportance;
|
|
172533
|
+
if (importanceDiff !== 0)
|
|
172534
|
+
return importanceDiff;
|
|
172535
|
+
return left.id - right.id;
|
|
172536
|
+
}
|
|
172537
|
+
function memoryRenderOrder(left, right) {
|
|
172538
|
+
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[left.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
172539
|
+
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[right.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
172540
|
+
const categoryDiff = aPriority - bPriority;
|
|
172541
|
+
if (categoryDiff !== 0)
|
|
172542
|
+
return categoryDiff;
|
|
172543
|
+
return left.id - right.id;
|
|
172544
|
+
}
|
|
171052
172545
|
var maxCompartmentSeqStatements = new WeakMap;
|
|
171053
172546
|
var maxMemoryIdStatements = new WeakMap;
|
|
171054
172547
|
var legacyCompartmentCountStatements = new WeakMap;
|
|
171055
172548
|
var m0CompartmentStatements = new WeakMap;
|
|
171056
172549
|
var newCompartmentStatements = new WeakMap;
|
|
171057
|
-
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
171058
|
-
const selectionOrder = [...memories].sort(
|
|
171059
|
-
if (a.status === "permanent" && b.status !== "permanent")
|
|
171060
|
-
return -1;
|
|
171061
|
-
if (b.status === "permanent" && a.status !== "permanent")
|
|
171062
|
-
return 1;
|
|
171063
|
-
const importanceDiff = (b.importance ?? 50) - (a.importance ?? 50);
|
|
171064
|
-
if (importanceDiff !== 0)
|
|
171065
|
-
return importanceDiff;
|
|
171066
|
-
return a.id - b.id;
|
|
171067
|
-
});
|
|
172550
|
+
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions = {}) {
|
|
172551
|
+
const selectionOrder = [...memories].sort(memorySelectionOrder);
|
|
171068
172552
|
const selected = [];
|
|
171069
172553
|
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
171070
172554
|
for (const memory of selectionOrder) {
|
|
171071
|
-
const memoryTokens = estimateTokens(renderMemoryLineV2(memory));
|
|
172555
|
+
const memoryTokens = estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
171072
172556
|
if (usedTokens + memoryTokens > budgetTokens)
|
|
171073
172557
|
continue;
|
|
171074
172558
|
selected.push(memory);
|
|
@@ -171077,16 +172561,70 @@ function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
|
171077
172561
|
if (selected.length < memories.length) {
|
|
171078
172562
|
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
171079
172563
|
}
|
|
171080
|
-
const renderOrder = [...selected].sort(
|
|
171081
|
-
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[a.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
171082
|
-
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[b.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
171083
|
-
const categoryDiff = aPriority - bPriority;
|
|
171084
|
-
if (categoryDiff !== 0)
|
|
171085
|
-
return categoryDiff;
|
|
171086
|
-
return a.id - b.id;
|
|
171087
|
-
});
|
|
172564
|
+
const renderOrder = [...selected].sort(memoryRenderOrder);
|
|
171088
172565
|
return { selected, renderOrder };
|
|
171089
172566
|
}
|
|
172567
|
+
function trimWorkspaceMemoriesToBudgetV2(sessionId, memories, budgetTokens, workspace, renderOptions = {}) {
|
|
172568
|
+
if (!workspace.isWorkspaced) {
|
|
172569
|
+
return trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions);
|
|
172570
|
+
}
|
|
172571
|
+
const selected = [];
|
|
172572
|
+
const selectedIds = new Set;
|
|
172573
|
+
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
172574
|
+
const tokenCost = (memory) => estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
172575
|
+
const trySelect = (memory) => {
|
|
172576
|
+
if (selectedIds.has(memory.id))
|
|
172577
|
+
return false;
|
|
172578
|
+
const tokens = tokenCost(memory);
|
|
172579
|
+
if (usedTokens + tokens > budgetTokens)
|
|
172580
|
+
return false;
|
|
172581
|
+
selected.push(memory);
|
|
172582
|
+
selectedIds.add(memory.id);
|
|
172583
|
+
usedTokens += tokens;
|
|
172584
|
+
return true;
|
|
172585
|
+
};
|
|
172586
|
+
for (const memory of memories.filter((candidate) => candidate.status === "permanent").sort(memorySelectionOrder)) {
|
|
172587
|
+
trySelect(memory);
|
|
172588
|
+
}
|
|
172589
|
+
const remainingAfterPermanent = Math.max(0, budgetTokens - usedTokens);
|
|
172590
|
+
const floorTokens = remainingAfterPermanent / Math.max(1, workspace.identities.length);
|
|
172591
|
+
const byIdentity = new Map;
|
|
172592
|
+
for (const memory of memories) {
|
|
172593
|
+
if (memory.status === "permanent")
|
|
172594
|
+
continue;
|
|
172595
|
+
const identity = memoryCanonicalIdentity(memory, workspace);
|
|
172596
|
+
if (!identity)
|
|
172597
|
+
continue;
|
|
172598
|
+
const list = byIdentity.get(identity) ?? [];
|
|
172599
|
+
list.push(memory);
|
|
172600
|
+
byIdentity.set(identity, list);
|
|
172601
|
+
}
|
|
172602
|
+
for (const identity of workspace.identities) {
|
|
172603
|
+
let memberTokens = 0;
|
|
172604
|
+
const candidates = (byIdentity.get(identity) ?? []).sort(memorySelectionOrder);
|
|
172605
|
+
for (const memory of candidates) {
|
|
172606
|
+
if (selectedIds.has(memory.id))
|
|
172607
|
+
continue;
|
|
172608
|
+
const tokens = tokenCost(memory);
|
|
172609
|
+
if (memberTokens + tokens > floorTokens)
|
|
172610
|
+
continue;
|
|
172611
|
+
if (usedTokens + tokens > budgetTokens)
|
|
172612
|
+
continue;
|
|
172613
|
+
selected.push(memory);
|
|
172614
|
+
selectedIds.add(memory.id);
|
|
172615
|
+
usedTokens += tokens;
|
|
172616
|
+
memberTokens += tokens;
|
|
172617
|
+
}
|
|
172618
|
+
}
|
|
172619
|
+
const remaining = memories.filter((memory) => !selectedIds.has(memory.id)).sort(memorySelectionOrder);
|
|
172620
|
+
for (const memory of remaining) {
|
|
172621
|
+
trySelect(memory);
|
|
172622
|
+
}
|
|
172623
|
+
if (selected.length < memories.length) {
|
|
172624
|
+
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
172625
|
+
}
|
|
172626
|
+
return { selected, renderOrder: [...selected].sort(memoryRenderOrder) };
|
|
172627
|
+
}
|
|
171090
172628
|
function trimUserMemoriesToBudget(memories, budgetTokens) {
|
|
171091
172629
|
const selected = [];
|
|
171092
172630
|
let usedTokens = 0;
|
|
@@ -171099,15 +172637,16 @@ function trimUserMemoriesToBudget(memories, budgetTokens) {
|
|
|
171099
172637
|
}
|
|
171100
172638
|
return selected;
|
|
171101
172639
|
}
|
|
171102
|
-
function renderMemoryLineV2(memory) {
|
|
171103
|
-
|
|
172640
|
+
function renderMemoryLineV2(memory, sourceName) {
|
|
172641
|
+
const sourceAttr = sourceName ? ` source="${escapeXmlAttr(sourceName)}"` : "";
|
|
172642
|
+
return ` <memory id="${memory.id}" category="${escapeXmlAttr(memory.category)}"${sourceAttr} importance="${memory.importance ?? 50}">${escapeXmlContent(memory.content)}</memory>`;
|
|
171104
172643
|
}
|
|
171105
|
-
function renderMemoryBlockV2(memories, wrapper = "project-memory") {
|
|
172644
|
+
function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions = {}) {
|
|
171106
172645
|
if (memories.length === 0)
|
|
171107
172646
|
return "";
|
|
171108
172647
|
const lines = [`<${wrapper}>`];
|
|
171109
172648
|
for (const memory of memories) {
|
|
171110
|
-
lines.push(renderMemoryLineV2(memory));
|
|
172649
|
+
lines.push(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
171111
172650
|
}
|
|
171112
172651
|
lines.push(`</${wrapper}>`);
|
|
171113
172652
|
return lines.join(`
|
|
@@ -171701,7 +173240,7 @@ async function ensureMemoryEmbeddings(args) {
|
|
|
171701
173240
|
continue;
|
|
171702
173241
|
}
|
|
171703
173242
|
saveEmbedding(args.db, memory.id, embedding, result.modelId);
|
|
171704
|
-
staged.set(memory.id, embedding);
|
|
173243
|
+
staged.set(memory.id, { embedding, modelId: result.modelId });
|
|
171705
173244
|
}
|
|
171706
173245
|
})();
|
|
171707
173246
|
const currentSnapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -171792,6 +173331,37 @@ function previewText(text) {
|
|
|
171792
173331
|
}
|
|
171793
173332
|
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}…`;
|
|
171794
173333
|
}
|
|
173334
|
+
function resolveSearchWorkspaceContext(db, projectPath, identitySet) {
|
|
173335
|
+
const resolved = identitySet ?? resolveWorkspaceIdentitySet(db, projectPath);
|
|
173336
|
+
const isWorkspaced = resolved.identities.length > 1;
|
|
173337
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(db, resolved.identities);
|
|
173338
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : resolved.identities;
|
|
173339
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(resolved.identities.map((identity) => [identity, identity]));
|
|
173340
|
+
const ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === projectPath);
|
|
173341
|
+
return {
|
|
173342
|
+
identities: resolved.identities,
|
|
173343
|
+
expandedIdentities,
|
|
173344
|
+
ownIdentities,
|
|
173345
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(db, projectPath) : null,
|
|
173346
|
+
namesByIdentity: resolved.namesByIdentity,
|
|
173347
|
+
canonicalIdentityByStoredPath,
|
|
173348
|
+
isWorkspaced
|
|
173349
|
+
};
|
|
173350
|
+
}
|
|
173351
|
+
function memoryWorkspaceIdentity(memory, workspace) {
|
|
173352
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
173353
|
+
}
|
|
173354
|
+
function sourceNamesForSearchMemories(args) {
|
|
173355
|
+
if (!args.workspace.isWorkspaced)
|
|
173356
|
+
return;
|
|
173357
|
+
const sourceNames = new Map;
|
|
173358
|
+
for (const memory of args.memories) {
|
|
173359
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
173360
|
+
if (source)
|
|
173361
|
+
sourceNames.set(memory.id, source);
|
|
173362
|
+
}
|
|
173363
|
+
return sourceNames.size > 0 ? sourceNames : undefined;
|
|
173364
|
+
}
|
|
171795
173365
|
function getMessageSearchStatement(db) {
|
|
171796
173366
|
let stmt = messageSearchStatements.get(db);
|
|
171797
173367
|
if (!stmt) {
|
|
@@ -171800,6 +173370,30 @@ function getMessageSearchStatement(db) {
|
|
|
171800
173370
|
}
|
|
171801
173371
|
return stmt;
|
|
171802
173372
|
}
|
|
173373
|
+
var ftsRowCountStatements = new WeakMap;
|
|
173374
|
+
var ftsMatchCountStatements = new WeakMap;
|
|
173375
|
+
function getSessionFtsRowCount(db, sessionId) {
|
|
173376
|
+
let stmt = ftsRowCountStatements.get(db);
|
|
173377
|
+
if (!stmt) {
|
|
173378
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ?");
|
|
173379
|
+
ftsRowCountStatements.set(db, stmt);
|
|
173380
|
+
}
|
|
173381
|
+
const row = stmt.get(sessionId);
|
|
173382
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
173383
|
+
}
|
|
173384
|
+
function countSessionFtsMatches(db, sessionId, ftsQuery) {
|
|
173385
|
+
let stmt = ftsMatchCountStatements.get(db);
|
|
173386
|
+
if (!stmt) {
|
|
173387
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ?");
|
|
173388
|
+
ftsMatchCountStatements.set(db, stmt);
|
|
173389
|
+
}
|
|
173390
|
+
try {
|
|
173391
|
+
const row = stmt.get(sessionId, ftsQuery);
|
|
173392
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
173393
|
+
} catch {
|
|
173394
|
+
return 0;
|
|
173395
|
+
}
|
|
173396
|
+
}
|
|
171803
173397
|
function getMessageOrdinal(value) {
|
|
171804
173398
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
171805
173399
|
return value;
|
|
@@ -171815,25 +173409,63 @@ async function getSemanticScores(args) {
|
|
|
171815
173409
|
if (!args.queryEmbedding || args.memories.length === 0) {
|
|
171816
173410
|
return semanticScores;
|
|
171817
173411
|
}
|
|
171818
|
-
|
|
171819
|
-
|
|
171820
|
-
|
|
171821
|
-
|
|
171822
|
-
|
|
171823
|
-
|
|
171824
|
-
|
|
173412
|
+
if (!args.workspace?.isWorkspaced) {
|
|
173413
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
173414
|
+
const embeddings = await ensureMemoryEmbeddings({
|
|
173415
|
+
db: args.db,
|
|
173416
|
+
projectIdentity: args.projectPath,
|
|
173417
|
+
memories: args.memories,
|
|
173418
|
+
existingEmbeddings: cachedEmbeddings
|
|
173419
|
+
});
|
|
173420
|
+
for (const memory of args.memories) {
|
|
173421
|
+
const memoryEmbedding = embeddings.get(memory.id);
|
|
173422
|
+
if (!memoryEmbedding) {
|
|
173423
|
+
continue;
|
|
173424
|
+
}
|
|
173425
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
173426
|
+
}
|
|
173427
|
+
return semanticScores;
|
|
173428
|
+
}
|
|
173429
|
+
if (!args.queryModelId || args.queryModelId === "off") {
|
|
173430
|
+
return semanticScores;
|
|
173431
|
+
}
|
|
173432
|
+
const workspace = args.workspace;
|
|
173433
|
+
const memoriesByIdentity = new Map;
|
|
171825
173434
|
for (const memory of args.memories) {
|
|
171826
|
-
const
|
|
171827
|
-
if (!
|
|
173435
|
+
const identity = memoryWorkspaceIdentity(memory, workspace);
|
|
173436
|
+
if (!identity)
|
|
173437
|
+
continue;
|
|
173438
|
+
const list = memoriesByIdentity.get(identity) ?? [];
|
|
173439
|
+
list.push(memory);
|
|
173440
|
+
memoriesByIdentity.set(identity, list);
|
|
173441
|
+
}
|
|
173442
|
+
const ownMemories = memoriesByIdentity.get(args.projectPath) ?? [];
|
|
173443
|
+
if (ownMemories.length > 0) {
|
|
173444
|
+
const ownEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
173445
|
+
await ensureMemoryEmbeddings({
|
|
173446
|
+
db: args.db,
|
|
173447
|
+
projectIdentity: args.projectPath,
|
|
173448
|
+
memories: ownMemories,
|
|
173449
|
+
existingEmbeddings: ownEmbeddings
|
|
173450
|
+
});
|
|
173451
|
+
}
|
|
173452
|
+
for (const identity of workspace.identities) {
|
|
173453
|
+
const memberMemories = memoriesByIdentity.get(identity) ?? [];
|
|
173454
|
+
if (memberMemories.length === 0)
|
|
171828
173455
|
continue;
|
|
173456
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, identity);
|
|
173457
|
+
for (const memory of memberMemories) {
|
|
173458
|
+
const memoryEmbedding = cachedEmbeddings.get(memory.id);
|
|
173459
|
+
if (!memoryEmbedding || memoryEmbedding.modelId !== args.queryModelId)
|
|
173460
|
+
continue;
|
|
173461
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
171829
173462
|
}
|
|
171830
|
-
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
|
|
171831
173463
|
}
|
|
171832
173464
|
return semanticScores;
|
|
171833
173465
|
}
|
|
171834
173466
|
function getFtsMatches(args) {
|
|
171835
173467
|
try {
|
|
171836
|
-
return searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
173468
|
+
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);
|
|
171837
173469
|
} catch (error51) {
|
|
171838
173470
|
log(`[search] FTS query failed for "${args.query}": ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
171839
173471
|
return [];
|
|
@@ -171847,8 +173479,11 @@ function selectSemanticCandidates(args) {
|
|
|
171847
173479
|
return args.memories;
|
|
171848
173480
|
}
|
|
171849
173481
|
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
171850
|
-
const
|
|
171851
|
-
|
|
173482
|
+
const embeddingProjects = args.workspace?.isWorkspaced ? args.workspace.identities : [args.projectPath];
|
|
173483
|
+
for (const projectPath of embeddingProjects) {
|
|
173484
|
+
const cachedEmbeddings = peekProjectEmbeddings(projectPath);
|
|
173485
|
+
if (!cachedEmbeddings)
|
|
173486
|
+
continue;
|
|
171852
173487
|
for (const memoryId of cachedEmbeddings.keys()) {
|
|
171853
173488
|
candidateIds.add(memoryId);
|
|
171854
173489
|
}
|
|
@@ -171890,7 +173525,8 @@ function mergeMemoryResults(args) {
|
|
|
171890
173525
|
score,
|
|
171891
173526
|
memoryId: memory.id,
|
|
171892
173527
|
category: memory.category,
|
|
171893
|
-
matchType
|
|
173528
|
+
matchType,
|
|
173529
|
+
sourceName: args.sourceNameByMemoryId?.get(memory.id)
|
|
171894
173530
|
});
|
|
171895
173531
|
}
|
|
171896
173532
|
return results.sort((left, right) => {
|
|
@@ -171904,7 +173540,7 @@ async function searchMemories(args) {
|
|
|
171904
173540
|
if (!args.memoryEnabled) {
|
|
171905
173541
|
return [];
|
|
171906
173542
|
}
|
|
171907
|
-
const memories = getMemoriesByProject(args.db, args.projectPath);
|
|
173543
|
+
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);
|
|
171908
173544
|
if (memories.length === 0) {
|
|
171909
173545
|
return [];
|
|
171910
173546
|
}
|
|
@@ -171912,26 +173548,43 @@ async function searchMemories(args) {
|
|
|
171912
173548
|
db: args.db,
|
|
171913
173549
|
projectPath: args.projectPath,
|
|
171914
173550
|
query: args.query,
|
|
171915
|
-
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
173551
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT,
|
|
173552
|
+
workspace: args.workspace
|
|
171916
173553
|
});
|
|
171917
173554
|
const ftsScores = getFtsScores(ftsMatches);
|
|
171918
173555
|
const semanticCandidates = selectSemanticCandidates({
|
|
171919
173556
|
memories,
|
|
171920
173557
|
projectPath: args.projectPath,
|
|
171921
|
-
ftsMatches
|
|
173558
|
+
ftsMatches,
|
|
173559
|
+
workspace: args.workspace
|
|
171922
173560
|
});
|
|
171923
173561
|
const semanticScores = await getSemanticScores({
|
|
171924
173562
|
db: args.db,
|
|
171925
173563
|
projectPath: args.projectPath,
|
|
171926
173564
|
memories: semanticCandidates,
|
|
171927
|
-
queryEmbedding: args.queryEmbedding
|
|
173565
|
+
queryEmbedding: args.queryEmbedding,
|
|
173566
|
+
queryModelId: args.queryModelId,
|
|
173567
|
+
workspace: args.workspace
|
|
171928
173568
|
});
|
|
171929
173569
|
return mergeMemoryResults({
|
|
171930
173570
|
memories,
|
|
171931
173571
|
semanticScores,
|
|
171932
173572
|
ftsScores,
|
|
171933
173573
|
limit: args.limit,
|
|
171934
|
-
visibleMemoryIds: args.visibleMemoryIds
|
|
173574
|
+
visibleMemoryIds: args.visibleMemoryIds,
|
|
173575
|
+
sourceNameByMemoryId: sourceNamesForSearchMemories({
|
|
173576
|
+
memories,
|
|
173577
|
+
projectPath: args.projectPath,
|
|
173578
|
+
workspace: args.workspace ?? {
|
|
173579
|
+
identities: [args.projectPath],
|
|
173580
|
+
expandedIdentities: [args.projectPath],
|
|
173581
|
+
namesByIdentity: new Map,
|
|
173582
|
+
canonicalIdentityByStoredPath: new Map([[args.projectPath, args.projectPath]]),
|
|
173583
|
+
ownIdentities: [args.projectPath],
|
|
173584
|
+
shareCategories: null,
|
|
173585
|
+
isWorkspaced: false
|
|
173586
|
+
}
|
|
173587
|
+
})
|
|
171935
173588
|
});
|
|
171936
173589
|
}
|
|
171937
173590
|
function linearDecayScore(rank, total) {
|
|
@@ -171962,7 +173615,13 @@ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
|
|
|
171962
173615
|
return result;
|
|
171963
173616
|
}
|
|
171964
173617
|
var RRF_K = 60;
|
|
171965
|
-
var
|
|
173618
|
+
var VERBATIM_RANK_BONUS = 1 / RRF_K;
|
|
173619
|
+
var IDF_FALLOFF = 100;
|
|
173620
|
+
function probeDiscriminationWeight(df, corpusSize) {
|
|
173621
|
+
if (corpusSize <= 0 || df <= 0)
|
|
173622
|
+
return 1;
|
|
173623
|
+
return 1 / (1 + IDF_FALLOFF * df / corpusSize);
|
|
173624
|
+
}
|
|
171966
173625
|
function searchMessages(args) {
|
|
171967
173626
|
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
171968
173627
|
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
@@ -171979,20 +173638,31 @@ function searchMessages(args) {
|
|
|
171979
173638
|
role: row.role
|
|
171980
173639
|
}));
|
|
171981
173640
|
}
|
|
173641
|
+
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId);
|
|
171982
173642
|
const queryLists = [];
|
|
171983
173643
|
if (baseQuery.length > 0) {
|
|
171984
|
-
queryLists.push(
|
|
173644
|
+
queryLists.push({
|
|
173645
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff),
|
|
173646
|
+
weight: 1
|
|
173647
|
+
});
|
|
171985
173648
|
}
|
|
173649
|
+
const probeWeights = new Map;
|
|
171986
173650
|
for (const probe of probes) {
|
|
171987
173651
|
const probeQuery = sanitizeFtsQuery(probe);
|
|
171988
173652
|
if (probeQuery.length === 0)
|
|
171989
173653
|
continue;
|
|
171990
|
-
|
|
173654
|
+
const df = countSessionFtsMatches(args.db, args.sessionId, probeQuery);
|
|
173655
|
+
const weight = probeDiscriminationWeight(df, corpusSize);
|
|
173656
|
+
probeWeights.set(probe, weight);
|
|
173657
|
+
queryLists.push({
|
|
173658
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff),
|
|
173659
|
+
weight
|
|
173660
|
+
});
|
|
171991
173661
|
}
|
|
171992
173662
|
const fused = new Map;
|
|
171993
173663
|
for (const list of queryLists) {
|
|
171994
|
-
list.forEach((row, rank) => {
|
|
171995
|
-
const rrf =
|
|
173664
|
+
list.rows.forEach((row, rank) => {
|
|
173665
|
+
const rrf = list.weight / (RRF_K + rank);
|
|
171996
173666
|
const existing = fused.get(row.messageId);
|
|
171997
173667
|
if (existing) {
|
|
171998
173668
|
existing.score += rrf;
|
|
@@ -172002,26 +173672,107 @@ function searchMessages(args) {
|
|
|
172002
173672
|
});
|
|
172003
173673
|
}
|
|
172004
173674
|
for (const entry of fused.values()) {
|
|
172005
|
-
|
|
172006
|
-
|
|
173675
|
+
let best = 0;
|
|
173676
|
+
for (const probe of probes) {
|
|
173677
|
+
const weight = probeWeights.get(probe) ?? 0;
|
|
173678
|
+
if (weight > best && containsProbeVerbatim(entry.row.content, [probe])) {
|
|
173679
|
+
best = weight;
|
|
173680
|
+
}
|
|
173681
|
+
}
|
|
173682
|
+
if (best > 0) {
|
|
173683
|
+
entry.score += best * VERBATIM_RANK_BONUS;
|
|
172007
173684
|
}
|
|
172008
173685
|
}
|
|
172009
173686
|
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);
|
|
172010
|
-
|
|
172011
|
-
return ranked.map((entry) => ({
|
|
173687
|
+
return ranked.map((entry, rank) => ({
|
|
172012
173688
|
source: "message",
|
|
172013
173689
|
content: previewText(entry.row.content),
|
|
172014
|
-
score:
|
|
173690
|
+
score: linearDecayScore(rank, ranked.length),
|
|
172015
173691
|
messageOrdinal: entry.row.messageOrdinal,
|
|
172016
173692
|
messageId: entry.row.messageId,
|
|
172017
173693
|
role: entry.row.role
|
|
172018
173694
|
}));
|
|
172019
173695
|
}
|
|
173696
|
+
function searchCompartmentChunks(args) {
|
|
173697
|
+
if (!args.queryEmbedding || args.limit <= 0)
|
|
173698
|
+
return [];
|
|
173699
|
+
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
173700
|
+
const rows = loadCompartmentChunkEmbeddingsForSearch(args.db, args.sessionId, args.projectPath, args.modelId);
|
|
173701
|
+
if (rows.length === 0)
|
|
173702
|
+
return [];
|
|
173703
|
+
const byCompartment = new Map;
|
|
173704
|
+
for (const row of rows) {
|
|
173705
|
+
if (cutoff !== null && row.endOrdinal > cutoff) {
|
|
173706
|
+
continue;
|
|
173707
|
+
}
|
|
173708
|
+
const score = normalizeCosineScore(cosineSimilarity(args.queryEmbedding, row.vector));
|
|
173709
|
+
if (score <= 0)
|
|
173710
|
+
continue;
|
|
173711
|
+
const existing = byCompartment.get(row.compartmentId);
|
|
173712
|
+
if (!existing || score > existing.score) {
|
|
173713
|
+
byCompartment.set(row.compartmentId, { row, score });
|
|
173714
|
+
}
|
|
173715
|
+
}
|
|
173716
|
+
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 }) => ({
|
|
173717
|
+
source: "compartment",
|
|
173718
|
+
content: previewText(row.title),
|
|
173719
|
+
score: score * SINGLE_SOURCE_PENALTY,
|
|
173720
|
+
compartmentId: row.compartmentId,
|
|
173721
|
+
sessionId: row.sessionId,
|
|
173722
|
+
title: row.title,
|
|
173723
|
+
startOrdinal: row.startOrdinal,
|
|
173724
|
+
endOrdinal: row.endOrdinal,
|
|
173725
|
+
matchType: "semantic"
|
|
173726
|
+
}));
|
|
173727
|
+
}
|
|
173728
|
+
function mergeMessageAndCompartmentResults(args) {
|
|
173729
|
+
if (args.compartments.length === 0)
|
|
173730
|
+
return args.messages;
|
|
173731
|
+
if (args.messages.length === 0)
|
|
173732
|
+
return args.compartments;
|
|
173733
|
+
const fused = new Map;
|
|
173734
|
+
const add = (key, result, score, tieOrdinal) => {
|
|
173735
|
+
const existing = fused.get(key);
|
|
173736
|
+
if (existing) {
|
|
173737
|
+
existing.score += score;
|
|
173738
|
+
return existing;
|
|
173739
|
+
}
|
|
173740
|
+
const entry = { result, score, tieOrdinal, snippetScore: -1 };
|
|
173741
|
+
fused.set(key, entry);
|
|
173742
|
+
return entry;
|
|
173743
|
+
};
|
|
173744
|
+
args.compartments.forEach((compartment, rank) => {
|
|
173745
|
+
add(`compartment:${compartment.compartmentId}`, compartment, 1 / (RRF_K + rank), compartment.startOrdinal);
|
|
173746
|
+
});
|
|
173747
|
+
for (const [rank, message] of args.messages.entries()) {
|
|
173748
|
+
const containing = args.compartments.find((compartment) => message.messageOrdinal >= compartment.startOrdinal && message.messageOrdinal <= compartment.endOrdinal);
|
|
173749
|
+
const contribution = 1 / (RRF_K + rank);
|
|
173750
|
+
if (!containing) {
|
|
173751
|
+
add(`message:${message.messageId}`, message, contribution, message.messageOrdinal);
|
|
173752
|
+
continue;
|
|
173753
|
+
}
|
|
173754
|
+
const entry = add(`compartment:${containing.compartmentId}`, containing, contribution, containing.startOrdinal);
|
|
173755
|
+
if (message.score > entry.snippetScore && entry.result.source === "compartment") {
|
|
173756
|
+
entry.snippetScore = message.score;
|
|
173757
|
+
entry.result = {
|
|
173758
|
+
...entry.result,
|
|
173759
|
+
matchType: "hybrid",
|
|
173760
|
+
snippet: message.content
|
|
173761
|
+
};
|
|
173762
|
+
}
|
|
173763
|
+
}
|
|
173764
|
+
const ranked = [...fused.values()].sort((left, right) => right.score !== left.score ? right.score - left.score : left.tieOrdinal - right.tieOrdinal).slice(0, args.limit);
|
|
173765
|
+
return ranked.map((entry, rank) => ({
|
|
173766
|
+
...entry.result,
|
|
173767
|
+
score: linearDecayScore(rank, ranked.length)
|
|
173768
|
+
}));
|
|
173769
|
+
}
|
|
172020
173770
|
function getSourceBoost(result) {
|
|
172021
173771
|
switch (result.source) {
|
|
172022
173772
|
case "memory":
|
|
172023
173773
|
return MEMORY_SOURCE_BOOST;
|
|
172024
173774
|
case "message":
|
|
173775
|
+
case "compartment":
|
|
172025
173776
|
return MESSAGE_SOURCE_BOOST;
|
|
172026
173777
|
case "git_commit":
|
|
172027
173778
|
return GIT_COMMIT_SOURCE_BOOST;
|
|
@@ -172039,6 +173790,9 @@ function compareUnifiedResults(left, right) {
|
|
|
172039
173790
|
if (left.source === "message" && right.source === "message") {
|
|
172040
173791
|
return left.messageOrdinal - right.messageOrdinal;
|
|
172041
173792
|
}
|
|
173793
|
+
if (left.source === "compartment" && right.source === "compartment") {
|
|
173794
|
+
return left.startOrdinal - right.startOrdinal;
|
|
173795
|
+
}
|
|
172042
173796
|
if (left.source === "git_commit" && right.source === "git_commit") {
|
|
172043
173797
|
return right.committedAtMs - left.committedAtMs;
|
|
172044
173798
|
}
|
|
@@ -172089,10 +173843,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172089
173843
|
const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
|
|
172090
173844
|
const gitCommitsEnabled = options.gitCommitsEnabled ?? false;
|
|
172091
173845
|
const activeSources = resolveSources(options.sources);
|
|
172092
|
-
const
|
|
173846
|
+
const memoryFeatureEnabled = options.memoryEnabled ?? true;
|
|
173847
|
+
const runMemory = activeSources.has("memory") && memoryFeatureEnabled;
|
|
172093
173848
|
const runMessages = activeSources.has("message");
|
|
172094
173849
|
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
172095
|
-
const
|
|
173850
|
+
const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
|
|
173851
|
+
const needsEmbedding = (runMemory || runGitCommits || runCompartmentChunks) && embeddingEnabled && isEmbeddingRuntimeEnabled();
|
|
172096
173852
|
const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error51) => {
|
|
172097
173853
|
log(`[search] query embedding failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
172098
173854
|
return null;
|
|
@@ -172108,6 +173864,24 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172108
173864
|
probes: messageProbes
|
|
172109
173865
|
}) : [];
|
|
172110
173866
|
const queryEmbedding = await queryEmbeddingPromise;
|
|
173867
|
+
const workspace = resolveSearchWorkspaceContext(db, projectPath);
|
|
173868
|
+
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
173869
|
+
const embeddingModelId = embeddingSnapshot?.modelId;
|
|
173870
|
+
const chunkModelId = embeddingSnapshot?.chunkModelId;
|
|
173871
|
+
const compartmentResults = runCompartmentChunks ? searchCompartmentChunks({
|
|
173872
|
+
db,
|
|
173873
|
+
sessionId,
|
|
173874
|
+
projectPath,
|
|
173875
|
+
queryEmbedding,
|
|
173876
|
+
limit: tierLimit,
|
|
173877
|
+
maxOrdinal: options.maxMessageOrdinal,
|
|
173878
|
+
modelId: chunkModelId && chunkModelId !== "off" ? chunkModelId : null
|
|
173879
|
+
}) : [];
|
|
173880
|
+
const messageLikeResults = mergeMessageAndCompartmentResults({
|
|
173881
|
+
messages: messageResults,
|
|
173882
|
+
compartments: compartmentResults,
|
|
173883
|
+
limit: tierLimit
|
|
173884
|
+
});
|
|
172111
173885
|
const [memoryResults, gitCommitResults] = await Promise.all([
|
|
172112
173886
|
runMemory ? searchMemories({
|
|
172113
173887
|
db,
|
|
@@ -172116,6 +173890,8 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172116
173890
|
limit: tierLimit,
|
|
172117
173891
|
memoryEnabled: true,
|
|
172118
173892
|
queryEmbedding,
|
|
173893
|
+
queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null,
|
|
173894
|
+
workspace,
|
|
172119
173895
|
visibleMemoryIds: options.visibleMemoryIds
|
|
172120
173896
|
}) : Promise.resolve([]),
|
|
172121
173897
|
runGitCommits ? Promise.resolve(searchGitCommits({
|
|
@@ -172126,7 +173902,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
172126
173902
|
queryEmbedding
|
|
172127
173903
|
})) : Promise.resolve([])
|
|
172128
173904
|
]);
|
|
172129
|
-
const results = [...memoryResults, ...
|
|
173905
|
+
const results = [...memoryResults, ...messageLikeResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
|
|
172130
173906
|
const countRetrievals = options.countRetrievals ?? true;
|
|
172131
173907
|
if (countRetrievals) {
|
|
172132
173908
|
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
@@ -172186,6 +173962,11 @@ function renderFragment(result, charCap) {
|
|
|
172186
173962
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
172187
173963
|
return truncate(compressed, charCap);
|
|
172188
173964
|
}
|
|
173965
|
+
case "compartment": {
|
|
173966
|
+
const source = result.snippet ?? result.title;
|
|
173967
|
+
const compressed = cavemanCompress(source, "ultra");
|
|
173968
|
+
return truncate(compressed, charCap);
|
|
173969
|
+
}
|
|
172189
173970
|
}
|
|
172190
173971
|
}
|
|
172191
173972
|
function buildAutoSearchHint(results, options = {}) {
|
|
@@ -172637,10 +174418,11 @@ function maybeChannel1ReminderForToolResult(args) {
|
|
|
172637
174418
|
contextLimit: state.contextLimit,
|
|
172638
174419
|
executeThresholdPercentage: state.executeThresholdPercentage
|
|
172639
174420
|
});
|
|
174421
|
+
const workingWindowTokens = Math.round(state.contextLimit * state.executeThresholdPercentage / 100);
|
|
172640
174422
|
const decision = decideChannel1({
|
|
172641
174423
|
undroppedTokens,
|
|
172642
174424
|
pressure,
|
|
172643
|
-
|
|
174425
|
+
workingWindowTokens,
|
|
172644
174426
|
lastNudgeUndropped: getLastNudgeUndropped(db, sessionId),
|
|
172645
174427
|
lastNudgeLevel: getLastNudgeLevel(db, sessionId),
|
|
172646
174428
|
hasRecentReduce: false
|
|
@@ -172875,51 +174657,6 @@ function planEmergencyDrop(input) {
|
|
|
172875
174657
|
};
|
|
172876
174658
|
}
|
|
172877
174659
|
|
|
172878
|
-
// ../plugin/src/hooks/magic-context/system-injection-stripper.ts
|
|
172879
|
-
var SYSTEM_INJECTION_MARKERS = [
|
|
172880
|
-
"<!-- OMO_INTERNAL_INITIATOR -->",
|
|
172881
|
-
"[SYSTEM DIRECTIVE: MAGIC-CONTEXT",
|
|
172882
|
-
"[SYSTEM DIRECTIVE: OH-MY-OPENCODE",
|
|
172883
|
-
"[Category+Skill Reminder]",
|
|
172884
|
-
"[EDIT ERROR - IMMEDIATE ACTION REQUIRED]",
|
|
172885
|
-
"[task CALL FAILED - IMMEDIATE RETRY REQUIRED]",
|
|
172886
|
-
"[EMERGENCY CONTEXT WINDOW WARNING]",
|
|
172887
|
-
"Unstable background agent appears idle",
|
|
172888
|
-
"**THE SUBAGENT JUST CLAIMED THIS TASK IS DONE."
|
|
172889
|
-
];
|
|
172890
|
-
var SYSTEM_REMINDER_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
172891
|
-
var OMO_MARKER_REGEX = /<!-- OMO_INTERNAL_INITIATOR -->/g;
|
|
172892
|
-
function stripSystemInjection(text) {
|
|
172893
|
-
let hasInjection = false;
|
|
172894
|
-
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
172895
|
-
if (text.includes(marker)) {
|
|
172896
|
-
hasInjection = true;
|
|
172897
|
-
break;
|
|
172898
|
-
}
|
|
172899
|
-
}
|
|
172900
|
-
if (SYSTEM_REMINDER_REGEX.test(text))
|
|
172901
|
-
hasInjection = true;
|
|
172902
|
-
SYSTEM_REMINDER_REGEX.lastIndex = 0;
|
|
172903
|
-
if (!hasInjection)
|
|
172904
|
-
return null;
|
|
172905
|
-
let cleaned = text;
|
|
172906
|
-
cleaned = cleaned.replace(SYSTEM_REMINDER_REGEX, "");
|
|
172907
|
-
cleaned = cleaned.replace(OMO_MARKER_REGEX, "");
|
|
172908
|
-
cleaned = cleaned.replace(/\[SYSTEM DIRECTIVE: OH-MY-(?:OPENCODE|CLAUDE)[^\]]*\][\s\S]*?(?=\n\n(?!\s*[-*])|$)/g, "");
|
|
172909
|
-
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
172910
|
-
if (marker.startsWith("<!-- ") || marker.startsWith("[SYSTEM DIRECTIVE"))
|
|
172911
|
-
continue;
|
|
172912
|
-
const idx = cleaned.indexOf(marker);
|
|
172913
|
-
if (idx === -1)
|
|
172914
|
-
continue;
|
|
172915
|
-
const blockEnd = cleaned.indexOf(`
|
|
172916
|
-
|
|
172917
|
-
`, idx + marker.length);
|
|
172918
|
-
cleaned = blockEnd !== -1 ? cleaned.slice(0, idx) + cleaned.slice(blockEnd) : cleaned.slice(0, idx);
|
|
172919
|
-
}
|
|
172920
|
-
return cleaned.trim();
|
|
172921
|
-
}
|
|
172922
|
-
|
|
172923
174660
|
// src/heuristic-cleanup-pi.ts
|
|
172924
174661
|
init_logger();
|
|
172925
174662
|
var DEDUP_SAFE_TOOLS = new Set([
|
|
@@ -173609,6 +175346,49 @@ function safeGetActiveUserMemoriesPi(db) {
|
|
|
173609
175346
|
function memoryProjectPath(state) {
|
|
173610
175347
|
return state.memoryEnabled === false ? undefined : state.projectIdentity;
|
|
173611
175348
|
}
|
|
175349
|
+
function resolveWorkspaceRenderContextPi(state, db) {
|
|
175350
|
+
const memPath = memoryProjectPath(state);
|
|
175351
|
+
if (!memPath) {
|
|
175352
|
+
return {
|
|
175353
|
+
identities: [],
|
|
175354
|
+
expandedIdentities: [],
|
|
175355
|
+
ownIdentities: [],
|
|
175356
|
+
shareCategories: null,
|
|
175357
|
+
namesByIdentity: new Map,
|
|
175358
|
+
canonicalIdentityByStoredPath: new Map,
|
|
175359
|
+
isWorkspaced: false
|
|
175360
|
+
};
|
|
175361
|
+
}
|
|
175362
|
+
const identitySet = resolveWorkspaceIdentitySet(db, memPath);
|
|
175363
|
+
const isWorkspaced = identitySet.identities.length > 1;
|
|
175364
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(db, identitySet.identities);
|
|
175365
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : identitySet.identities;
|
|
175366
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(identitySet.identities.map((identity) => [identity, identity]));
|
|
175367
|
+
let ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === memPath);
|
|
175368
|
+
if (ownIdentities.length === 0 && expandedIdentities.includes(memPath)) {
|
|
175369
|
+
ownIdentities = [memPath];
|
|
175370
|
+
}
|
|
175371
|
+
return {
|
|
175372
|
+
identities: identitySet.identities,
|
|
175373
|
+
expandedIdentities,
|
|
175374
|
+
ownIdentities,
|
|
175375
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(db, memPath) : null,
|
|
175376
|
+
namesByIdentity: identitySet.namesByIdentity,
|
|
175377
|
+
canonicalIdentityByStoredPath,
|
|
175378
|
+
isWorkspaced
|
|
175379
|
+
};
|
|
175380
|
+
}
|
|
175381
|
+
function sourceNamesForPiMemories(args) {
|
|
175382
|
+
if (!args.projectPath || !args.workspace.isWorkspaced)
|
|
175383
|
+
return;
|
|
175384
|
+
const names = new Map;
|
|
175385
|
+
for (const memory of args.memories) {
|
|
175386
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
175387
|
+
if (source)
|
|
175388
|
+
names.set(memory.id, source);
|
|
175389
|
+
}
|
|
175390
|
+
return names.size > 0 ? names : undefined;
|
|
175391
|
+
}
|
|
173612
175392
|
var EMPTY_PI_HARD_SIGNALS = {
|
|
173613
175393
|
systemHash: "",
|
|
173614
175394
|
modelKey: "",
|
|
@@ -173656,6 +175436,7 @@ function getCachedMarkers(db, state, compartmentsForNormalization) {
|
|
|
173656
175436
|
maxMutationId: meta3.cachedM0MaxMutationId,
|
|
173657
175437
|
maxMemoryMutationId: meta3.cachedM0MaxMemoryMutationId,
|
|
173658
175438
|
projectMemoryEpoch: meta3.cachedM0ProjectMemoryEpoch,
|
|
175439
|
+
workspaceFingerprint: meta3.cachedM0WorkspaceFingerprint,
|
|
173659
175440
|
projectUserProfileVersion: meta3.cachedM0ProjectUserProfileVersion,
|
|
173660
175441
|
projectDocsHash: meta3.cachedM0ProjectDocsHash,
|
|
173661
175442
|
sessionFactsVersion: meta3.cachedM0SessionFactsVersion,
|
|
@@ -173675,15 +175456,17 @@ function readCurrentMarkers(db, state, projectDocsHash) {
|
|
|
173675
175456
|
}
|
|
173676
175457
|
function readCurrentMarkersFromCompartments(db, state, compartments, projectDocsHash) {
|
|
173677
175458
|
const memPath = memoryProjectPath(state);
|
|
173678
|
-
const
|
|
175459
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
175460
|
+
const maxMemoryId = memPath ? workspace.isWorkspaced ? getMaxMemoryIdForProjects(db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryIdForProjects(db, [memPath]) : 0;
|
|
173679
175461
|
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
173680
175462
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
173681
175463
|
return {
|
|
173682
175464
|
maxCompartmentSeq: compartments.length > 0 ? compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ) : EMPTY_MAX_COMPARTMENT_SEQ,
|
|
173683
|
-
maxMemoryId
|
|
175465
|
+
maxMemoryId,
|
|
173684
175466
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
173685
|
-
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
175467
|
+
maxMemoryMutationId: memPath ? workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(db, workspace.expandedIdentities) ?? 0 : getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
173686
175468
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
175469
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(db, workspace.identities) : null,
|
|
173687
175470
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
173688
175471
|
projectDocsHash: projectDocsHash ?? readProjectDocsCanonical(state.projectDirectory).canonicalHash,
|
|
173689
175472
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
@@ -173721,10 +175504,11 @@ function mustMaterializePi(state, db, currentCompartmentsOverride) {
|
|
|
173721
175504
|
if (meta3.cachedM0UpgradeState !== current.upgradeState) {
|
|
173722
175505
|
return { value: true, reason: "renderer_upgrade" };
|
|
173723
175506
|
}
|
|
173724
|
-
if (current.
|
|
173725
|
-
|
|
173726
|
-
|
|
173727
|
-
|
|
175507
|
+
if (current.workspaceFingerprint !== null || (meta3.cachedM0WorkspaceFingerprint ?? null) !== null) {
|
|
175508
|
+
if (current.workspaceFingerprint !== (meta3.cachedM0WorkspaceFingerprint ?? null)) {
|
|
175509
|
+
return { value: true, reason: "project_memory_change" };
|
|
175510
|
+
}
|
|
175511
|
+
} else if (current.projectMemoryEpoch !== (meta3.cachedM0ProjectMemoryEpoch ?? 0)) {
|
|
173728
175512
|
return { value: true, reason: "project_memory_change" };
|
|
173729
175513
|
}
|
|
173730
175514
|
if (current.maxMutationId !== (meta3.cachedM0MaxMutationId ?? 0)) {
|
|
@@ -173741,11 +175525,19 @@ ${memories.map((memory) => `- ${escapeXmlContent(memory.content)}`).join(`
|
|
|
173741
175525
|
`)}
|
|
173742
175526
|
</${wrapper}>`;
|
|
173743
175527
|
}
|
|
173744
|
-
function renderM0Pi(state, db, projectDocs = readProjectDocsCanonical(state.projectDirectory).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride) {
|
|
175528
|
+
function renderM0Pi(state, db, projectDocs = readProjectDocsCanonical(state.projectDirectory).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride, workspaceOverride) {
|
|
173745
175529
|
const memPath = memoryProjectPath(state);
|
|
173746
|
-
const
|
|
173747
|
-
const
|
|
173748
|
-
const
|
|
175530
|
+
const workspace = workspaceOverride ?? resolveWorkspaceRenderContextPi(state, db);
|
|
175531
|
+
const allMemories = memoriesOverride ?? (memPath ? workspace.isWorkspaced ? getMemoriesByProjects(db, workspace.expandedIdentities, ["active", "permanent"], Date.now(), workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(db, memPath, ["active", "permanent"]) : []);
|
|
175532
|
+
const memoryRenderOptions = {
|
|
175533
|
+
sourceNameByMemoryId: sourceNamesForPiMemories({
|
|
175534
|
+
memories: allMemories,
|
|
175535
|
+
projectPath: memPath,
|
|
175536
|
+
workspace
|
|
175537
|
+
})
|
|
175538
|
+
};
|
|
175539
|
+
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;
|
|
175540
|
+
const memoryBlock = memories.length > 0 ? renderMemoryBlockV2(memories, "project-memory", memoryRenderOptions) : undefined;
|
|
173749
175541
|
const baseHistoryBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173750
175542
|
const decayed = renderDecayedCompartments({
|
|
173751
175543
|
compartments: compartmentsOverride ?? getCompartments(db, state.sessionId),
|
|
@@ -173767,10 +175559,19 @@ ${decayed}
|
|
|
173767
175559
|
|
|
173768
175560
|
`).trim();
|
|
173769
175561
|
}
|
|
173770
|
-
function renderedMemoryIdsForPi(state, memories) {
|
|
175562
|
+
function renderedMemoryIdsForPi(state, memories, workspace, db) {
|
|
173771
175563
|
if (memories.length === 0)
|
|
173772
175564
|
return [];
|
|
173773
|
-
|
|
175565
|
+
const resolvedWorkspace = workspace ?? (db ? resolveWorkspaceRenderContextPi(state, db) : undefined);
|
|
175566
|
+
const renderOptions = resolvedWorkspace ? {
|
|
175567
|
+
sourceNameByMemoryId: sourceNamesForPiMemories({
|
|
175568
|
+
memories,
|
|
175569
|
+
projectPath: memoryProjectPath(state),
|
|
175570
|
+
workspace: resolvedWorkspace
|
|
175571
|
+
})
|
|
175572
|
+
} : {};
|
|
175573
|
+
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);
|
|
175574
|
+
return trimmed.renderOrder.map((memory) => memory.id);
|
|
173774
175575
|
}
|
|
173775
175576
|
function isTransientSqliteLockError(error51) {
|
|
173776
175577
|
if (!error51 || typeof error51 !== "object")
|
|
@@ -173795,17 +175596,19 @@ class PiMaterializeContentionError extends Error {
|
|
|
173795
175596
|
function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.projectDirectory), memoryCutoff) {
|
|
173796
175597
|
const memPath = memoryProjectPath(state);
|
|
173797
175598
|
const read = db.transaction(() => {
|
|
175599
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
173798
175600
|
const compartments = getCompartments(db, state.sessionId);
|
|
173799
|
-
const memories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], memoryCutoff) : [];
|
|
175601
|
+
const memories = memPath ? workspace.isWorkspaced ? getMemoriesByProjects(db, workspace.expandedIdentities, ["active", "permanent"], memoryCutoff, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(db, memPath, ["active", "permanent"], memoryCutoff) : [];
|
|
173800
175602
|
const userProfile = safeGetActiveUserMemoriesPi(db);
|
|
173801
175603
|
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
173802
175604
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
173803
175605
|
const markers = {
|
|
173804
175606
|
maxCompartmentSeq: compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ),
|
|
173805
|
-
maxMemoryId:
|
|
175607
|
+
maxMemoryId: memPath ? workspace.isWorkspaced ? getMaxMemoryIdForProjects(db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryIdForProjects(db, [memPath]) : 0,
|
|
173806
175608
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
173807
|
-
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
175609
|
+
maxMemoryMutationId: memPath ? workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(db, workspace.expandedIdentities) ?? 0 : getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
173808
175610
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
175611
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(db, workspace.identities) : null,
|
|
173809
175612
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
173810
175613
|
projectDocsHash: docs.canonicalHash,
|
|
173811
175614
|
sessionFactsVersion: getSessionFactsVersion(db, state.sessionId),
|
|
@@ -173815,7 +175618,7 @@ function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.p
|
|
|
173815
175618
|
systemHash: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).systemHash,
|
|
173816
175619
|
modelKey: (state.hardSignals ?? EMPTY_PI_HARD_SIGNALS).modelKey
|
|
173817
175620
|
};
|
|
173818
|
-
return { docs, markers, compartments, memories, userProfile };
|
|
175621
|
+
return { docs, markers, compartments, memories, userProfile, workspace };
|
|
173819
175622
|
});
|
|
173820
175623
|
return read();
|
|
173821
175624
|
}
|
|
@@ -173826,17 +175629,17 @@ function renderFreshM0PiNonPersisted(state, db) {
|
|
|
173826
175629
|
frozen.markers.materializedAt = cachedMaterializedAt;
|
|
173827
175630
|
const historyBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173828
175631
|
let dpm = 1;
|
|
173829
|
-
let m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile);
|
|
175632
|
+
let m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile, frozen.workspace);
|
|
173830
175633
|
let attempts = 0;
|
|
173831
175634
|
while (historyBudget > 0 && historySliceTokensPi(m0) > historyBudget * 1.05 && attempts < 3) {
|
|
173832
175635
|
dpm *= 1.15;
|
|
173833
|
-
m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile);
|
|
175636
|
+
m0 = renderM0Pi(state, db, docs.renderedBlock, dpm, frozen.memories, frozen.compartments, frozen.userProfile, frozen.workspace);
|
|
173834
175637
|
attempts += 1;
|
|
173835
175638
|
}
|
|
173836
175639
|
return {
|
|
173837
175640
|
m0,
|
|
173838
175641
|
snapshotMarkers: frozen.markers,
|
|
173839
|
-
renderedMemoryIds: renderedMemoryIdsForPi(state, frozen.memories)
|
|
175642
|
+
renderedMemoryIds: renderedMemoryIdsForPi(state, frozen.memories, frozen.workspace, db)
|
|
173840
175643
|
};
|
|
173841
175644
|
}
|
|
173842
175645
|
function materializeM0Pi(state, db) {
|
|
@@ -173846,14 +175649,14 @@ function materializeM0Pi(state, db) {
|
|
|
173846
175649
|
const snapshotMemories = frozen.memories;
|
|
173847
175650
|
const snapshotCompartments = frozen.compartments;
|
|
173848
175651
|
const snapshotUserProfile = frozen.userProfile;
|
|
173849
|
-
const renderedMemoryIds = renderedMemoryIdsForPi(state, snapshotMemories);
|
|
175652
|
+
const renderedMemoryIds = renderedMemoryIdsForPi(state, snapshotMemories, frozen.workspace, db);
|
|
173850
175653
|
let decayPressureMultiplier = 1;
|
|
173851
|
-
let m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile);
|
|
175654
|
+
let m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile, frozen.workspace);
|
|
173852
175655
|
const historyBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
173853
175656
|
let attempts = 0;
|
|
173854
175657
|
while (historyBudget > 0 && historySliceTokensPi(m0) > historyBudget * 1.05 && attempts < 3) {
|
|
173855
175658
|
decayPressureMultiplier *= 1.15;
|
|
173856
|
-
m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile);
|
|
175659
|
+
m0 = renderM0Pi(state, db, docs.renderedBlock, decayPressureMultiplier, snapshotMemories, snapshotCompartments, snapshotUserProfile, frozen.workspace);
|
|
173857
175660
|
attempts += 1;
|
|
173858
175661
|
}
|
|
173859
175662
|
const m0Bytes = Buffer.from(m0, "utf8");
|
|
@@ -173869,7 +175672,8 @@ function materializeM0Pi(state, db) {
|
|
|
173869
175672
|
}
|
|
173870
175673
|
try {
|
|
173871
175674
|
const current = readCurrentMarkers(db, state, phase3ProjectDocsHash);
|
|
173872
|
-
const
|
|
175675
|
+
const memoryEpochStale = current.workspaceFingerprint !== null || snapshotMarkers.workspaceFingerprint !== null ? current.workspaceFingerprint !== snapshotMarkers.workspaceFingerprint : current.projectMemoryEpoch !== snapshotMarkers.projectMemoryEpoch;
|
|
175676
|
+
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;
|
|
173873
175677
|
if (stale) {
|
|
173874
175678
|
db.exec("ROLLBACK");
|
|
173875
175679
|
throw new PiMaterializeContentionError("snapshot changed before persist");
|
|
@@ -173880,6 +175684,7 @@ function materializeM0Pi(state, db) {
|
|
|
173880
175684
|
persistCachedM0(db, state.sessionId, {
|
|
173881
175685
|
m0Bytes,
|
|
173882
175686
|
projectMemoryEpoch: snapshotMarkers.projectMemoryEpoch,
|
|
175687
|
+
workspaceFingerprint: snapshotMarkers.workspaceFingerprint,
|
|
173883
175688
|
projectUserProfileVersion: snapshotMarkers.projectUserProfileVersion,
|
|
173884
175689
|
maxCompartmentSeq: snapshotMarkers.maxCompartmentSeq,
|
|
173885
175690
|
maxMemoryId: snapshotMarkers.maxMemoryId,
|
|
@@ -173944,7 +175749,7 @@ function renderMemoryUpdatesBlockPi(args) {
|
|
|
173944
175749
|
if (args.renderedMemoryIds.length === 0)
|
|
173945
175750
|
return { block: "", count: 0 };
|
|
173946
175751
|
const renderedIds = new Set(args.renderedMemoryIds);
|
|
173947
|
-
const mutations = getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
175752
|
+
const mutations = args.workspace.isWorkspaced ? getMemoryMutationsForRenderByProjects(args.db, args.workspace.expandedIdentities, args.afterId, args.renderedMemoryIds) : getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
173948
175753
|
if (mutations.length === 0)
|
|
173949
175754
|
return { block: "", count: 0 };
|
|
173950
175755
|
const lines = [
|
|
@@ -173975,6 +175780,7 @@ ${lines.join(`
|
|
|
173975
175780
|
}
|
|
173976
175781
|
function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRenderedKeyFilesBlock, compartmentsOverride) {
|
|
173977
175782
|
const sections = [];
|
|
175783
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
173978
175784
|
const keyFiles = renderedKeyFilesBlockPi(state, db, preRenderedKeyFilesBlock);
|
|
173979
175785
|
if (keyFiles)
|
|
173980
175786
|
sections.push(keyFiles);
|
|
@@ -173982,6 +175788,7 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
|
|
|
173982
175788
|
const memoryUpdates = memPath ? renderMemoryUpdatesBlockPi({
|
|
173983
175789
|
db,
|
|
173984
175790
|
projectPath: memPath,
|
|
175791
|
+
workspace,
|
|
173985
175792
|
afterId: markers.maxMemoryMutationId,
|
|
173986
175793
|
renderedMemoryIds
|
|
173987
175794
|
}) : { block: undefined, count: 0 };
|
|
@@ -173996,11 +175803,18 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
|
|
|
173996
175803
|
${body}
|
|
173997
175804
|
</new-compartments>`);
|
|
173998
175805
|
}
|
|
173999
|
-
const newMemories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], markers.materializedAt).filter((memory) => memory.id > markers.maxMemoryId) : [];
|
|
175806
|
+
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) : [];
|
|
174000
175807
|
if (newMemories.length > 0) {
|
|
174001
175808
|
const memoryBudget = state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
174002
|
-
const
|
|
174003
|
-
|
|
175809
|
+
const memoryRenderOptions = {
|
|
175810
|
+
sourceNameByMemoryId: sourceNamesForPiMemories({
|
|
175811
|
+
memories: newMemories,
|
|
175812
|
+
projectPath: memPath,
|
|
175813
|
+
workspace
|
|
175814
|
+
})
|
|
175815
|
+
};
|
|
175816
|
+
const trimmedNewMemories = trimMemoriesToBudgetV2(state.sessionId, newMemories, Math.max(1, Math.floor(memoryBudget * 0.25)), memoryRenderOptions).renderOrder;
|
|
175817
|
+
const newMemoriesBlock = renderMemoryBlockV2(trimmedNewMemories, "new-memories", memoryRenderOptions);
|
|
174004
175818
|
if (newMemoriesBlock)
|
|
174005
175819
|
sections.push(newMemoriesBlock);
|
|
174006
175820
|
}
|
|
@@ -174049,6 +175863,7 @@ function parseMemoryBlockIds(raw) {
|
|
|
174049
175863
|
function readCachedPiM0M1Row(db, sessionId) {
|
|
174050
175864
|
return db.prepare(`SELECT cached_m0_bytes, cached_m1_bytes,
|
|
174051
175865
|
cached_m0_project_memory_epoch,
|
|
175866
|
+
cached_m0_workspace_fingerprint,
|
|
174052
175867
|
cached_m0_project_user_profile_version,
|
|
174053
175868
|
cached_m0_max_compartment_seq,
|
|
174054
175869
|
cached_m0_max_memory_id,
|
|
@@ -174092,6 +175907,7 @@ function markersFromCachedPiRow(row, compartmentsForNormalization) {
|
|
|
174092
175907
|
maxMutationId: row.cached_m0_max_mutation_id,
|
|
174093
175908
|
maxMemoryMutationId: row.cached_m0_max_memory_mutation_id,
|
|
174094
175909
|
projectMemoryEpoch: row.cached_m0_project_memory_epoch,
|
|
175910
|
+
workspaceFingerprint: row.cached_m0_workspace_fingerprint,
|
|
174095
175911
|
projectUserProfileVersion: row.cached_m0_project_user_profile_version,
|
|
174096
175912
|
projectDocsHash: row.cached_m0_project_docs_hash ?? "",
|
|
174097
175913
|
materializedAt: row.cached_m0_materialized_at,
|
|
@@ -174106,7 +175922,7 @@ function cachedPiRowMatchesSnapshot(args) {
|
|
|
174106
175922
|
const rowMarkers = markersFromCachedPiRow(args.row, args.compartmentsForNormalization);
|
|
174107
175923
|
if (!rowMarkers)
|
|
174108
175924
|
return false;
|
|
174109
|
-
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 &&
|
|
175925
|
+
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);
|
|
174110
175926
|
}
|
|
174111
175927
|
function decodeCachedM1(row, sessionId) {
|
|
174112
175928
|
if (!row.cached_m1_bytes) {
|
|
@@ -174317,14 +176133,14 @@ function injectM0M1Pi(state, db, piMessages, entryIds, recomputeM1ThisPass = fal
|
|
|
174317
176133
|
const skippedVisibleMessages = boundaryId ? trimPiMessagesToBoundary(piMessages, entryIds, boundaryId) : 0;
|
|
174318
176134
|
prependM0M1Messages(piMessages, m0, m1);
|
|
174319
176135
|
sessionLog(state.sessionId, `injected m[0]/m[1] into Pi messages (${m0.length} + ${m1.length} bytes, materialized=${materialized}${decision.reason ? ` reason=${decision.reason}` : ""})`);
|
|
176136
|
+
const memPath = memoryProjectPath(state);
|
|
176137
|
+
const workspace = resolveWorkspaceRenderContextPi(state, db);
|
|
176138
|
+
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;
|
|
174320
176139
|
return {
|
|
174321
176140
|
injected: true,
|
|
174322
176141
|
compartmentCount: getCompartments(db, state.sessionId).length,
|
|
174323
176142
|
factCount: 0,
|
|
174324
|
-
memoryCount
|
|
174325
|
-
"active",
|
|
174326
|
-
"permanent"
|
|
174327
|
-
]).length : 0,
|
|
176143
|
+
memoryCount,
|
|
174328
176144
|
skippedVisibleMessages,
|
|
174329
176145
|
m0Materialized: materialized,
|
|
174330
176146
|
m0Reason: decision.reason,
|
|
@@ -174385,21 +176201,48 @@ import * as crypto2 from "node:crypto";
|
|
|
174385
176201
|
|
|
174386
176202
|
// ../plugin/src/features/magic-context/compartment-embedding.ts
|
|
174387
176203
|
init_logger();
|
|
174388
|
-
async function
|
|
176204
|
+
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
174389
176205
|
if (compartments.length === 0)
|
|
174390
176206
|
return;
|
|
174391
|
-
const
|
|
174392
|
-
for (const
|
|
174393
|
-
if (!c.p1 || c.p1.length === 0)
|
|
174394
|
-
continue;
|
|
176207
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
176208
|
+
for (const compartment of compartments) {
|
|
174395
176209
|
try {
|
|
174396
|
-
const
|
|
174397
|
-
|
|
174398
|
-
|
|
174399
|
-
|
|
176210
|
+
const fromMemory = compartment.sourceChunkText ? canonicalizeInMemoryChunkTextForEmbedding(compartment.sourceChunkText, compartment.startMessage, compartment.endMessage) : "";
|
|
176211
|
+
const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage);
|
|
176212
|
+
if (canonicalText.length === 0)
|
|
176213
|
+
continue;
|
|
176214
|
+
const windows = chunkCanonicalText(canonicalText, compartment.startMessage, compartment.endMessage, maxInputTokens);
|
|
176215
|
+
if (windows.length === 0)
|
|
176216
|
+
continue;
|
|
176217
|
+
const currentModelId = getProjectChunkEmbeddingModelId(projectPath);
|
|
176218
|
+
if (currentModelId !== "off" && chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
176219
|
+
continue;
|
|
176220
|
+
}
|
|
176221
|
+
const result = await embedBatchForProject(projectPath, windows.map((window) => window.text));
|
|
176222
|
+
if (!result)
|
|
176223
|
+
continue;
|
|
176224
|
+
if (chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
176225
|
+
continue;
|
|
176226
|
+
}
|
|
176227
|
+
const rows = [];
|
|
176228
|
+
for (const [index, window] of windows.entries()) {
|
|
176229
|
+
const vector = result.vectors[index];
|
|
176230
|
+
if (!vector)
|
|
176231
|
+
continue;
|
|
176232
|
+
rows.push({
|
|
176233
|
+
compartmentId: compartment.id,
|
|
176234
|
+
sessionId,
|
|
176235
|
+
projectPath,
|
|
176236
|
+
window,
|
|
176237
|
+
modelId: currentModelId,
|
|
176238
|
+
vector
|
|
176239
|
+
});
|
|
176240
|
+
}
|
|
176241
|
+
if (rows.length === windows.length) {
|
|
176242
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
174400
176243
|
}
|
|
174401
176244
|
} catch (error51) {
|
|
174402
|
-
sessionLog(sessionId, `compartment embedding failed for compartment ${
|
|
176245
|
+
sessionLog(sessionId, `compartment chunk embedding failed for compartment ${compartment.id}:`, error51);
|
|
174403
176246
|
}
|
|
174404
176247
|
}
|
|
174405
176248
|
}
|
|
@@ -177468,6 +179311,7 @@ async function runPiHistorian(deps) {
|
|
|
177468
179311
|
fallbackModels,
|
|
177469
179312
|
historianChunkTokens,
|
|
177470
179313
|
boundarySnapshot: providedBoundarySnapshot,
|
|
179314
|
+
refreshBoundarySnapshot,
|
|
177471
179315
|
currentContextLimit,
|
|
177472
179316
|
historianTimeoutMs = DEFAULT_HISTORIAN_TIMEOUT_MS2,
|
|
177473
179317
|
twoPass,
|
|
@@ -177521,16 +179365,29 @@ async function runPiHistorian(deps) {
|
|
|
177521
179365
|
return;
|
|
177522
179366
|
}
|
|
177523
179367
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
177524
|
-
|
|
179368
|
+
let boundarySnapshot = providedBoundarySnapshot ?? null;
|
|
177525
179369
|
if (!boundarySnapshot) {
|
|
177526
179370
|
sessionLog(sessionId, "historian no-op: missing protected-tail boundary snapshot from Pi trigger decision");
|
|
177527
179371
|
return;
|
|
177528
179372
|
}
|
|
177529
|
-
|
|
179373
|
+
let validation = boundarySnapshot.rawRangeFingerprint.length > 0 ? validateBoundarySnapshot({
|
|
177530
179374
|
db,
|
|
177531
179375
|
snapshot: boundarySnapshot,
|
|
177532
179376
|
currentContextLimit: currentContextLimit ?? boundarySnapshot.contextLimit
|
|
177533
179377
|
}) : { ok: true };
|
|
179378
|
+
if (!validation.ok && validation.reason === "stale_snapshot" && refreshBoundarySnapshot) {
|
|
179379
|
+
try {
|
|
179380
|
+
const refreshed = refreshBoundarySnapshot();
|
|
179381
|
+
if (hasRunnableCompartmentWindow(refreshed)) {
|
|
179382
|
+
sessionLog(sessionId, `historian: refreshed stale protected-tail snapshot at run time (was: ${validation.detail ?? "stale"}) — eligible head ${refreshed.offset}-${refreshed.eligibleEndOrdinal - 1}`);
|
|
179383
|
+
boundarySnapshot = refreshed;
|
|
179384
|
+
validation = { ok: true };
|
|
179385
|
+
}
|
|
179386
|
+
} catch (error51) {
|
|
179387
|
+
const desc = describeError(error51);
|
|
179388
|
+
sessionLog(sessionId, `historian: failed to refresh stale protected-tail snapshot at run time (${validation.detail ?? "stale"}): ${desc.brief}`);
|
|
179389
|
+
}
|
|
179390
|
+
}
|
|
177534
179391
|
if (!validation.ok) {
|
|
177535
179392
|
sessionLog(sessionId, `historian no-op: stale protected-tail snapshot (${validation.detail ?? validation.reason ?? "unknown"})`);
|
|
177536
179393
|
return;
|
|
@@ -177859,8 +179716,13 @@ ${chunkText}`,
|
|
|
177859
179716
|
}
|
|
177860
179717
|
}
|
|
177861
179718
|
if (embeddingActive) {
|
|
177862
|
-
const
|
|
177863
|
-
|
|
179719
|
+
const chunksToEmbed = newCompartments.map((c, i) => ({
|
|
179720
|
+
id: persistedIds[i],
|
|
179721
|
+
startMessage: c.startMessage,
|
|
179722
|
+
endMessage: c.endMessage,
|
|
179723
|
+
sourceChunkText: chunk.text
|
|
179724
|
+
})).filter((c) => typeof c.id === "number");
|
|
179725
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectPath, chunksToEmbed);
|
|
177864
179726
|
}
|
|
177865
179727
|
onPublished?.();
|
|
177866
179728
|
completedSuccessfully = true;
|
|
@@ -178408,7 +180270,7 @@ function stripPiDroppedPlaceholderMessages(args) {
|
|
|
178408
180270
|
}
|
|
178409
180271
|
|
|
178410
180272
|
// src/system-prompt.ts
|
|
178411
|
-
import { createHash as
|
|
180273
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
178412
180274
|
|
|
178413
180275
|
// ../plugin/src/agents/magic-context-prompt.ts
|
|
178414
180276
|
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
@@ -178559,7 +180421,7 @@ function processSystemPromptForCache(args) {
|
|
|
178559
180421
|
sessionLog(sessionId, `system prompt date frozen: real=${liveDate}, using=${stickyDate} (cache-stable pass)`);
|
|
178560
180422
|
}
|
|
178561
180423
|
}
|
|
178562
|
-
const currentHash =
|
|
180424
|
+
const currentHash = createHash11("md5").update(frozenPrompt).digest("hex");
|
|
178563
180425
|
const hashChanged = !isFirstHash && currentHash !== previousHash;
|
|
178564
180426
|
if (hashChanged) {
|
|
178565
180427
|
sessionLog(sessionId, `system prompt hash changed: ${previousHash} → ${currentHash} (len=${frozenPrompt.length})`);
|
|
@@ -179186,6 +181048,19 @@ function extractStableId(msg, index, entryIds) {
|
|
|
179186
181048
|
// src/context-handler.ts
|
|
179187
181049
|
var FORCE_MATERIALIZATION_PERCENTAGE = 85;
|
|
179188
181050
|
var EMERGENCY_BLOCK_PERCENTAGE = 95;
|
|
181051
|
+
var FORWARD_PRESSURE_LIMIT_FACTOR = 0.85;
|
|
181052
|
+
function applyForwardPressureFloor(trailingPercentage, trailingInputTokens, piUsageTokens, correctedLimit) {
|
|
181053
|
+
const forwardTokens = typeof piUsageTokens === "number" && piUsageTokens > 0 ? piUsageTokens : 0;
|
|
181054
|
+
if (forwardTokens === 0 || !isSaneLimit(correctedLimit)) {
|
|
181055
|
+
return { percentage: trailingPercentage, inputTokens: trailingInputTokens };
|
|
181056
|
+
}
|
|
181057
|
+
const forwardPressureLimit = correctedLimit * FORWARD_PRESSURE_LIMIT_FACTOR;
|
|
181058
|
+
const forwardPercentage = forwardTokens / forwardPressureLimit * 100;
|
|
181059
|
+
return forwardPercentage > trailingPercentage ? {
|
|
181060
|
+
percentage: forwardPercentage,
|
|
181061
|
+
inputTokens: Math.max(trailingInputTokens, forwardTokens)
|
|
181062
|
+
} : { percentage: trailingPercentage, inputTokens: trailingInputTokens };
|
|
181063
|
+
}
|
|
179189
181064
|
var DEFAULT_CLEAR_REASONING_AGE = 50;
|
|
179190
181065
|
var PI_STABLE_ID_SCHEME = 1;
|
|
179191
181066
|
var lastEmergencyNotificationAtMs = new Map;
|
|
@@ -179270,7 +181145,7 @@ function trackSessionForProject(projectIdentity, sessionId) {
|
|
|
179270
181145
|
function isContextHandlerSessionActive(sessionId) {
|
|
179271
181146
|
return activeContextHandlerSessions.has(sessionId);
|
|
179272
181147
|
}
|
|
179273
|
-
function updateSessionProjectTracking(sessionId, projectIdentity) {
|
|
181148
|
+
function updateSessionProjectTracking(sessionId, projectIdentity, db) {
|
|
179274
181149
|
const prev = lastSeenProjectIdentityBySession.get(sessionId);
|
|
179275
181150
|
if (prev && prev !== projectIdentity) {
|
|
179276
181151
|
const prevSessions = sessionsByProject.get(prev);
|
|
@@ -179279,6 +181154,11 @@ function updateSessionProjectTracking(sessionId, projectIdentity) {
|
|
|
179279
181154
|
sessionsByProject.delete(prev);
|
|
179280
181155
|
clearPiSystemPromptSession(sessionId);
|
|
179281
181156
|
}
|
|
181157
|
+
if (db && prev !== projectIdentity) {
|
|
181158
|
+
try {
|
|
181159
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
181160
|
+
} catch {}
|
|
181161
|
+
}
|
|
179282
181162
|
trackSessionForProject(projectIdentity, sessionId);
|
|
179283
181163
|
lastSeenProjectIdentityBySession.set(sessionId, projectIdentity);
|
|
179284
181164
|
}
|
|
@@ -179559,7 +181439,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
179559
181439
|
const schedulerConfig = options.scheduler ?? DEFAULT_SCHEDULER_CONFIG;
|
|
179560
181440
|
const scheduler2 = schedulerFor(options);
|
|
179561
181441
|
const projectIdentity = resolveProjectIdentity(projectDirectory);
|
|
179562
|
-
updateSessionProjectTracking(sessionId, projectIdentity);
|
|
181442
|
+
updateSessionProjectTracking(sessionId, projectIdentity, options.db);
|
|
179563
181443
|
logTransformTiming(sessionId, "findSessionId", tFindSession, `messages=${event.messages.length}`);
|
|
179564
181444
|
const branchEntries = readPiBranchEntriesForContext(ctx, sessionId);
|
|
179565
181445
|
const rawMessageProvider = {
|
|
@@ -179668,9 +181548,10 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
179668
181548
|
if (!usedPersistedUsage && isSaneLimit(usageContextLimit) && usageInputTokens > 0) {
|
|
179669
181549
|
usagePercentage = usageInputTokens / usageContextLimit * 100;
|
|
179670
181550
|
}
|
|
181551
|
+
({ percentage: usagePercentage, inputTokens: usageInputTokens } = applyForwardPressureFloor(usagePercentage, usageInputTokens, piUsage?.tokens, usageContextLimit));
|
|
179671
181552
|
if (needsEmergencyBump) {
|
|
179672
181553
|
sessionLog(sessionId, `transform: overflow recovery flag set — bumping percentage to 95% (detectedLimit=${usageContextLimit ?? "unknown"})`);
|
|
179673
|
-
usagePercentage = 95;
|
|
181554
|
+
usagePercentage = Math.max(usagePercentage, 95);
|
|
179674
181555
|
}
|
|
179675
181556
|
let schedulerDecision;
|
|
179676
181557
|
const tScheduler = performance.now();
|
|
@@ -179895,7 +181776,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
179895
181776
|
let tailToolTokens;
|
|
179896
181777
|
let liveTailTokens;
|
|
179897
181778
|
try {
|
|
179898
|
-
const agg = getActiveTagTokenAggregate(options.db, sessionId);
|
|
181779
|
+
const agg = getActiveTagTokenAggregate(options.db, sessionId, options.protectedTags ?? 20);
|
|
179899
181780
|
tailToolTokens = agg.toolOutput;
|
|
179900
181781
|
liveTailTokens = agg.conversation + agg.toolCall;
|
|
179901
181782
|
} catch {
|
|
@@ -180054,6 +181935,7 @@ function spawnPiHistorianRun(args) {
|
|
|
180054
181935
|
provider: provider2,
|
|
180055
181936
|
unregister,
|
|
180056
181937
|
boundarySnapshot,
|
|
181938
|
+
refreshBoundarySnapshot,
|
|
180057
181939
|
currentContextLimit
|
|
180058
181940
|
} = args;
|
|
180059
181941
|
const holderId = crypto3.randomUUID();
|
|
@@ -180077,6 +181959,7 @@ function spawnPiHistorianRun(args) {
|
|
|
180077
181959
|
fallbackModels: historian.fallbackModels,
|
|
180078
181960
|
historianChunkTokens: historian.historianChunkTokens,
|
|
180079
181961
|
boundarySnapshot,
|
|
181962
|
+
refreshBoundarySnapshot,
|
|
180080
181963
|
currentContextLimit,
|
|
180081
181964
|
historianTimeoutMs: historian.timeoutMs,
|
|
180082
181965
|
twoPass: historian.twoPass,
|
|
@@ -180143,6 +182026,7 @@ function maybeFireHistorian(args) {
|
|
|
180143
182026
|
let usageContextLimit;
|
|
180144
182027
|
try {
|
|
180145
182028
|
const piUsage = ctx.getContextUsage?.();
|
|
182029
|
+
let usageSource;
|
|
180146
182030
|
usageContextLimit = isSaneLimit(piUsage?.contextWindow) ? piUsage.contextWindow : undefined;
|
|
180147
182031
|
if (usageContextLimit === undefined && isSaneLimit(ctx.model?.contextWindow)) {
|
|
180148
182032
|
usageContextLimit = ctx.model.contextWindow;
|
|
@@ -180159,7 +182043,7 @@ function maybeFireHistorian(args) {
|
|
|
180159
182043
|
percentage: sessionMetaForUsage.lastContextPercentage,
|
|
180160
182044
|
inputTokens: sessionMetaForUsage.lastInputTokens
|
|
180161
182045
|
};
|
|
180162
|
-
|
|
182046
|
+
usageSource = "session_meta";
|
|
180163
182047
|
} else {
|
|
180164
182048
|
if (!piUsage || piUsage.tokens === null || piUsage.percent === null || piUsage.contextWindow === 0) {
|
|
180165
182049
|
sessionLog(sessionId, `historian trigger eval: no usage info yet (tokens=${piUsage?.tokens ?? "<no piUsage>"}, percent=${piUsage?.percent ?? "<no piUsage>"}, contextWindow=${piUsage?.contextWindow ?? "<no piUsage>"})`);
|
|
@@ -180170,8 +182054,10 @@ function maybeFireHistorian(args) {
|
|
|
180170
182054
|
percentage: fallbackPercentage,
|
|
180171
182055
|
inputTokens: piUsage.tokens
|
|
180172
182056
|
};
|
|
180173
|
-
|
|
182057
|
+
usageSource = "piUsage fallback";
|
|
180174
182058
|
}
|
|
182059
|
+
usage = applyForwardPressureFloor(usage.percentage, usage.inputTokens, piUsage?.tokens, usageContextLimit);
|
|
182060
|
+
sessionLog(sessionId, `historian trigger eval: usage=${usage.percentage.toFixed(1)}% (${usage.inputTokens} tokens) [${usageSource}], checking trigger...`);
|
|
180175
182061
|
} catch (err) {
|
|
180176
182062
|
sessionLog(sessionId, `historian trigger eval: getContextUsage threw: ${err instanceof Error ? err.message : String(err)}`);
|
|
180177
182063
|
return;
|
|
@@ -180202,10 +182088,14 @@ function maybeFireHistorian(args) {
|
|
|
180202
182088
|
cacheNamespace: `pi:${sessionId}`,
|
|
180203
182089
|
emergencyTailScale
|
|
180204
182090
|
}));
|
|
180205
|
-
|
|
180206
|
-
|
|
180207
|
-
|
|
180208
|
-
|
|
182091
|
+
const resolveRunnablePiBoundarySnapshot = () => {
|
|
182092
|
+
let snapshot = ensureRunnablePiBoundaryForTests(resolvePiBoundarySnapshot());
|
|
182093
|
+
if (!hasRunnableCompartmentWindow(snapshot) && usage.percentage >= 80) {
|
|
182094
|
+
snapshot = ensureRunnablePiBoundaryForTests(resolvePiBoundarySnapshot(usage.percentage >= 95 ? 0.25 : 0.5));
|
|
182095
|
+
}
|
|
182096
|
+
return snapshot;
|
|
182097
|
+
};
|
|
182098
|
+
const boundarySnapshot = resolveRunnablePiBoundarySnapshot();
|
|
180209
182099
|
let triggered = false;
|
|
180210
182100
|
try {
|
|
180211
182101
|
if (isFirstContextPassForSession) {
|
|
@@ -180230,6 +182120,7 @@ Historian previously failed ${failureState.failureCount} time(s), so Magic Conte
|
|
|
180230
182120
|
provider: provider2,
|
|
180231
182121
|
unregister,
|
|
180232
182122
|
boundarySnapshot,
|
|
182123
|
+
refreshBoundarySnapshot: resolveRunnablePiBoundarySnapshot,
|
|
180233
182124
|
currentContextLimit: boundaryContextLimit
|
|
180234
182125
|
});
|
|
180235
182126
|
return;
|
|
@@ -180238,6 +182129,15 @@ Historian previously failed ${failureState.failureCount} time(s), so Magic Conte
|
|
|
180238
182129
|
const trigger = checkCompartmentTrigger(db, sessionId, sessionMeta, usage, 0, triggerInputs.executeThresholdPercentage, triggerInputs.triggerBudget, triggerInputs.clearReasoningAge, triggerInputs.commitClusterTrigger, args.activeTags, boundaryContextLimit);
|
|
180239
182130
|
if (!trigger.shouldFire) {
|
|
180240
182131
|
sessionLog(sessionId, `historian trigger eval: shouldFire=false (no trigger condition met)`);
|
|
182132
|
+
try {
|
|
182133
|
+
const overflowState = getOverflowState(db, sessionId);
|
|
182134
|
+
if (overflowState.needsEmergencyRecovery && usage.percentage < FORCE_MATERIALIZATION_PERCENTAGE && !inFlightHistorian.has(sessionId) && !hasRunnableCompartmentWindow(boundarySnapshot)) {
|
|
182135
|
+
clearEmergencyRecovery(db, sessionId);
|
|
182136
|
+
sessionLog(sessionId, `historian: disarming stale emergency recovery — real pressure ${usage.percentage.toFixed(1)}% with no runnable compartment window (would otherwise bump to 95% every pass)`);
|
|
182137
|
+
}
|
|
182138
|
+
} catch (err) {
|
|
182139
|
+
sessionLog(sessionId, `historian: emergency-recovery disarm check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
182140
|
+
}
|
|
180241
182141
|
return;
|
|
180242
182142
|
}
|
|
180243
182143
|
triggered = true;
|
|
@@ -180253,6 +182153,7 @@ Historian previously failed ${failureState.failureCount} time(s), so Magic Conte
|
|
|
180253
182153
|
resolvedBoundarySnapshot: boundarySnapshot,
|
|
180254
182154
|
triggerBoundarySnapshot: trigger.boundarySnapshot
|
|
180255
182155
|
}),
|
|
182156
|
+
refreshBoundarySnapshot: resolveRunnablePiBoundarySnapshot,
|
|
180256
182157
|
currentContextLimit: boundaryContextLimit
|
|
180257
182158
|
});
|
|
180258
182159
|
} catch (err) {
|
|
@@ -180293,7 +182194,31 @@ async function runPipeline(args) {
|
|
|
180293
182194
|
const alreadyRanHeuristicsThisTurn = currentTurnId !== null && lastHeuristicsTurnIdBySession.get(args.sessionId) === currentTurnId;
|
|
180294
182195
|
const canConsumeDeferredLate = args.schedulerDecision === "execute" || args.forceMaterialization === true || args.contextUsage.percentage >= FORCE_MATERIALIZATION_PERCENTAGE;
|
|
180295
182196
|
const deferredMaterializeEligible = canConsumeDeferredLate && deferredMaterializationSessions.has(args.sessionId);
|
|
180296
|
-
const
|
|
182197
|
+
const piHardSignals = args.injection ? (() => {
|
|
182198
|
+
const hardMeta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
182199
|
+
let piTtlMs = 5 * 60 * 1000;
|
|
182200
|
+
try {
|
|
182201
|
+
piTtlMs = parseCacheTtl(hardMeta.cacheTtl);
|
|
182202
|
+
} catch {}
|
|
182203
|
+
return {
|
|
182204
|
+
systemHash: typeof hardMeta.systemPromptHash === "string" ? hardMeta.systemPromptHash : "",
|
|
182205
|
+
modelKey: liveModelBySession.get(args.sessionId) ?? "",
|
|
182206
|
+
cacheExpired: hardMeta.lastResponseTime > 0 && Date.now() - hardMeta.lastResponseTime >= piTtlMs,
|
|
182207
|
+
lastResponseTime: hardMeta.lastResponseTime
|
|
182208
|
+
};
|
|
182209
|
+
})() : undefined;
|
|
182210
|
+
const m0HardFoldThisPass = args.injection && piHardSignals ? mustMaterializePi({
|
|
182211
|
+
sessionId: args.sessionId,
|
|
182212
|
+
projectIdentity: args.projectIdentity,
|
|
182213
|
+
projectDirectory: args.projectDirectory,
|
|
182214
|
+
memoryEnabled: args.injection.memoryEnabled,
|
|
182215
|
+
injectionBudgetTokens: args.injection.injectionBudgetTokens,
|
|
182216
|
+
historyBudgetTokens: args.injection.historyBudgetTokens,
|
|
182217
|
+
keyFilesEnabled: args.injection.keyFilesEnabled,
|
|
182218
|
+
keyFilesTokenBudget: args.injection.keyFilesTokenBudget,
|
|
182219
|
+
hardSignals: piHardSignals
|
|
182220
|
+
}, args.db, getCompartments(args.db, args.sessionId)).value : false;
|
|
182221
|
+
const shouldRunHeuristics = args.heuristics !== undefined && (args.forceMaterialization === true || hasPendingMaterialization(args.sessionId) || deferredMaterializeEligible || m0HardFoldThisPass || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
|
|
180297
182222
|
const entryFingerprintByMessageId = buildEntryFingerprintMap(args.messages, stableIdResolver);
|
|
180298
182223
|
adoptPiFallbackTags(args.db, args.sessionId, args.tagger, entryFingerprintByMessageId);
|
|
180299
182224
|
const tTag = performance.now();
|
|
@@ -180320,12 +182245,12 @@ async function runPipeline(args) {
|
|
|
180320
182245
|
const deferredMaterializationWasPending = deferredMaterializationSessions.has(args.sessionId);
|
|
180321
182246
|
const deferredHistoryRefreshWasPending = deferredHistoryWasPendingAtPassStart;
|
|
180322
182247
|
const pendingOps = getPendingOps(args.db, args.sessionId);
|
|
180323
|
-
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal;
|
|
182248
|
+
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal || m0HardFoldThisPass;
|
|
180324
182249
|
const deferredMaterialize = canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
180325
182250
|
const deferredHistoryRefresh = canConsumeDeferredLate && deferredHistoryRefreshWasPending;
|
|
180326
182251
|
const shouldApplyPendingOps = baseShouldApplyPendingOps || deferredMaterialize;
|
|
180327
182252
|
if (shouldApplyPendingOps) {
|
|
180328
|
-
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
182253
|
+
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})`;
|
|
180329
182254
|
sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
|
|
180330
182255
|
try {
|
|
180331
182256
|
const tApplyPending = performance.now();
|
|
@@ -180396,7 +182321,7 @@ async function runPipeline(args) {
|
|
|
180396
182321
|
const activeTags = getActiveTagsBySession(args.db, args.sessionId);
|
|
180397
182322
|
logTransformTiming(args.sessionId, "getActiveTagsBySession", tActiveTags, `count=${activeTags.length}`);
|
|
180398
182323
|
if (shouldRunHeuristics) {
|
|
180399
|
-
const reason = args.forceMaterialization ? "force_materialization" : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
182324
|
+
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})`;
|
|
180400
182325
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=n/a`);
|
|
180401
182326
|
} else {
|
|
180402
182327
|
const reason = args.heuristics === undefined ? "disabled" : "scheduler_defer";
|
|
@@ -180484,17 +182409,6 @@ async function runPipeline(args) {
|
|
|
180484
182409
|
if (args.injection) {
|
|
180485
182410
|
try {
|
|
180486
182411
|
const tInjection = performance.now();
|
|
180487
|
-
const hardMeta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
180488
|
-
let piTtlMs = 5 * 60 * 1000;
|
|
180489
|
-
try {
|
|
180490
|
-
piTtlMs = parseCacheTtl(hardMeta.cacheTtl);
|
|
180491
|
-
} catch {}
|
|
180492
|
-
const piHardSignals = {
|
|
180493
|
-
systemHash: typeof hardMeta.systemPromptHash === "string" ? hardMeta.systemPromptHash : "",
|
|
180494
|
-
modelKey: liveModelBySession.get(args.sessionId) ?? "",
|
|
180495
|
-
cacheExpired: hardMeta.lastResponseTime > 0 && Date.now() - hardMeta.lastResponseTime >= piTtlMs,
|
|
180496
|
-
lastResponseTime: hardMeta.lastResponseTime
|
|
180497
|
-
};
|
|
180498
182412
|
injectionResult = injectM0M1Pi({
|
|
180499
182413
|
sessionId: args.sessionId,
|
|
180500
182414
|
projectIdentity: args.projectIdentity,
|
|
@@ -181584,8 +183498,12 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
181584
183498
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181585
183499
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
181586
183500
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181587
|
-
const
|
|
181588
|
-
|
|
183501
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
183502
|
+
id: c.id,
|
|
183503
|
+
startMessage: c.startMessage,
|
|
183504
|
+
endMessage: c.endMessage
|
|
183505
|
+
}));
|
|
183506
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
181589
183507
|
}
|
|
181590
183508
|
const lastCompartmentEnd2 = promoted2.compartments[promoted2.compartments.length - 1]?.endMessage ?? 0;
|
|
181591
183509
|
if (lastCompartmentEnd2 > 0) {
|
|
@@ -181798,8 +183716,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
181798
183716
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181799
183717
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
181800
183718
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181801
|
-
const
|
|
181802
|
-
|
|
183719
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
183720
|
+
id: c.id,
|
|
183721
|
+
startMessage: c.startMessage,
|
|
183722
|
+
endMessage: c.endMessage
|
|
183723
|
+
}));
|
|
183724
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
181803
183725
|
}
|
|
181804
183726
|
if (lastCompartmentEnd > 0) {
|
|
181805
183727
|
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
@@ -181956,8 +183878,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
181956
183878
|
if (deps.memoryEnabled !== false) {
|
|
181957
183879
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
181958
183880
|
const liveCompartments = getCompartments(db, sessionId);
|
|
181959
|
-
const
|
|
181960
|
-
|
|
183881
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
183882
|
+
id: c.id,
|
|
183883
|
+
startMessage: c.startMessage,
|
|
183884
|
+
endMessage: c.endMessage
|
|
183885
|
+
}));
|
|
183886
|
+
Promise.resolve(deps.ensureProjectRegistered?.(sessionDirectory, db)).then(() => embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed));
|
|
181961
183887
|
}
|
|
181962
183888
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
181963
183889
|
if (lastEnd > 0) {
|
|
@@ -182403,7 +184329,7 @@ function renderStatusText(ctx, db, sessionId) {
|
|
|
182403
184329
|
const pct = typeof usage?.percent === "number" ? usage.percent : undefined;
|
|
182404
184330
|
const meta3 = readSessionMetaStatus(db, sessionId);
|
|
182405
184331
|
const state = renderHistorianState(meta3, recompSessions.has(sessionId));
|
|
182406
|
-
return `
|
|
184332
|
+
return `MC: ${inputTokens === undefined ? "--" : fmt(inputTokens)} (${pct === undefined ? "--" : `${Math.round(pct)}%`}) · ${state}`;
|
|
182407
184333
|
}
|
|
182408
184334
|
function renderHistorianState(meta3, recompActive) {
|
|
182409
184335
|
const failureCount = meta3?.historian_failure_count ?? 0;
|
|
@@ -182592,6 +184518,11 @@ Historian recomp started. Rebuilding compartments and facts from raw Pi session
|
|
|
182592
184518
|
fallbackModelId: ctx.model ? `${ctx.model.provider}/${ctx.model.id}` : undefined
|
|
182593
184519
|
}, parsed.kind === "partial" ? { range: parsed.range } : {});
|
|
182594
184520
|
if (result.published) {
|
|
184521
|
+
try {
|
|
184522
|
+
clearEmergencyRecovery(deps.db, sessionId);
|
|
184523
|
+
} catch (recoveryError) {
|
|
184524
|
+
sessionLog(sessionId, `/ctx-recomp: clearEmergencyRecovery failed (continuing): ${describeError(recoveryError).brief}`);
|
|
184525
|
+
}
|
|
182595
184526
|
try {
|
|
182596
184527
|
stagePiRecompMarker({ db: deps.db, sessionId, ctx });
|
|
182597
184528
|
} catch (markerError) {
|
|
@@ -182769,7 +184700,7 @@ function applyMemoryMigration(db, projectPath, result) {
|
|
|
182769
184700
|
inserted++;
|
|
182770
184701
|
}
|
|
182771
184702
|
if (removed > 0 || inserted > 0) {
|
|
182772
|
-
|
|
184703
|
+
bumpEpochsForWorkspaceMembers(db, projectPath);
|
|
182773
184704
|
}
|
|
182774
184705
|
})();
|
|
182775
184706
|
return { removed, inserted };
|
|
@@ -183245,7 +185176,7 @@ function formatThresholdPercent(value) {
|
|
|
183245
185176
|
// package.json
|
|
183246
185177
|
var package_default = {
|
|
183247
185178
|
name: "@wolfx/pi-magic-context",
|
|
183248
|
-
version: "0.
|
|
185179
|
+
version: "0.24.1",
|
|
183249
185180
|
type: "module",
|
|
183250
185181
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
183251
185182
|
main: "dist/index.js",
|
|
@@ -188136,6 +190067,23 @@ function createCtxMemoryTool(deps) {
|
|
|
188136
190067
|
}
|
|
188137
190068
|
const projectIdentity = resolveProjectIdentity(ctx.cwd);
|
|
188138
190069
|
await deps.ensureProjectRegistered?.(ctx.cwd, deps.db);
|
|
190070
|
+
const workspaceIdentitySet = resolveWorkspaceIdentitySet(deps.db, projectIdentity);
|
|
190071
|
+
const expandedWorkspace = expandWorkspaceIdentitySetWithAliases(deps.db, workspaceIdentitySet.identities);
|
|
190072
|
+
const workspaceVisibleIdentities = workspaceIdentitySet.identities.length > 1 ? expandedWorkspace.expandedIdentities : workspaceIdentitySet.identities;
|
|
190073
|
+
const targetIdentityForStoredPath = (rawProjectPath) => workspaceIdentitySet.identities.length > 1 ? resolveStoredPathWorkspaceIdentity(rawProjectPath, workspaceIdentitySet.identities, expandedWorkspace.canonicalIdentityByStoredPath) ?? normalizeStoredProjectPath(rawProjectPath) : normalizeStoredProjectPath(rawProjectPath);
|
|
190074
|
+
const toolShareCategories = workspaceIdentitySet.identities.length > 1 ? resolveWorkspaceShareCategories(deps.db, projectIdentity) : null;
|
|
190075
|
+
const memoryVisibleToTool = (memory2) => {
|
|
190076
|
+
if (workspaceIdentitySet.identities.length <= 1) {
|
|
190077
|
+
return storedPathBelongsToIdentity(memory2.projectPath, projectIdentity);
|
|
190078
|
+
}
|
|
190079
|
+
if (!storedPathBelongsToWorkspace(memory2.projectPath, workspaceIdentitySet.identities, workspaceVisibleIdentities, expandedWorkspace.canonicalIdentityByStoredPath)) {
|
|
190080
|
+
return false;
|
|
190081
|
+
}
|
|
190082
|
+
const isOwn = targetIdentityForStoredPath(memory2.projectPath) === projectIdentity;
|
|
190083
|
+
if (isOwn)
|
|
190084
|
+
return true;
|
|
190085
|
+
return toolShareCategories === null || toolShareCategories.includes(memory2.category);
|
|
190086
|
+
};
|
|
188139
190087
|
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
188140
190088
|
if (snapshot ? !snapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
188141
190089
|
return err2("Cross-session memory is disabled for this project.");
|
|
@@ -188182,28 +190130,34 @@ function createCtxMemoryTool(deps) {
|
|
|
188182
190130
|
return err2("Error: 'content' is required when action is 'update'.");
|
|
188183
190131
|
}
|
|
188184
190132
|
const memory2 = getMemoryById(deps.db, updateId);
|
|
188185
|
-
if (!memory2 || !
|
|
190133
|
+
if (!memory2 || !memoryVisibleToTool(memory2)) {
|
|
188186
190134
|
return err2(`Error: Memory with ID ${updateId} was not found.`);
|
|
188187
190135
|
}
|
|
188188
190136
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
188189
190137
|
return err2(inactiveMemoryError(updateId, "updating"));
|
|
188190
190138
|
}
|
|
188191
190139
|
const normalizedHash = computeNormalizedHash(content);
|
|
188192
|
-
const
|
|
190140
|
+
const targetIdentity = targetIdentityForStoredPath(memory2.projectPath);
|
|
190141
|
+
const duplicate = getMemoryByHash(deps.db, targetIdentity, memory2.category, normalizedHash);
|
|
188193
190142
|
if (duplicate && duplicate.id !== memory2.id) {
|
|
188194
190143
|
return err2(`Error: Memory content already exists as ID ${duplicate.id}; merge or archive duplicates instead.`);
|
|
188195
190144
|
}
|
|
188196
190145
|
deps.db.transaction(() => {
|
|
188197
190146
|
updateMemoryContent(deps.db, memory2.id, content, normalizedHash);
|
|
188198
190147
|
queueMemoryMutation(deps.db, {
|
|
188199
|
-
projectPath:
|
|
190148
|
+
projectPath: targetIdentity,
|
|
188200
190149
|
mutationType: "update",
|
|
188201
190150
|
targetMemoryId: memory2.id,
|
|
188202
190151
|
category: memory2.category,
|
|
188203
190152
|
newContent: content
|
|
188204
190153
|
});
|
|
188205
190154
|
})();
|
|
188206
|
-
queueEmbedding({
|
|
190155
|
+
queueEmbedding({
|
|
190156
|
+
deps,
|
|
190157
|
+
projectIdentity: targetIdentity,
|
|
190158
|
+
memoryId: memory2.id,
|
|
190159
|
+
content
|
|
190160
|
+
});
|
|
188207
190161
|
return ok2(`Updated memory [ID: ${memory2.id}] in ${memory2.category}.`);
|
|
188208
190162
|
}
|
|
188209
190163
|
if (params.action === "merge") {
|
|
@@ -188223,7 +190177,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188223
190177
|
return err2("Error: One or more source memories were not found.");
|
|
188224
190178
|
}
|
|
188225
190179
|
if (!dreamerAllowed) {
|
|
188226
|
-
const foreign = sourceMemories.find((memory2) => !
|
|
190180
|
+
const foreign = sourceMemories.find((memory2) => !memoryVisibleToTool(memory2));
|
|
188227
190181
|
if (foreign) {
|
|
188228
190182
|
return err2(`Error: Memory with ID ${foreign.id} was not found.`);
|
|
188229
190183
|
}
|
|
@@ -188312,26 +190266,36 @@ function createCtxMemoryTool(deps) {
|
|
|
188312
190266
|
return ok2(`Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`);
|
|
188313
190267
|
}
|
|
188314
190268
|
if (params.action === "archive") {
|
|
188315
|
-
const
|
|
188316
|
-
if (!
|
|
190269
|
+
const rawArchiveIds = params.ids;
|
|
190270
|
+
if (!rawArchiveIds || rawArchiveIds.length === 0 || !rawArchiveIds.every(Number.isInteger)) {
|
|
188317
190271
|
return err2("Error: 'ids' must contain at least one integer memory ID when action is 'archive'.");
|
|
188318
190272
|
}
|
|
190273
|
+
const archiveIds = [...new Set(rawArchiveIds)];
|
|
188319
190274
|
for (const memoryId of archiveIds) {
|
|
188320
190275
|
const memory2 = getMemoryById(deps.db, memoryId);
|
|
188321
|
-
if (!memory2 || !
|
|
190276
|
+
if (!memory2 || !memoryVisibleToTool(memory2)) {
|
|
188322
190277
|
return err2(`Error: Memory with ID ${memoryId} was not found.`);
|
|
188323
190278
|
}
|
|
188324
190279
|
if (!dreamerAllowed && !isPrimaryMutableMemory(memory2)) {
|
|
188325
190280
|
return err2(inactiveMemoryError(memoryId, "archiving"));
|
|
188326
190281
|
}
|
|
188327
190282
|
}
|
|
190283
|
+
const targets = archiveIds.map((memoryId) => {
|
|
190284
|
+
const memory2 = getMemoryById(deps.db, memoryId);
|
|
190285
|
+
if (!memory2)
|
|
190286
|
+
throw new Error(`validated memory ${memoryId} disappeared`);
|
|
190287
|
+
return {
|
|
190288
|
+
memoryId,
|
|
190289
|
+
projectIdentity: targetIdentityForStoredPath(memory2.projectPath)
|
|
190290
|
+
};
|
|
190291
|
+
});
|
|
188328
190292
|
deps.db.transaction(() => {
|
|
188329
|
-
for (const
|
|
188330
|
-
archiveMemory(deps.db, memoryId, params.reason);
|
|
190293
|
+
for (const target2 of targets) {
|
|
190294
|
+
archiveMemory(deps.db, target2.memoryId, params.reason);
|
|
188331
190295
|
queueMemoryMutation(deps.db, {
|
|
188332
|
-
projectPath: projectIdentity,
|
|
190296
|
+
projectPath: target2.projectIdentity,
|
|
188333
190297
|
mutationType: "archive",
|
|
188334
|
-
targetMemoryId: memoryId
|
|
190298
|
+
targetMemoryId: target2.memoryId
|
|
188335
190299
|
});
|
|
188336
190300
|
}
|
|
188337
190301
|
})();
|
|
@@ -188839,8 +190803,9 @@ function formatAge2(committedAtMs) {
|
|
|
188839
190803
|
}
|
|
188840
190804
|
function formatResult(result, index) {
|
|
188841
190805
|
if (result.source === "memory") {
|
|
190806
|
+
const source = result.sourceName ? ` source=${result.sourceName}` : "";
|
|
188842
190807
|
return [
|
|
188843
|
-
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category} match=${result.matchType}`,
|
|
190808
|
+
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category}${source} match=${result.matchType}`,
|
|
188844
190809
|
result.content
|
|
188845
190810
|
].join(`
|
|
188846
190811
|
`);
|
|
@@ -188850,6 +190815,13 @@ function formatResult(result, index) {
|
|
|
188850
190815
|
`[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge2(result.committedAtMs)} match=${result.matchType}`,
|
|
188851
190816
|
result.content
|
|
188852
190817
|
].join(`
|
|
190818
|
+
`);
|
|
190819
|
+
}
|
|
190820
|
+
if (result.source === "compartment") {
|
|
190821
|
+
return [
|
|
190822
|
+
`[${index}] [message] score=${result.score.toFixed(2)} compartment_id=${result.compartmentId} range=${result.startOrdinal}-${result.endOrdinal} match=${result.matchType} title=${result.title}`,
|
|
190823
|
+
result.snippet ? `Snippet: ${result.snippet}` : result.content
|
|
190824
|
+
].join(`
|
|
188853
190825
|
`);
|
|
188854
190826
|
}
|
|
188855
190827
|
const expandStart = Math.max(1, result.messageOrdinal - 3);
|
|
@@ -188865,7 +190837,7 @@ function formatSearchResults(query, results) {
|
|
|
188865
190837
|
return `No results found for "${query}" across memories, git commits, or message history.`;
|
|
188866
190838
|
}
|
|
188867
190839
|
const bodyParts = results.map((result, index) => formatResult(result, index + 1));
|
|
188868
|
-
if (results.some((result) => result.source === "message")) {
|
|
190840
|
+
if (results.some((result) => result.source === "message" || result.source === "compartment")) {
|
|
188869
190841
|
bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
|
|
188870
190842
|
}
|
|
188871
190843
|
const body = bodyParts.join(`
|
|
@@ -189361,6 +191333,14 @@ async function src_default2(pi) {
|
|
|
189361
191333
|
onProjectSeen: (identity) => seenDreamerProjectIdentities.add(identity)
|
|
189362
191334
|
});
|
|
189363
191335
|
info("registered /ctx-dream");
|
|
191336
|
+
registerCtxEmbedHistoryCommand(pi, {
|
|
191337
|
+
db,
|
|
191338
|
+
projectDir,
|
|
191339
|
+
projectIdentity,
|
|
191340
|
+
memoryEnabled: config2.memory.enabled,
|
|
191341
|
+
resolveProject: resolveCurrentProject
|
|
191342
|
+
});
|
|
191343
|
+
info("registered /ctx-embed-history");
|
|
189364
191344
|
const dreamerConfig = resolveDreamerFromConfig(config2);
|
|
189365
191345
|
if (dreamerConfig) {
|
|
189366
191346
|
registerPiDreamerProject({
|