@wolfx/opencode-magic-context 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/schema/magic-context.d.ts +10 -3
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/builtin-commands/commands.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts +70 -0
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -0
- package/dist/features/magic-context/compartment-embedding.d.ts +22 -26
- package/dist/features/magic-context/compartment-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-backfill.d.ts +3 -2
- package/dist/features/magic-context/memory/embedding-backfill.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-cache.d.ts +3 -2
- package/dist/features/magic-context/memory/embedding-cache.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts +2 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-openai.d.ts +3 -0
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-provider.d.ts +2 -0
- package/dist/features/magic-context/memory/embedding-provider.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts +1 -1
- package/dist/features/magic-context/memory/embedding.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts +5 -1
- package/dist/features/magic-context/memory/storage-memory-embeddings.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory-fts.d.ts +1 -7
- package/dist/features/magic-context/memory/storage-memory-fts.d.ts.map +1 -1
- package/dist/features/magic-context/memory/storage-memory.d.ts +18 -12
- package/dist/features/magic-context/memory/storage-memory.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +53 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/search.d.ts +14 -1
- package/dist/features/magic-context/search.d.ts.map +1 -1
- package/dist/features/magic-context/session-project-storage.d.ts +17 -0
- package/dist/features/magic-context/session-project-storage.d.ts.map +1 -0
- package/dist/features/magic-context/storage-db.d.ts +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-memory-mutation-log.d.ts +2 -0
- package/dist/features/magic-context/storage-memory-mutation-log.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +16 -0
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-shared.d.ts +3 -2
- package/dist/features/magic-context/storage-meta-shared.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +1 -1
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +3 -2
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/tool-definition-tokens.d.ts +0 -21
- package/dist/features/magic-context/tool-definition-tokens.d.ts.map +1 -1
- package/dist/features/magic-context/types.d.ts +1 -0
- package/dist/features/magic-context/types.d.ts.map +1 -1
- package/dist/features/magic-context/workspaces.d.ts +20 -0
- package/dist/features/magic-context/workspaces.d.ts.map +1 -0
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +5 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +11 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts +18 -0
- package/dist/hooks/magic-context/ctx-reduce-availability.d.ts.map +1 -0
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +23 -5
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/issue-135-wire-fixtures.d.ts +8 -0
- package/dist/hooks/magic-context/issue-135-wire-fixtures.d.ts.map +1 -0
- package/dist/hooks/magic-context/openai-compat-adjacency.d.ts +38 -0
- package/dist/hooks/magic-context/openai-compat-adjacency.d.ts.map +1 -0
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts +1 -1
- package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
- package/dist/hooks/magic-context/reference-retrieval.d.ts.map +1 -1
- package/dist/hooks/magic-context/sentinel.d.ts +33 -28
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +34 -17
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-structural-noise.d.ts +5 -7
- package/dist/hooks/magic-context/strip-structural-noise.d.ts.map +1 -1
- package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +4 -5
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +0 -8
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/index.js +2387 -348
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/shared/announcement.d.ts +1 -1
- package/dist/shared/rpc-types.d.ts +1 -1
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-search/tools.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/shared/announcement.ts +6 -6
- package/src/shared/rpc-types.ts +1 -1
- package/src/tui/index.tsx +5 -3
- package/src/tui/slots/sidebar-content.tsx +24 -5
package/dist/index.js
CHANGED
|
@@ -14887,7 +14887,8 @@ var init_magic_context = __esm(() => {
|
|
|
14887
14887
|
endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
|
|
14888
14888
|
api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
|
|
14889
14889
|
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."),
|
|
14890
|
-
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.")
|
|
14890
|
+
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."),
|
|
14891
|
+
max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
|
|
14891
14892
|
}).superRefine((data, ctx) => {
|
|
14892
14893
|
if (data.provider === "openai-compatible" && !data.endpoint?.trim()) {
|
|
14893
14894
|
ctx.addIssue({
|
|
@@ -14908,7 +14909,8 @@ var init_magic_context = __esm(() => {
|
|
|
14908
14909
|
if (data.provider === "local") {
|
|
14909
14910
|
return {
|
|
14910
14911
|
provider: "local",
|
|
14911
|
-
model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
14912
|
+
model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
14913
|
+
...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
|
|
14912
14914
|
};
|
|
14913
14915
|
}
|
|
14914
14916
|
if (data.provider === "openai-compatible") {
|
|
@@ -14921,7 +14923,8 @@ var init_magic_context = __esm(() => {
|
|
|
14921
14923
|
endpoint: data.endpoint?.trim() ?? "",
|
|
14922
14924
|
...apiKey ? { api_key: apiKey } : {},
|
|
14923
14925
|
...inputType ? { input_type: inputType } : {},
|
|
14924
|
-
...truncate ? { truncate } : {}
|
|
14926
|
+
...truncate ? { truncate } : {},
|
|
14927
|
+
...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
|
|
14925
14928
|
};
|
|
14926
14929
|
}
|
|
14927
14930
|
return { provider: "off" };
|
|
@@ -15844,7 +15847,7 @@ function isSessionMetaRow(row) {
|
|
|
15844
15847
|
if (row === null || typeof row !== "object")
|
|
15845
15848
|
return false;
|
|
15846
15849
|
const r = row;
|
|
15847
|
-
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);
|
|
15850
|
+
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);
|
|
15848
15851
|
}
|
|
15849
15852
|
function getDefaultSessionMeta(sessionId) {
|
|
15850
15853
|
return {
|
|
@@ -15871,6 +15874,7 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
15871
15874
|
cachedM0Bytes: null,
|
|
15872
15875
|
cachedM1Bytes: null,
|
|
15873
15876
|
cachedM0ProjectMemoryEpoch: null,
|
|
15877
|
+
cachedM0WorkspaceFingerprint: null,
|
|
15874
15878
|
cachedM0ProjectUserProfileVersion: null,
|
|
15875
15879
|
cachedM0MaxCompartmentSeq: null,
|
|
15876
15880
|
cachedM0MaxMemoryId: null,
|
|
@@ -15933,6 +15937,7 @@ function toSessionMeta(row) {
|
|
|
15933
15937
|
cachedM0Bytes: toBufferOrNull(row.cached_m0_bytes),
|
|
15934
15938
|
cachedM1Bytes: toBufferOrNull(row.cached_m1_bytes),
|
|
15935
15939
|
cachedM0ProjectMemoryEpoch: numOrNull(row.cached_m0_project_memory_epoch),
|
|
15940
|
+
cachedM0WorkspaceFingerprint: stringOrNull(row.cached_m0_workspace_fingerprint),
|
|
15936
15941
|
cachedM0ProjectUserProfileVersion: numOrNull(row.cached_m0_project_user_profile_version),
|
|
15937
15942
|
cachedM0MaxCompartmentSeq: numOrNull(row.cached_m0_max_compartment_seq),
|
|
15938
15943
|
cachedM0MaxMemoryId: numOrNull(row.cached_m0_max_memory_id),
|
|
@@ -15963,6 +15968,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
15963
15968
|
db.prepare(`UPDATE session_meta SET
|
|
15964
15969
|
cached_m0_bytes = ?,
|
|
15965
15970
|
cached_m0_project_memory_epoch = ?,
|
|
15971
|
+
cached_m0_workspace_fingerprint = ?,
|
|
15966
15972
|
cached_m0_project_user_profile_version = ?,
|
|
15967
15973
|
cached_m0_max_compartment_seq = ?,
|
|
15968
15974
|
cached_m0_max_memory_id = ?,
|
|
@@ -15974,9 +15980,8 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
15974
15980
|
cached_m0_session_facts_version = ?,
|
|
15975
15981
|
cached_m0_upgrade_state = ?,
|
|
15976
15982
|
cached_m0_system_hash = ?,
|
|
15977
|
-
cached_m0_tool_set_hash = ?,
|
|
15978
15983
|
cached_m0_model_key = ?
|
|
15979
|
-
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.
|
|
15984
|
+
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);
|
|
15980
15985
|
}
|
|
15981
15986
|
function clearCachedM0M1(db, sessionId) {
|
|
15982
15987
|
ensureSessionMetaRow(db, sessionId);
|
|
@@ -15985,6 +15990,7 @@ function clearCachedM0M1(db, sessionId) {
|
|
|
15985
15990
|
["cached_m0_bytes", null],
|
|
15986
15991
|
["cached_m1_bytes", null],
|
|
15987
15992
|
["cached_m0_project_memory_epoch", null],
|
|
15993
|
+
["cached_m0_workspace_fingerprint", null],
|
|
15988
15994
|
["cached_m0_project_user_profile_version", null],
|
|
15989
15995
|
["cached_m0_max_compartment_seq", null],
|
|
15990
15996
|
["cached_m0_max_memory_id", null],
|
|
@@ -16040,6 +16046,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16040
16046
|
"cached_m0_bytes",
|
|
16041
16047
|
"cached_m1_bytes",
|
|
16042
16048
|
"cached_m0_project_memory_epoch",
|
|
16049
|
+
"cached_m0_workspace_fingerprint",
|
|
16043
16050
|
"cached_m0_project_user_profile_version",
|
|
16044
16051
|
"cached_m0_max_compartment_seq",
|
|
16045
16052
|
"cached_m0_max_memory_id",
|
|
@@ -16087,6 +16094,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16087
16094
|
cachedM0Bytes: "cached_m0_bytes",
|
|
16088
16095
|
cachedM1Bytes: "cached_m1_bytes",
|
|
16089
16096
|
cachedM0ProjectMemoryEpoch: "cached_m0_project_memory_epoch",
|
|
16097
|
+
cachedM0WorkspaceFingerprint: "cached_m0_workspace_fingerprint",
|
|
16090
16098
|
cachedM0ProjectUserProfileVersion: "cached_m0_project_user_profile_version",
|
|
16091
16099
|
cachedM0MaxCompartmentSeq: "cached_m0_max_compartment_seq",
|
|
16092
16100
|
cachedM0MaxMemoryId: "cached_m0_max_memory_id",
|
|
@@ -16116,6 +16124,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16116
16124
|
"cachedM0Bytes",
|
|
16117
16125
|
"cachedM1Bytes",
|
|
16118
16126
|
"cachedM0ProjectMemoryEpoch",
|
|
16127
|
+
"cachedM0WorkspaceFingerprint",
|
|
16119
16128
|
"cachedM0ProjectUserProfileVersion",
|
|
16120
16129
|
"cachedM0MaxCompartmentSeq",
|
|
16121
16130
|
"cachedM0MaxMemoryId",
|
|
@@ -150320,18 +150329,6 @@ function keyFor(providerID, modelID, agentName) {
|
|
|
150320
150329
|
function fingerprintFor(description, parameters) {
|
|
150321
150330
|
return createHash3("sha256").update(description).update("\x00").update(stableStringify(parameters)).digest("hex");
|
|
150322
150331
|
}
|
|
150323
|
-
function getCurrentToolSetHash(providerID, modelID, agentName) {
|
|
150324
|
-
const key = keyFor(providerID, modelID, agentName);
|
|
150325
|
-
const inner = fingerprints.get(key);
|
|
150326
|
-
if (!inner || inner.size === 0)
|
|
150327
|
-
return "";
|
|
150328
|
-
const parts = [];
|
|
150329
|
-
for (const [toolID, fp] of inner)
|
|
150330
|
-
parts.push(`${toolID}\x00${fp}`);
|
|
150331
|
-
parts.sort();
|
|
150332
|
-
return createHash3("sha256").update(parts.join(`
|
|
150333
|
-
`)).digest("hex");
|
|
150334
|
-
}
|
|
150335
150332
|
function setDatabase(db) {
|
|
150336
150333
|
persistenceDb = db;
|
|
150337
150334
|
cachedInsertStmt = null;
|
|
@@ -150839,6 +150836,35 @@ function initializeDatabase(db) {
|
|
|
150839
150836
|
);
|
|
150840
150837
|
CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
|
|
150841
150838
|
|
|
150839
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
150840
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
150841
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
150842
|
+
session_id TEXT NOT NULL,
|
|
150843
|
+
project_path TEXT NOT NULL,
|
|
150844
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
150845
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
150846
|
+
start_ordinal INTEGER NOT NULL,
|
|
150847
|
+
end_ordinal INTEGER NOT NULL,
|
|
150848
|
+
chunk_hash TEXT NOT NULL,
|
|
150849
|
+
model_id TEXT NOT NULL,
|
|
150850
|
+
dims INTEGER NOT NULL,
|
|
150851
|
+
vector BLOB NOT NULL,
|
|
150852
|
+
created_at INTEGER NOT NULL,
|
|
150853
|
+
UNIQUE(compartment_id, window_index)
|
|
150854
|
+
);
|
|
150855
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session ON compartment_chunk_embeddings(session_id);
|
|
150856
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model ON compartment_chunk_embeddings(project_path, model_id);
|
|
150857
|
+
|
|
150858
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
150859
|
+
session_id TEXT NOT NULL,
|
|
150860
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
150861
|
+
project_path TEXT NOT NULL,
|
|
150862
|
+
updated_at INTEGER NOT NULL,
|
|
150863
|
+
PRIMARY KEY(session_id, harness)
|
|
150864
|
+
);
|
|
150865
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
150866
|
+
ON session_projects(project_path);
|
|
150867
|
+
|
|
150842
150868
|
CREATE TABLE IF NOT EXISTS compartment_events (
|
|
150843
150869
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
150844
150870
|
session_id TEXT NOT NULL,
|
|
@@ -151024,6 +151050,25 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151024
151050
|
rekeyed_at INTEGER NOT NULL
|
|
151025
151051
|
);
|
|
151026
151052
|
|
|
151053
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
151054
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151055
|
+
name TEXT NOT NULL UNIQUE,
|
|
151056
|
+
created_at INTEGER NOT NULL,
|
|
151057
|
+
updated_at INTEGER NOT NULL,
|
|
151058
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
151059
|
+
);
|
|
151060
|
+
|
|
151061
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
151062
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
151063
|
+
project_path TEXT NOT NULL,
|
|
151064
|
+
display_name TEXT NOT NULL,
|
|
151065
|
+
display_path TEXT NOT NULL,
|
|
151066
|
+
added_at INTEGER NOT NULL,
|
|
151067
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
151068
|
+
);
|
|
151069
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
151070
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
151071
|
+
|
|
151027
151072
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
151028
151073
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151029
151074
|
table_name TEXT NOT NULL,
|
|
@@ -151135,6 +151180,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151135
151180
|
deferred_execute_state TEXT,
|
|
151136
151181
|
cached_m0_bytes BLOB,
|
|
151137
151182
|
cached_m0_project_memory_epoch INTEGER,
|
|
151183
|
+
cached_m0_workspace_fingerprint TEXT,
|
|
151138
151184
|
cached_m0_project_user_profile_version INTEGER,
|
|
151139
151185
|
cached_m0_max_compartment_seq INTEGER,
|
|
151140
151186
|
cached_m0_max_memory_id INTEGER,
|
|
@@ -151293,6 +151339,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151293
151339
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
151294
151340
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
151295
151341
|
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
151342
|
+
ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
|
|
151296
151343
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
151297
151344
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
151298
151345
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -151346,6 +151393,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151346
151393
|
ensureColumn(db, "memories", "importance", "INTEGER");
|
|
151347
151394
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
151348
151395
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
151396
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
151349
151397
|
ensureColumn(db, "session_meta", "cached_m0_project_user_profile_version", "INTEGER");
|
|
151350
151398
|
ensureColumn(db, "session_meta", "cached_m0_max_compartment_seq", "INTEGER");
|
|
151351
151399
|
ensureColumn(db, "session_meta", "cached_m0_max_memory_id", "INTEGER");
|
|
@@ -151377,6 +151425,15 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151377
151425
|
project_user_profile_version INTEGER NOT NULL DEFAULT 0,
|
|
151378
151426
|
updated_at INTEGER NOT NULL DEFAULT 0
|
|
151379
151427
|
);
|
|
151428
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
151429
|
+
session_id TEXT NOT NULL,
|
|
151430
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
151431
|
+
project_path TEXT NOT NULL,
|
|
151432
|
+
updated_at INTEGER NOT NULL,
|
|
151433
|
+
PRIMARY KEY(session_id, harness)
|
|
151434
|
+
);
|
|
151435
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
151436
|
+
ON session_projects(project_path);
|
|
151380
151437
|
CREATE TABLE IF NOT EXISTS m0_mutation_log (
|
|
151381
151438
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151382
151439
|
session_id TEXT NOT NULL,
|
|
@@ -151404,6 +151461,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151404
151461
|
new_project_path TEXT NOT NULL,
|
|
151405
151462
|
rekeyed_at INTEGER NOT NULL
|
|
151406
151463
|
);
|
|
151464
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
151465
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151466
|
+
name TEXT NOT NULL UNIQUE,
|
|
151467
|
+
created_at INTEGER NOT NULL,
|
|
151468
|
+
updated_at INTEGER NOT NULL,
|
|
151469
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
151470
|
+
);
|
|
151471
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
151472
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
151473
|
+
project_path TEXT NOT NULL,
|
|
151474
|
+
display_name TEXT NOT NULL,
|
|
151475
|
+
display_path TEXT NOT NULL,
|
|
151476
|
+
added_at INTEGER NOT NULL,
|
|
151477
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
151478
|
+
);
|
|
151479
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
151480
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
151407
151481
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
151408
151482
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151409
151483
|
table_name TEXT NOT NULL,
|
|
@@ -151425,6 +151499,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151425
151499
|
ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151426
151500
|
ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151427
151501
|
ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151502
|
+
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
151428
151503
|
}
|
|
151429
151504
|
function healAllNullColumns(db) {
|
|
151430
151505
|
healNullTextColumns(db);
|
|
@@ -151462,6 +151537,7 @@ function healNullTextColumns(db) {
|
|
|
151462
151537
|
["system_prompt_hash", ""],
|
|
151463
151538
|
["stripped_placeholder_ids", ""],
|
|
151464
151539
|
["stale_reduce_stripped_ids", ""],
|
|
151540
|
+
["processed_image_stripped_ids", ""],
|
|
151465
151541
|
["memory_block_cache", ""],
|
|
151466
151542
|
["memory_block_ids", ""],
|
|
151467
151543
|
["compaction_marker_state", ""],
|
|
@@ -151506,7 +151582,7 @@ function healNullIntegerColumns(db) {
|
|
|
151506
151582
|
}
|
|
151507
151583
|
}
|
|
151508
151584
|
function ensureColumn(db, table, column, definition) {
|
|
151509
|
-
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_'(),[\]\s]+$/i.test(definition)) {
|
|
151585
|
+
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_"'(),[\]\s]+$/i.test(definition)) {
|
|
151510
151586
|
throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
|
|
151511
151587
|
}
|
|
151512
151588
|
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
@@ -151592,7 +151668,7 @@ function getDatabasePersistenceError(db) {
|
|
|
151592
151668
|
return null;
|
|
151593
151669
|
return persistenceErrorByDatabase.get(db) ?? null;
|
|
151594
151670
|
}
|
|
151595
|
-
var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION =
|
|
151671
|
+
var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 36, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
|
|
151596
151672
|
var init_storage_db = __esm(async () => {
|
|
151597
151673
|
init_data_path();
|
|
151598
151674
|
init_logger();
|
|
@@ -151612,10 +151688,302 @@ var init_storage_db = __esm(async () => {
|
|
|
151612
151688
|
};
|
|
151613
151689
|
});
|
|
151614
151690
|
|
|
151691
|
+
// src/features/magic-context/memory/constants.ts
|
|
151692
|
+
var V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
151693
|
+
var init_constants = __esm(() => {
|
|
151694
|
+
V2_MEMORY_CATEGORIES = [
|
|
151695
|
+
"PROJECT_RULES",
|
|
151696
|
+
"ARCHITECTURE",
|
|
151697
|
+
"CONSTRAINTS",
|
|
151698
|
+
"CONFIG_VALUES",
|
|
151699
|
+
"NAMING"
|
|
151700
|
+
];
|
|
151701
|
+
PROMOTABLE_CATEGORIES = [
|
|
151702
|
+
"PROJECT_RULES",
|
|
151703
|
+
"ARCHITECTURE",
|
|
151704
|
+
"CONSTRAINTS",
|
|
151705
|
+
"CONFIG_VALUES",
|
|
151706
|
+
"NAMING",
|
|
151707
|
+
"ARCHITECTURE_DECISIONS",
|
|
151708
|
+
"CONFIG_DEFAULTS",
|
|
151709
|
+
"USER_PREFERENCES",
|
|
151710
|
+
"USER_DIRECTIVES",
|
|
151711
|
+
"ENVIRONMENT",
|
|
151712
|
+
"WORKFLOW_RULES",
|
|
151713
|
+
"KNOWN_ISSUES"
|
|
151714
|
+
];
|
|
151715
|
+
CATEGORY_PRIORITY = [
|
|
151716
|
+
"PROJECT_RULES",
|
|
151717
|
+
"ARCHITECTURE",
|
|
151718
|
+
"CONSTRAINTS",
|
|
151719
|
+
"CONFIG_VALUES",
|
|
151720
|
+
"NAMING",
|
|
151721
|
+
"USER_DIRECTIVES",
|
|
151722
|
+
"USER_PREFERENCES",
|
|
151723
|
+
"CONFIG_DEFAULTS",
|
|
151724
|
+
"ARCHITECTURE_DECISIONS",
|
|
151725
|
+
"ENVIRONMENT",
|
|
151726
|
+
"WORKFLOW_RULES",
|
|
151727
|
+
"KNOWN_ISSUES"
|
|
151728
|
+
];
|
|
151729
|
+
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
151730
|
+
acc[category] = index;
|
|
151731
|
+
return acc;
|
|
151732
|
+
}, {});
|
|
151733
|
+
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
151734
|
+
CATEGORY_DEFAULT_TTL = {
|
|
151735
|
+
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
151736
|
+
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
151737
|
+
};
|
|
151738
|
+
});
|
|
151739
|
+
|
|
151740
|
+
// src/features/magic-context/project-identity.ts
|
|
151741
|
+
var init_project_identity2 = __esm(() => {
|
|
151742
|
+
init_project_identity();
|
|
151743
|
+
});
|
|
151744
|
+
|
|
151745
|
+
// src/features/magic-context/workspaces.ts
|
|
151746
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
151747
|
+
function tableExists(db, tableName) {
|
|
151748
|
+
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ? LIMIT 1").get(tableName);
|
|
151749
|
+
return Boolean(row);
|
|
151750
|
+
}
|
|
151751
|
+
function columnExists(db, tableName, columnName) {
|
|
151752
|
+
const rows = db.prepare(`PRAGMA table_info(${tableName})`).all();
|
|
151753
|
+
return rows.some((row) => row.name === columnName);
|
|
151754
|
+
}
|
|
151755
|
+
function uniqueSorted(values) {
|
|
151756
|
+
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
151757
|
+
}
|
|
151758
|
+
function placeholders(values) {
|
|
151759
|
+
return values.map(() => "?").join(", ");
|
|
151760
|
+
}
|
|
151761
|
+
function normalizeShareCategories(raw) {
|
|
151762
|
+
if (raw === null || raw === undefined)
|
|
151763
|
+
return null;
|
|
151764
|
+
if (typeof raw !== "string")
|
|
151765
|
+
return null;
|
|
151766
|
+
let parsed;
|
|
151767
|
+
try {
|
|
151768
|
+
parsed = JSON.parse(raw);
|
|
151769
|
+
} catch {
|
|
151770
|
+
return null;
|
|
151771
|
+
}
|
|
151772
|
+
if (!Array.isArray(parsed))
|
|
151773
|
+
return null;
|
|
151774
|
+
const categories = [];
|
|
151775
|
+
for (const value of parsed) {
|
|
151776
|
+
if (typeof value !== "string" || !VALID_SHARE_CATEGORIES.has(value)) {
|
|
151777
|
+
return null;
|
|
151778
|
+
}
|
|
151779
|
+
if (!categories.includes(value))
|
|
151780
|
+
categories.push(value);
|
|
151781
|
+
}
|
|
151782
|
+
return categories.sort((left, right) => left.localeCompare(right));
|
|
151783
|
+
}
|
|
151784
|
+
function selectWorkspaceShareCategories(db, identities) {
|
|
151785
|
+
const candidates = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
151786
|
+
if (candidates.length === 0 || !tableExists(db, "workspace_members") || !tableExists(db, "workspaces") || !columnExists(db, "workspaces", "share_categories")) {
|
|
151787
|
+
return null;
|
|
151788
|
+
}
|
|
151789
|
+
const row = db.prepare(`SELECT workspace.share_categories AS shareCategories
|
|
151790
|
+
FROM workspace_members AS member
|
|
151791
|
+
JOIN workspaces AS workspace ON workspace.id = member.workspace_id
|
|
151792
|
+
WHERE member.project_path IN (${placeholders(candidates)})
|
|
151793
|
+
ORDER BY workspace.id ASC
|
|
151794
|
+
LIMIT 1`).get(...candidates);
|
|
151795
|
+
return normalizeShareCategories(row?.shareCategories ?? null);
|
|
151796
|
+
}
|
|
151797
|
+
function resolveWorkspaceShareCategories(db, projectIdentity) {
|
|
151798
|
+
return selectWorkspaceShareCategories(db, [projectIdentity]);
|
|
151799
|
+
}
|
|
151800
|
+
function resolveWorkspaceIdentitySet(db, projectIdentity) {
|
|
151801
|
+
if (!tableExists(db, "workspace_members")) {
|
|
151802
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
151803
|
+
}
|
|
151804
|
+
const rows = db.prepare(`SELECT member.project_path AS identity, member.display_name AS displayName
|
|
151805
|
+
FROM workspace_members AS anchor
|
|
151806
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
151807
|
+
WHERE anchor.project_path = ?
|
|
151808
|
+
ORDER BY member.display_name ASC, member.project_path ASC`).all(projectIdentity);
|
|
151809
|
+
if (rows.length === 0) {
|
|
151810
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
151811
|
+
}
|
|
151812
|
+
const namesByIdentity = new Map;
|
|
151813
|
+
const identities = [];
|
|
151814
|
+
for (const row of rows) {
|
|
151815
|
+
if (typeof row.identity !== "string" || row.identity.length === 0)
|
|
151816
|
+
continue;
|
|
151817
|
+
if (identities.includes(row.identity))
|
|
151818
|
+
continue;
|
|
151819
|
+
identities.push(row.identity);
|
|
151820
|
+
if (typeof row.displayName === "string" && row.displayName.length > 0) {
|
|
151821
|
+
namesByIdentity.set(row.identity, row.displayName);
|
|
151822
|
+
}
|
|
151823
|
+
}
|
|
151824
|
+
return identities.length > 0 ? { identities, namesByIdentity } : { identities: [projectIdentity], namesByIdentity: new Map };
|
|
151825
|
+
}
|
|
151826
|
+
function expandWorkspaceIdentitySetWithAliases(db, identities) {
|
|
151827
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
151828
|
+
const expanded = new Set(canonical);
|
|
151829
|
+
const canonicalIdentityByStoredPath = new Map;
|
|
151830
|
+
for (const identity of canonical) {
|
|
151831
|
+
canonicalIdentityByStoredPath.set(identity, identity);
|
|
151832
|
+
}
|
|
151833
|
+
if (canonical.length === 0 || !tableExists(db, "v22_identity_rekey_map")) {
|
|
151834
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
151835
|
+
}
|
|
151836
|
+
const rows = db.prepare(`SELECT old_project_path AS oldProjectPath, new_project_path AS newProjectPath
|
|
151837
|
+
FROM v22_identity_rekey_map
|
|
151838
|
+
WHERE new_project_path IN (${placeholders(canonical)})
|
|
151839
|
+
ORDER BY old_project_path ASC`).all(...canonical);
|
|
151840
|
+
for (const row of rows) {
|
|
151841
|
+
if (typeof row.oldProjectPath !== "string" || typeof row.newProjectPath !== "string") {
|
|
151842
|
+
continue;
|
|
151843
|
+
}
|
|
151844
|
+
if (!canonicalIdentityByStoredPath.has(row.newProjectPath))
|
|
151845
|
+
continue;
|
|
151846
|
+
expanded.add(row.oldProjectPath);
|
|
151847
|
+
canonicalIdentityByStoredPath.set(row.oldProjectPath, row.newProjectPath);
|
|
151848
|
+
}
|
|
151849
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
151850
|
+
}
|
|
151851
|
+
function resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) {
|
|
151852
|
+
const direct = canonicalIdentityByStoredPath.get(storedProjectPath);
|
|
151853
|
+
if (direct)
|
|
151854
|
+
return direct;
|
|
151855
|
+
const normalized = normalizeStoredProjectPath(storedProjectPath);
|
|
151856
|
+
const normalizedDirect = canonicalIdentityByStoredPath.get(normalized);
|
|
151857
|
+
if (normalizedDirect)
|
|
151858
|
+
return normalizedDirect;
|
|
151859
|
+
if (memberIdentities.includes(normalized))
|
|
151860
|
+
return normalized;
|
|
151861
|
+
for (const identity of memberIdentities) {
|
|
151862
|
+
if (storedPathBelongsToIdentity(storedProjectPath, identity)) {
|
|
151863
|
+
return identity;
|
|
151864
|
+
}
|
|
151865
|
+
}
|
|
151866
|
+
return null;
|
|
151867
|
+
}
|
|
151868
|
+
function storedPathBelongsToWorkspace(storedProjectPath, memberIdentities, expandedIdentities, canonicalIdentityByStoredPath) {
|
|
151869
|
+
if (expandedIdentities.includes(storedProjectPath))
|
|
151870
|
+
return true;
|
|
151871
|
+
return resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) !== null;
|
|
151872
|
+
}
|
|
151873
|
+
function sourceNameForMemory(storedProjectPath, ownIdentity, memberIdentities, namesByIdentity, canonicalIdentityByStoredPath) {
|
|
151874
|
+
const canonicalIdentity = resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath);
|
|
151875
|
+
if (!canonicalIdentity || canonicalIdentity === ownIdentity)
|
|
151876
|
+
return;
|
|
151877
|
+
return namesByIdentity.get(canonicalIdentity);
|
|
151878
|
+
}
|
|
151879
|
+
function getEpochMap(db, identities) {
|
|
151880
|
+
if (identities.length === 0)
|
|
151881
|
+
return new Map;
|
|
151882
|
+
const rows = db.prepare(`SELECT project_path AS projectPath, project_memory_epoch AS epoch
|
|
151883
|
+
FROM project_state
|
|
151884
|
+
WHERE project_path IN (${placeholders(identities)})`).all(...identities);
|
|
151885
|
+
const epochs = new Map;
|
|
151886
|
+
for (const row of rows) {
|
|
151887
|
+
if (typeof row.projectPath !== "string" || typeof row.epoch !== "number")
|
|
151888
|
+
continue;
|
|
151889
|
+
epochs.set(row.projectPath, row.epoch);
|
|
151890
|
+
}
|
|
151891
|
+
return epochs;
|
|
151892
|
+
}
|
|
151893
|
+
function computeWorkspaceEpochFingerprint(db, identities) {
|
|
151894
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
151895
|
+
const epochs = getEpochMap(db, canonical);
|
|
151896
|
+
const shareCategories = selectWorkspaceShareCategories(db, canonical);
|
|
151897
|
+
const hash2 = createHash4("sha256");
|
|
151898
|
+
hash2.update("share_categories", "utf8");
|
|
151899
|
+
hash2.update("\x00");
|
|
151900
|
+
hash2.update(shareCategories === null ? "ALL" : JSON.stringify(shareCategories), "utf8");
|
|
151901
|
+
hash2.update(`
|
|
151902
|
+
`);
|
|
151903
|
+
for (const identity of canonical) {
|
|
151904
|
+
hash2.update(identity, "utf8");
|
|
151905
|
+
hash2.update("\x00");
|
|
151906
|
+
hash2.update(String(epochs.get(identity) ?? 0), "utf8");
|
|
151907
|
+
hash2.update(`
|
|
151908
|
+
`);
|
|
151909
|
+
}
|
|
151910
|
+
return hash2.digest("hex");
|
|
151911
|
+
}
|
|
151912
|
+
function isInTransaction(db) {
|
|
151913
|
+
const candidate = db;
|
|
151914
|
+
return candidate.inTransaction === true || candidate.isTransaction === true;
|
|
151915
|
+
}
|
|
151916
|
+
function workspaceMembersForIdentity(db, identity) {
|
|
151917
|
+
if (!tableExists(db, "workspace_members"))
|
|
151918
|
+
return [identity];
|
|
151919
|
+
const rows = db.prepare(`SELECT member.project_path AS identity
|
|
151920
|
+
FROM workspace_members AS anchor
|
|
151921
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
151922
|
+
WHERE anchor.project_path = ?
|
|
151923
|
+
ORDER BY member.project_path ASC`).all(identity);
|
|
151924
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((value) => value.length > 0);
|
|
151925
|
+
return identities.length > 0 ? uniqueSorted(identities) : [identity];
|
|
151926
|
+
}
|
|
151927
|
+
function bumpEpochRows(db, identities, now) {
|
|
151928
|
+
const stmt = db.prepare(`INSERT INTO project_state
|
|
151929
|
+
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
151930
|
+
VALUES (?, 1, 0, ?)
|
|
151931
|
+
ON CONFLICT(project_path) DO UPDATE SET
|
|
151932
|
+
project_memory_epoch = project_memory_epoch + 1,
|
|
151933
|
+
updated_at = excluded.updated_at`);
|
|
151934
|
+
for (const identity of uniqueSorted(identities)) {
|
|
151935
|
+
stmt.run(identity, now);
|
|
151936
|
+
}
|
|
151937
|
+
}
|
|
151938
|
+
function bumpEpochsForWorkspaceMembers(db, identity, now = Date.now()) {
|
|
151939
|
+
const run = () => bumpEpochRows(db, workspaceMembersForIdentity(db, identity), now);
|
|
151940
|
+
if (isInTransaction(db)) {
|
|
151941
|
+
run();
|
|
151942
|
+
return;
|
|
151943
|
+
}
|
|
151944
|
+
db.exec("BEGIN IMMEDIATE");
|
|
151945
|
+
try {
|
|
151946
|
+
run();
|
|
151947
|
+
db.exec("COMMIT");
|
|
151948
|
+
} catch (error51) {
|
|
151949
|
+
try {
|
|
151950
|
+
db.exec("ROLLBACK");
|
|
151951
|
+
} catch {}
|
|
151952
|
+
throw error51;
|
|
151953
|
+
}
|
|
151954
|
+
}
|
|
151955
|
+
function bumpEpochsForWorkspaceMemberSet(db, identities, now = Date.now()) {
|
|
151956
|
+
const run = () => bumpEpochRows(db, identities, now);
|
|
151957
|
+
if (isInTransaction(db)) {
|
|
151958
|
+
run();
|
|
151959
|
+
return;
|
|
151960
|
+
}
|
|
151961
|
+
db.exec("BEGIN IMMEDIATE");
|
|
151962
|
+
try {
|
|
151963
|
+
run();
|
|
151964
|
+
db.exec("COMMIT");
|
|
151965
|
+
} catch (error51) {
|
|
151966
|
+
try {
|
|
151967
|
+
db.exec("ROLLBACK");
|
|
151968
|
+
} catch {}
|
|
151969
|
+
throw error51;
|
|
151970
|
+
}
|
|
151971
|
+
}
|
|
151972
|
+
var VALID_SHARE_CATEGORIES;
|
|
151973
|
+
var init_workspaces = __esm(() => {
|
|
151974
|
+
init_constants();
|
|
151975
|
+
init_project_identity2();
|
|
151976
|
+
VALID_SHARE_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
151977
|
+
});
|
|
151978
|
+
|
|
151615
151979
|
// src/features/magic-context/migrations.ts
|
|
151616
|
-
function
|
|
151980
|
+
function tableExists2(db, name2) {
|
|
151617
151981
|
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name2));
|
|
151618
151982
|
}
|
|
151983
|
+
function columnExists2(db, table, column) {
|
|
151984
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
151985
|
+
return rows.some((row) => row.name === column);
|
|
151986
|
+
}
|
|
151619
151987
|
function ensureMigrationsTable(db) {
|
|
151620
151988
|
db.exec(`
|
|
151621
151989
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
@@ -151684,6 +152052,7 @@ function runMigrations(db) {
|
|
|
151684
152052
|
var MIGRATIONS, LATEST_MIGRATION_VERSION;
|
|
151685
152053
|
var init_migrations = __esm(async () => {
|
|
151686
152054
|
init_logger();
|
|
152055
|
+
init_workspaces();
|
|
151687
152056
|
await init_storage_db();
|
|
151688
152057
|
MIGRATIONS = [
|
|
151689
152058
|
{
|
|
@@ -152143,9 +152512,9 @@ var init_migrations = __esm(async () => {
|
|
|
152143
152512
|
version: 22,
|
|
152144
152513
|
description: "v2.0 cache architecture schema foundation",
|
|
152145
152514
|
up: (db) => {
|
|
152146
|
-
const hasSessionMetaTable =
|
|
152147
|
-
const hasCompartmentsTable =
|
|
152148
|
-
const hasMemoriesTable =
|
|
152515
|
+
const hasSessionMetaTable = tableExists2(db, "session_meta");
|
|
152516
|
+
const hasCompartmentsTable = tableExists2(db, "compartments");
|
|
152517
|
+
const hasMemoriesTable = tableExists2(db, "memories");
|
|
152149
152518
|
if (hasSessionMetaTable) {
|
|
152150
152519
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
152151
152520
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
@@ -152170,7 +152539,7 @@ var init_migrations = __esm(async () => {
|
|
|
152170
152539
|
ensureColumn(db, "compartments", "p1_embedding_model_id", "TEXT");
|
|
152171
152540
|
ensureColumn(db, "compartments", "legacy", "INTEGER NOT NULL DEFAULT 0");
|
|
152172
152541
|
}
|
|
152173
|
-
const hasRecompCompartmentsTable =
|
|
152542
|
+
const hasRecompCompartmentsTable = tableExists2(db, "recomp_compartments");
|
|
152174
152543
|
if (hasRecompCompartmentsTable) {
|
|
152175
152544
|
ensureColumn(db, "recomp_compartments", "p1", "TEXT");
|
|
152176
152545
|
ensureColumn(db, "recomp_compartments", "p2", "TEXT");
|
|
@@ -152481,13 +152850,163 @@ var init_migrations = __esm(async () => {
|
|
|
152481
152850
|
db.prepare("UPDATE session_meta SET force_emergency_bypass_used = 0 WHERE force_emergency_bypass_used IS NULL").run();
|
|
152482
152851
|
db.prepare("UPDATE session_meta SET last_usage_context_limit = 0 WHERE last_usage_context_limit IS NULL").run();
|
|
152483
152852
|
}
|
|
152853
|
+
},
|
|
152854
|
+
{
|
|
152855
|
+
version: 33,
|
|
152856
|
+
description: "Compartment chunk embeddings for semantic message-history search",
|
|
152857
|
+
up: (db) => {
|
|
152858
|
+
db.exec(`
|
|
152859
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
152860
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152861
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
152862
|
+
session_id TEXT NOT NULL,
|
|
152863
|
+
project_path TEXT NOT NULL,
|
|
152864
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
152865
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
152866
|
+
start_ordinal INTEGER NOT NULL,
|
|
152867
|
+
end_ordinal INTEGER NOT NULL,
|
|
152868
|
+
chunk_hash TEXT NOT NULL,
|
|
152869
|
+
model_id TEXT NOT NULL,
|
|
152870
|
+
dims INTEGER NOT NULL,
|
|
152871
|
+
vector BLOB NOT NULL,
|
|
152872
|
+
created_at INTEGER NOT NULL,
|
|
152873
|
+
UNIQUE(compartment_id, window_index)
|
|
152874
|
+
);
|
|
152875
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session
|
|
152876
|
+
ON compartment_chunk_embeddings(session_id);
|
|
152877
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model
|
|
152878
|
+
ON compartment_chunk_embeddings(project_path, model_id);
|
|
152879
|
+
`);
|
|
152880
|
+
}
|
|
152881
|
+
},
|
|
152882
|
+
{
|
|
152883
|
+
version: 34,
|
|
152884
|
+
description: "workspace tables and m[0] workspace fingerprint cache reset",
|
|
152885
|
+
up: (db) => {
|
|
152886
|
+
db.exec(`
|
|
152887
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
152888
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152889
|
+
name TEXT NOT NULL UNIQUE,
|
|
152890
|
+
created_at INTEGER NOT NULL,
|
|
152891
|
+
updated_at INTEGER NOT NULL
|
|
152892
|
+
);
|
|
152893
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
152894
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
152895
|
+
project_path TEXT NOT NULL,
|
|
152896
|
+
display_name TEXT NOT NULL,
|
|
152897
|
+
display_path TEXT NOT NULL,
|
|
152898
|
+
added_at INTEGER NOT NULL,
|
|
152899
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
152900
|
+
);
|
|
152901
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique
|
|
152902
|
+
ON workspace_members(project_path);
|
|
152903
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name
|
|
152904
|
+
ON workspace_members(workspace_id, display_name);
|
|
152905
|
+
`);
|
|
152906
|
+
const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
|
|
152907
|
+
if (!hasSessionMeta)
|
|
152908
|
+
return;
|
|
152909
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
152910
|
+
const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
|
|
152911
|
+
const clears = [
|
|
152912
|
+
["cached_m0_bytes", null],
|
|
152913
|
+
["cached_m1_bytes", null],
|
|
152914
|
+
["cached_m0_project_memory_epoch", null],
|
|
152915
|
+
["cached_m0_workspace_fingerprint", null],
|
|
152916
|
+
["cached_m0_project_user_profile_version", null],
|
|
152917
|
+
["cached_m0_max_compartment_seq", null],
|
|
152918
|
+
["cached_m0_max_memory_id", null],
|
|
152919
|
+
["cached_m0_max_mutation_id", null],
|
|
152920
|
+
["cached_m0_max_memory_mutation_id", null],
|
|
152921
|
+
["cached_m0_project_docs_hash", null],
|
|
152922
|
+
["cached_m0_materialized_at", null],
|
|
152923
|
+
["cached_m0_session_facts_version", null],
|
|
152924
|
+
["cached_m0_upgrade_state", null],
|
|
152925
|
+
["cached_m0_system_hash", null],
|
|
152926
|
+
["cached_m0_tool_set_hash", null],
|
|
152927
|
+
["cached_m0_model_key", null],
|
|
152928
|
+
["cached_m0_last_baseline_end_message_id", null],
|
|
152929
|
+
["memory_block_cache", ""],
|
|
152930
|
+
["memory_block_ids", ""],
|
|
152931
|
+
["memory_block_count", 0]
|
|
152932
|
+
];
|
|
152933
|
+
const setClauses = [];
|
|
152934
|
+
const values = [];
|
|
152935
|
+
for (const [column, value] of clears) {
|
|
152936
|
+
if (!columns.has(column))
|
|
152937
|
+
continue;
|
|
152938
|
+
setClauses.push(`${column} = ?`);
|
|
152939
|
+
values.push(value);
|
|
152940
|
+
}
|
|
152941
|
+
if (setClauses.length > 0) {
|
|
152942
|
+
db.prepare(`UPDATE session_meta SET ${setClauses.join(", ")}`).run(...values);
|
|
152943
|
+
}
|
|
152944
|
+
}
|
|
152945
|
+
},
|
|
152946
|
+
{
|
|
152947
|
+
version: 35,
|
|
152948
|
+
description: "workspace per-category share defaults and epoch refresh",
|
|
152949
|
+
up: (db) => {
|
|
152950
|
+
db.exec(`
|
|
152951
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
152952
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152953
|
+
name TEXT NOT NULL UNIQUE,
|
|
152954
|
+
created_at INTEGER NOT NULL,
|
|
152955
|
+
updated_at INTEGER NOT NULL,
|
|
152956
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
152957
|
+
);
|
|
152958
|
+
`);
|
|
152959
|
+
if (!columnExists2(db, "workspaces", "share_categories")) {
|
|
152960
|
+
db.exec(`ALTER TABLE workspaces ADD COLUMN share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
152961
|
+
}
|
|
152962
|
+
db.prepare(`UPDATE workspaces
|
|
152963
|
+
SET share_categories = '["CONSTRAINTS"]'
|
|
152964
|
+
WHERE share_categories IS NULL OR share_categories = ''`).run();
|
|
152965
|
+
if (!tableExists2(db, "workspace_members"))
|
|
152966
|
+
return;
|
|
152967
|
+
const rows = db.prepare(`SELECT DISTINCT project_path AS identity
|
|
152968
|
+
FROM workspace_members
|
|
152969
|
+
WHERE project_path IS NOT NULL AND project_path <> ''
|
|
152970
|
+
ORDER BY project_path ASC`).all();
|
|
152971
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((identity) => identity.length > 0);
|
|
152972
|
+
if (identities.length > 0) {
|
|
152973
|
+
bumpEpochsForWorkspaceMemberSet(db, identities, Date.now());
|
|
152974
|
+
}
|
|
152975
|
+
}
|
|
152976
|
+
},
|
|
152977
|
+
{
|
|
152978
|
+
version: 36,
|
|
152979
|
+
description: "session project ownership map for compartment chunk backfill scoping",
|
|
152980
|
+
up: (db) => {
|
|
152981
|
+
db.exec(`
|
|
152982
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
152983
|
+
session_id TEXT NOT NULL,
|
|
152984
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
152985
|
+
project_path TEXT NOT NULL,
|
|
152986
|
+
updated_at INTEGER NOT NULL,
|
|
152987
|
+
PRIMARY KEY(session_id, harness)
|
|
152988
|
+
);
|
|
152989
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
152990
|
+
ON session_projects(project_path);
|
|
152991
|
+
`);
|
|
152992
|
+
const hasChunkTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='compartment_chunk_embeddings'").get();
|
|
152993
|
+
if (hasChunkTable) {
|
|
152994
|
+
db.exec(`
|
|
152995
|
+
INSERT OR IGNORE INTO session_projects (session_id, harness, project_path, updated_at)
|
|
152996
|
+
SELECT session_id, harness, MIN(project_path), 0
|
|
152997
|
+
FROM compartment_chunk_embeddings
|
|
152998
|
+
GROUP BY session_id, harness
|
|
152999
|
+
HAVING COUNT(DISTINCT project_path) = 1;
|
|
153000
|
+
`);
|
|
153001
|
+
}
|
|
153002
|
+
}
|
|
152484
153003
|
}
|
|
152485
153004
|
];
|
|
152486
153005
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
152487
153006
|
});
|
|
152488
153007
|
|
|
152489
153008
|
// src/features/magic-context/project-docs-hash.ts
|
|
152490
|
-
import { createHash as
|
|
153009
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
152491
153010
|
import { lstatSync, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
|
|
152492
153011
|
import path4 from "node:path";
|
|
152493
153012
|
function canonicalizeDocContent(raw) {
|
|
@@ -152577,7 +153096,7 @@ function hashCanonicalPieces(hashPieces) {
|
|
|
152577
153096
|
if (hashPieces.length === 0) {
|
|
152578
153097
|
return "";
|
|
152579
153098
|
}
|
|
152580
|
-
return
|
|
153099
|
+
return createHash5("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
|
|
152581
153100
|
}
|
|
152582
153101
|
function readProjectDocsCanonical(projectDirectory) {
|
|
152583
153102
|
const canonicalDirectory = path4.resolve(projectDirectory);
|
|
@@ -152615,11 +153134,6 @@ var init_project_docs_hash = __esm(() => {
|
|
|
152615
153134
|
MAX_PROJECT_DOC_BYTES = 256 * 1024;
|
|
152616
153135
|
docsCache = new Map;
|
|
152617
153136
|
});
|
|
152618
|
-
|
|
152619
|
-
// src/features/magic-context/project-identity.ts
|
|
152620
|
-
var init_project_identity2 = __esm(() => {
|
|
152621
|
-
init_project_identity();
|
|
152622
|
-
});
|
|
152623
153137
|
// src/features/magic-context/storage-m0-mutation-log.ts
|
|
152624
153138
|
function assertMutationType(mutationType) {
|
|
152625
153139
|
if (!M0_MUTATION_TYPES.has(mutationType)) {
|
|
@@ -152704,18 +153218,13 @@ function getMemoryMutation(db, id) {
|
|
|
152704
153218
|
WHERE id = ?`).get(id);
|
|
152705
153219
|
return row ? toMemoryMutation(row) : null;
|
|
152706
153220
|
}
|
|
152707
|
-
function
|
|
152708
|
-
|
|
152709
|
-
|
|
152710
|
-
|
|
152711
|
-
|
|
152712
|
-
|
|
152713
|
-
|
|
152714
|
-
FROM memory_mutation_log
|
|
152715
|
-
WHERE project_path = ?
|
|
152716
|
-
AND id > ?
|
|
152717
|
-
AND target_memory_id IN (${placeholders})
|
|
152718
|
-
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
153221
|
+
function uniqueProjectPaths(projectPaths) {
|
|
153222
|
+
return [...new Set(projectPaths.filter((path5) => path5.length > 0))];
|
|
153223
|
+
}
|
|
153224
|
+
function placeholders2(values) {
|
|
153225
|
+
return values.map(() => "?").join(", ");
|
|
153226
|
+
}
|
|
153227
|
+
function coalesceMutations(rows) {
|
|
152719
153228
|
const chosenByTarget = new Map;
|
|
152720
153229
|
for (const dbRow of rows) {
|
|
152721
153230
|
const candidate = toMemoryMutation(dbRow);
|
|
@@ -152736,10 +153245,54 @@ function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds
|
|
|
152736
153245
|
}
|
|
152737
153246
|
return [...chosenByTarget.values()].sort((left, right) => left.id - right.id);
|
|
152738
153247
|
}
|
|
153248
|
+
function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds) {
|
|
153249
|
+
if (renderedMemoryIds.length === 0)
|
|
153250
|
+
return [];
|
|
153251
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
153252
|
+
const placeholders3 = uniqueIds.map(() => "?").join(", ");
|
|
153253
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
153254
|
+
superseded_by_id, category, new_content, queued_at
|
|
153255
|
+
FROM memory_mutation_log
|
|
153256
|
+
WHERE project_path = ?
|
|
153257
|
+
AND id > ?
|
|
153258
|
+
AND target_memory_id IN (${placeholders3})
|
|
153259
|
+
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
153260
|
+
return coalesceMutations(rows);
|
|
153261
|
+
}
|
|
153262
|
+
function getMemoryMutationsForRenderByProjects(db, projectPaths, afterId, renderedMemoryIds) {
|
|
153263
|
+
if (renderedMemoryIds.length === 0)
|
|
153264
|
+
return [];
|
|
153265
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
153266
|
+
if (identities.length === 0)
|
|
153267
|
+
return [];
|
|
153268
|
+
if (identities.length === 1) {
|
|
153269
|
+
return getMemoryMutationsForRender(db, identities[0], afterId, renderedMemoryIds);
|
|
153270
|
+
}
|
|
153271
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
153272
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
153273
|
+
superseded_by_id, category, new_content, queued_at
|
|
153274
|
+
FROM memory_mutation_log
|
|
153275
|
+
WHERE project_path IN (${placeholders2(identities)})
|
|
153276
|
+
AND id > ?
|
|
153277
|
+
AND target_memory_id IN (${placeholders2(uniqueIds)})
|
|
153278
|
+
ORDER BY id ASC`).all(...identities, afterId ?? 0, ...uniqueIds);
|
|
153279
|
+
return coalesceMutations(rows);
|
|
153280
|
+
}
|
|
152739
153281
|
function getMaxMemoryMutationId(db, projectPath) {
|
|
152740
153282
|
const row = db.prepare("SELECT MAX(id) AS max_id FROM memory_mutation_log WHERE project_path = ?").get(projectPath);
|
|
152741
153283
|
return row?.max_id ?? null;
|
|
152742
153284
|
}
|
|
153285
|
+
function getMaxMemoryMutationIdForProjects(db, projectPaths) {
|
|
153286
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
153287
|
+
if (identities.length === 0)
|
|
153288
|
+
return null;
|
|
153289
|
+
if (identities.length === 1)
|
|
153290
|
+
return getMaxMemoryMutationId(db, identities[0]);
|
|
153291
|
+
const row = db.prepare(`SELECT MAX(id) AS max_id
|
|
153292
|
+
FROM memory_mutation_log
|
|
153293
|
+
WHERE project_path IN (${placeholders2(identities)})`).get(...identities);
|
|
153294
|
+
return row?.max_id ?? null;
|
|
153295
|
+
}
|
|
152743
153296
|
var MEMORY_MUTATION_TYPES, TERMINAL_MUTATION_TYPES;
|
|
152744
153297
|
var init_storage_memory_mutation_log = __esm(() => {
|
|
152745
153298
|
MEMORY_MUTATION_TYPES = new Set(["archive", "delete", "update", "superseded"]);
|
|
@@ -153432,6 +153985,36 @@ function addStaleReduceStrippedIds(db, sessionId, ids) {
|
|
|
153432
153985
|
sessionLog(sessionId, `stale_reduce_stripped_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
153433
153986
|
return false;
|
|
153434
153987
|
}
|
|
153988
|
+
function getProcessedImageStrippedIds(db, sessionId) {
|
|
153989
|
+
const row = db.prepare("SELECT processed_image_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
153990
|
+
return new Set(parseStrippedBlob(row?.processed_image_stripped_ids));
|
|
153991
|
+
}
|
|
153992
|
+
function addProcessedImageStrippedIds(db, sessionId, ids) {
|
|
153993
|
+
const add = [...ids];
|
|
153994
|
+
if (add.length === 0)
|
|
153995
|
+
return true;
|
|
153996
|
+
ensureSessionMetaRow(db, sessionId);
|
|
153997
|
+
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
153998
|
+
const row = db.prepare("SELECT processed_image_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
153999
|
+
const rawStored = row ? row.processed_image_stripped_ids ?? null : null;
|
|
154000
|
+
const current = new Set(parseStrippedBlob(rawStored));
|
|
154001
|
+
let changed = false;
|
|
154002
|
+
for (const id of add) {
|
|
154003
|
+
if (!current.has(id)) {
|
|
154004
|
+
current.add(id);
|
|
154005
|
+
changed = true;
|
|
154006
|
+
}
|
|
154007
|
+
}
|
|
154008
|
+
if (!changed)
|
|
154009
|
+
return true;
|
|
154010
|
+
const nextBlob = JSON.stringify([...current]);
|
|
154011
|
+
const result = db.prepare("UPDATE session_meta SET processed_image_stripped_ids = ? WHERE session_id = ? AND processed_image_stripped_ids IS ?").run(nextBlob, sessionId, rawStored);
|
|
154012
|
+
if (result.changes > 0)
|
|
154013
|
+
return true;
|
|
154014
|
+
}
|
|
154015
|
+
sessionLog(sessionId, `processed_image_stripped_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
154016
|
+
return false;
|
|
154017
|
+
}
|
|
153435
154018
|
function isPendingCompactionMarker(value) {
|
|
153436
154019
|
return typeof value === "object" && value !== null && typeof value.ordinal === "number" && typeof value.endMessageId === "string" && typeof value.publishedAt === "number";
|
|
153437
154020
|
}
|
|
@@ -153610,6 +154193,8 @@ function clearSession(db, sessionId) {
|
|
|
153610
154193
|
db.prepare("DELETE FROM source_contents WHERE session_id = ?").run(sessionId);
|
|
153611
154194
|
db.prepare("DELETE FROM tags WHERE session_id = ?").run(sessionId);
|
|
153612
154195
|
db.prepare("DELETE FROM session_meta WHERE session_id = ?").run(sessionId);
|
|
154196
|
+
db.prepare("DELETE FROM session_projects WHERE session_id = ?").run(sessionId);
|
|
154197
|
+
db.prepare("DELETE FROM compartment_chunk_embeddings WHERE session_id = ?").run(sessionId);
|
|
153613
154198
|
db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
|
|
153614
154199
|
clearCompressionDepth(db, sessionId);
|
|
153615
154200
|
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
@@ -153716,9 +154301,9 @@ function buildStatusClause(status) {
|
|
|
153716
154301
|
if (statuses.length === 0) {
|
|
153717
154302
|
return null;
|
|
153718
154303
|
}
|
|
153719
|
-
const
|
|
154304
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
153720
154305
|
return {
|
|
153721
|
-
sql: `status IN (${
|
|
154306
|
+
sql: `status IN (${placeholders3})`,
|
|
153722
154307
|
params: statuses
|
|
153723
154308
|
};
|
|
153724
154309
|
}
|
|
@@ -153924,19 +154509,6 @@ function getProjectState(db, projectPath) {
|
|
|
153924
154509
|
WHERE project_path = ?`).get(projectPath);
|
|
153925
154510
|
return row ? toProjectState(row) : null;
|
|
153926
154511
|
}
|
|
153927
|
-
function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
|
|
153928
|
-
db.prepare(`INSERT INTO project_state
|
|
153929
|
-
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
153930
|
-
VALUES (?, 1, 0, ?)
|
|
153931
|
-
ON CONFLICT(project_path) DO UPDATE SET
|
|
153932
|
-
project_memory_epoch = project_memory_epoch + 1,
|
|
153933
|
-
updated_at = excluded.updated_at`).run(projectPath, now);
|
|
153934
|
-
const state = getProjectState(db, projectPath);
|
|
153935
|
-
if (!state) {
|
|
153936
|
-
throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
|
|
153937
|
-
}
|
|
153938
|
-
return state;
|
|
153939
|
-
}
|
|
153940
154512
|
function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PROJECT_PATH, now = Date.now()) {
|
|
153941
154513
|
db.prepare(`INSERT INTO project_state
|
|
153942
154514
|
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
@@ -153972,8 +154544,8 @@ function getSourceContents(db, sessionId, tagIds) {
|
|
|
153972
154544
|
if (tagIds.length === 0) {
|
|
153973
154545
|
return new Map;
|
|
153974
154546
|
}
|
|
153975
|
-
const
|
|
153976
|
-
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${
|
|
154547
|
+
const placeholders3 = tagIds.map(() => "?").join(", ");
|
|
154548
|
+
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${placeholders3})`).all(sessionId, ...tagIds).filter(isSourceContentRow);
|
|
153977
154549
|
const sources = new Map;
|
|
153978
154550
|
for (const row of rows) {
|
|
153979
154551
|
sources.set(row.tag_id, row.content);
|
|
@@ -154283,8 +154855,8 @@ function getTagsByNumbers(db, sessionId, tagNumbers) {
|
|
|
154283
154855
|
}
|
|
154284
154856
|
return all;
|
|
154285
154857
|
}
|
|
154286
|
-
const
|
|
154287
|
-
const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${
|
|
154858
|
+
const placeholders3 = tagNumbers.map(() => "?").join(",");
|
|
154859
|
+
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);
|
|
154288
154860
|
return rows.map(toTagEntry);
|
|
154289
154861
|
}
|
|
154290
154862
|
function getMaxDroppedTagNumber(db, sessionId) {
|
|
@@ -154437,6 +155009,7 @@ var init_storage = __esm(async () => {
|
|
|
154437
155009
|
init_storage_source();
|
|
154438
155010
|
init_storage_tags();
|
|
154439
155011
|
init_storage_v22_backfill_failures();
|
|
155012
|
+
init_workspaces();
|
|
154440
155013
|
await __promiseAll([
|
|
154441
155014
|
init_message_index(),
|
|
154442
155015
|
init_migrations(),
|
|
@@ -163888,7 +164461,7 @@ function isEmbeddingRow(row) {
|
|
|
163888
164461
|
if (row === null || typeof row !== "object")
|
|
163889
164462
|
return false;
|
|
163890
164463
|
const candidate = row;
|
|
163891
|
-
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding);
|
|
164464
|
+
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding) && (candidate.modelId === null || typeof candidate.modelId === "string");
|
|
163892
164465
|
}
|
|
163893
164466
|
function toFloat32Array(blob) {
|
|
163894
164467
|
if (blob instanceof Uint8Array) {
|
|
@@ -163908,7 +164481,7 @@ function getSaveEmbeddingStatement(db) {
|
|
|
163908
164481
|
function getLoadAllEmbeddingsStatement(db) {
|
|
163909
164482
|
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
163910
164483
|
if (!stmt) {
|
|
163911
|
-
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");
|
|
164484
|
+
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");
|
|
163912
164485
|
loadAllEmbeddingsStatements.set(db, stmt);
|
|
163913
164486
|
}
|
|
163914
164487
|
return stmt;
|
|
@@ -163937,7 +164510,10 @@ function loadAllEmbeddings(db, projectPath) {
|
|
|
163937
164510
|
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath).filter(isEmbeddingRow);
|
|
163938
164511
|
const embeddings = new Map;
|
|
163939
164512
|
for (const row of rows) {
|
|
163940
|
-
embeddings.set(row.memoryId,
|
|
164513
|
+
embeddings.set(row.memoryId, {
|
|
164514
|
+
embedding: toFloat32Array(row.embedding),
|
|
164515
|
+
modelId: row.modelId
|
|
164516
|
+
});
|
|
163941
164517
|
}
|
|
163942
164518
|
return embeddings;
|
|
163943
164519
|
}
|
|
@@ -164000,13 +164576,13 @@ var init_embedding_cache = __esm(() => {
|
|
|
164000
164576
|
});
|
|
164001
164577
|
|
|
164002
164578
|
// src/features/magic-context/memory/normalize-hash.ts
|
|
164003
|
-
import { createHash as
|
|
164579
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
164004
164580
|
function normalizeMemoryContent(content) {
|
|
164005
164581
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
164006
164582
|
}
|
|
164007
164583
|
function computeNormalizedHash(content) {
|
|
164008
164584
|
const normalized = normalizeMemoryContent(content);
|
|
164009
|
-
return
|
|
164585
|
+
return createHash7("md5").update(normalized).digest("hex");
|
|
164010
164586
|
}
|
|
164011
164587
|
var init_normalize_hash = () => {};
|
|
164012
164588
|
|
|
@@ -164120,8 +164696,8 @@ function getMemoriesByProjectStatement(db, statuses) {
|
|
|
164120
164696
|
}
|
|
164121
164697
|
let stmt = statements.get(db);
|
|
164122
164698
|
if (!stmt) {
|
|
164123
|
-
const
|
|
164124
|
-
stmt = db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories WHERE project_path = ? AND status IN (${
|
|
164699
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
164700
|
+
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`);
|
|
164125
164701
|
statements.set(db, stmt);
|
|
164126
164702
|
}
|
|
164127
164703
|
return stmt;
|
|
@@ -164242,6 +164818,97 @@ function getMemoriesByProject(db, projectPath, statuses = ["active", "permanent"
|
|
|
164242
164818
|
const rows = getMemoriesByProjectStatement(db, statuses).all(projectPath, ...statuses, expiryCutoff).filter(isMemoryRow);
|
|
164243
164819
|
return rows.map(toMemory);
|
|
164244
164820
|
}
|
|
164821
|
+
function sqlPlaceholders(values) {
|
|
164822
|
+
return values.map(() => "?").join(", ");
|
|
164823
|
+
}
|
|
164824
|
+
function uniqueValues(values) {
|
|
164825
|
+
return [...new Set(values.filter((value) => value.length > 0))];
|
|
164826
|
+
}
|
|
164827
|
+
function buildWorkspaceMemorySqlFilter(args) {
|
|
164828
|
+
if (args.shareCategories === null || args.shareCategories === undefined) {
|
|
164829
|
+
return { clause: "", params: [], active: false };
|
|
164830
|
+
}
|
|
164831
|
+
const identities = uniqueValues(args.identities);
|
|
164832
|
+
const identitySet = new Set(identities);
|
|
164833
|
+
const ownSet = new Set(uniqueValues(args.ownIdentities ?? []).filter((identity) => identitySet.has(identity)));
|
|
164834
|
+
const foreignIdentities = identities.filter((identity) => !ownSet.has(identity));
|
|
164835
|
+
if (foreignIdentities.length === 0) {
|
|
164836
|
+
return { clause: "", params: [], active: false };
|
|
164837
|
+
}
|
|
164838
|
+
const ownIdentities = identities.filter((identity) => ownSet.has(identity));
|
|
164839
|
+
const shareCategories = uniqueValues([...args.shareCategories]);
|
|
164840
|
+
const qualifier = args.tableName ? `${args.tableName}.` : "";
|
|
164841
|
+
const predicates = [];
|
|
164842
|
+
const params = [];
|
|
164843
|
+
if (ownIdentities.length > 0) {
|
|
164844
|
+
predicates.push(`${qualifier}project_path IN (${sqlPlaceholders(ownIdentities)})`);
|
|
164845
|
+
params.push(...ownIdentities);
|
|
164846
|
+
}
|
|
164847
|
+
if (foreignIdentities.length > 0 && shareCategories.length > 0) {
|
|
164848
|
+
predicates.push(`(${qualifier}project_path IN (${sqlPlaceholders(foreignIdentities)}) AND ${qualifier}category IN (${sqlPlaceholders(shareCategories)}))`);
|
|
164849
|
+
params.push(...foreignIdentities, ...shareCategories);
|
|
164850
|
+
}
|
|
164851
|
+
if (predicates.length === 0) {
|
|
164852
|
+
return { clause: " AND 0 = 1", params: [], active: true };
|
|
164853
|
+
}
|
|
164854
|
+
return { clause: ` AND (${predicates.join(" OR ")})`, params, active: true };
|
|
164855
|
+
}
|
|
164856
|
+
function getMemoriesByProjects(db, projectPaths, statuses = ["active", "permanent"], expiryCutoff = Date.now(), ownIdentities, shareCategories) {
|
|
164857
|
+
const identities = uniqueValues(projectPaths);
|
|
164858
|
+
if (identities.length === 0 || statuses.length === 0)
|
|
164859
|
+
return [];
|
|
164860
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
164861
|
+
identities,
|
|
164862
|
+
ownIdentities,
|
|
164863
|
+
shareCategories
|
|
164864
|
+
});
|
|
164865
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
164866
|
+
return getMemoriesByProject(db, identities[0], statuses, expiryCutoff);
|
|
164867
|
+
}
|
|
164868
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
164869
|
+
FROM memories
|
|
164870
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
164871
|
+
AND status IN (${sqlPlaceholders(statuses)})
|
|
164872
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
164873
|
+
ORDER BY category ASC, updated_at DESC, id ASC`).all(...identities, ...statuses, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
164874
|
+
return rows.map(toMemory);
|
|
164875
|
+
}
|
|
164876
|
+
function getMaxMemoryIdForProjects(db, projectPaths, ownIdentities, shareCategories) {
|
|
164877
|
+
const identities = uniqueValues(projectPaths);
|
|
164878
|
+
if (identities.length === 0)
|
|
164879
|
+
return 0;
|
|
164880
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
164881
|
+
identities,
|
|
164882
|
+
ownIdentities,
|
|
164883
|
+
shareCategories
|
|
164884
|
+
});
|
|
164885
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
164886
|
+
const row2 = db.prepare("SELECT COALESCE(MAX(id), 0) AS max_id FROM memories WHERE project_path = ?").get(identities[0]);
|
|
164887
|
+
return typeof row2?.max_id === "number" ? row2.max_id : 0;
|
|
164888
|
+
}
|
|
164889
|
+
const row = db.prepare(`SELECT COALESCE(MAX(id), 0) AS max_id
|
|
164890
|
+
FROM memories
|
|
164891
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})${sharingFilter.clause}`).get(...identities, ...sharingFilter.params);
|
|
164892
|
+
return typeof row?.max_id === "number" ? row.max_id : 0;
|
|
164893
|
+
}
|
|
164894
|
+
function readNewMemoriesForM1Union(db, projectPaths, afterId, expiryCutoff, ownIdentities, shareCategories) {
|
|
164895
|
+
const identities = uniqueValues(projectPaths);
|
|
164896
|
+
if (identities.length === 0)
|
|
164897
|
+
return [];
|
|
164898
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
164899
|
+
identities,
|
|
164900
|
+
ownIdentities,
|
|
164901
|
+
shareCategories
|
|
164902
|
+
});
|
|
164903
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
164904
|
+
FROM memories
|
|
164905
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
164906
|
+
AND id > ?
|
|
164907
|
+
AND status IN ('active', 'permanent')
|
|
164908
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
164909
|
+
ORDER BY ${MEMORY_CATEGORY_ORDER_SQL}, id ASC`).all(...identities, afterId, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
164910
|
+
return rows.map(toMemory);
|
|
164911
|
+
}
|
|
164245
164912
|
function getAllActiveMemoriesForMigration(db, projectPath) {
|
|
164246
164913
|
const rows = getActiveMemoriesNoExpiryStatement(db).all(projectPath).filter(isMemoryRow);
|
|
164247
164914
|
return rows.map(toMemory);
|
|
@@ -164339,6 +165006,7 @@ function getMemoryCountsByStatus(db, projectPath) {
|
|
|
164339
165006
|
}
|
|
164340
165007
|
var COLUMN_MAP, MEMORY_CATEGORY_LOOKUP, MEMORY_STATUS_LOOKUP, MEMORY_SOURCE_TYPE_LOOKUP, VERIFICATION_STATUS_LOOKUP, insertMemoryStatements, getMemoryByHashStatements, getMemoryByIdStatements, activeMemoriesNoExpiryStatements, updateMemorySeenCountStatements, updateMemoryRetrievalCountStatements, updateMemoryStatusStatements, updateArchivedMemoryStatements, updateMemoryVerificationStatements, updateMemoryContentStatements, supersededMemoryStatements, mergeMemoryStatsStatements, deleteMemoryStatements, deleteMemoryEmbeddingStatements, deleteEmbeddingOnContentUpdateStatements, getMemoryCountStatements, getMemoryCountByProjectStatements, getMemoryCountsByStatusStatements, memoriesByProjectStatements, memoryImportanceColumnCache;
|
|
164341
165008
|
var init_storage_memory = __esm(() => {
|
|
165009
|
+
init_constants();
|
|
164342
165010
|
init_embedding_cache();
|
|
164343
165011
|
init_normalize_hash();
|
|
164344
165012
|
COLUMN_MAP = {
|
|
@@ -164444,8 +165112,8 @@ function getUserMemoryCandidates(db) {
|
|
|
164444
165112
|
function deleteUserMemoryCandidates(db, ids) {
|
|
164445
165113
|
if (ids.length === 0)
|
|
164446
165114
|
return;
|
|
164447
|
-
const
|
|
164448
|
-
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${
|
|
165115
|
+
const placeholders3 = ids.map(() => "?").join(",");
|
|
165116
|
+
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${placeholders3})`).run(...ids);
|
|
164449
165117
|
}
|
|
164450
165118
|
function insertUserMemory(db, content, sourceCandidateIds) {
|
|
164451
165119
|
const now = Date.now();
|
|
@@ -164478,6 +165146,444 @@ function parseUserMemoryRow(row) {
|
|
|
164478
165146
|
};
|
|
164479
165147
|
}
|
|
164480
165148
|
|
|
165149
|
+
// src/features/magic-context/compartment-chunk-embedding.ts
|
|
165150
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
165151
|
+
function getLoadFtsRowsStatement(db) {
|
|
165152
|
+
let stmt = loadFtsRowsStatements.get(db);
|
|
165153
|
+
if (!stmt) {
|
|
165154
|
+
stmt = db.prepare(`SELECT message_ordinal AS messageOrdinal, role, content
|
|
165155
|
+
FROM message_history_fts
|
|
165156
|
+
WHERE session_id = ?
|
|
165157
|
+
AND message_ordinal >= ?
|
|
165158
|
+
AND message_ordinal <= ?
|
|
165159
|
+
AND role IN ('user', 'assistant')
|
|
165160
|
+
ORDER BY message_ordinal ASC`);
|
|
165161
|
+
loadFtsRowsStatements.set(db, stmt);
|
|
165162
|
+
}
|
|
165163
|
+
return stmt;
|
|
165164
|
+
}
|
|
165165
|
+
function getExistingHashStatement(db, scopedToProject) {
|
|
165166
|
+
const map2 = scopedToProject ? existingHashByProjectStatements : existingHashStatements;
|
|
165167
|
+
let stmt = map2.get(db);
|
|
165168
|
+
if (!stmt) {
|
|
165169
|
+
stmt = db.prepare(`SELECT window_index AS windowIndex, chunk_hash AS chunkHash
|
|
165170
|
+
FROM compartment_chunk_embeddings
|
|
165171
|
+
WHERE compartment_id = ?
|
|
165172
|
+
AND model_id = ?
|
|
165173
|
+
${scopedToProject ? "AND project_path = ?" : ""}
|
|
165174
|
+
ORDER BY window_index ASC`);
|
|
165175
|
+
map2.set(db, stmt);
|
|
165176
|
+
}
|
|
165177
|
+
return stmt;
|
|
165178
|
+
}
|
|
165179
|
+
function getDeleteByCompartmentStatement(db) {
|
|
165180
|
+
let stmt = deleteByCompartmentStatements.get(db);
|
|
165181
|
+
if (!stmt) {
|
|
165182
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE compartment_id = ?");
|
|
165183
|
+
deleteByCompartmentStatements.set(db, stmt);
|
|
165184
|
+
}
|
|
165185
|
+
return stmt;
|
|
165186
|
+
}
|
|
165187
|
+
function getInsertEmbeddingStatement(db) {
|
|
165188
|
+
let stmt = insertEmbeddingStatements.get(db);
|
|
165189
|
+
if (!stmt) {
|
|
165190
|
+
stmt = db.prepare(`INSERT INTO compartment_chunk_embeddings (
|
|
165191
|
+
compartment_id, session_id, project_path, harness, window_index,
|
|
165192
|
+
start_ordinal, end_ordinal, chunk_hash, model_id, dims, vector, created_at
|
|
165193
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
165194
|
+
insertEmbeddingStatements.set(db, stmt);
|
|
165195
|
+
}
|
|
165196
|
+
return stmt;
|
|
165197
|
+
}
|
|
165198
|
+
function getDistinctModelStatement(db) {
|
|
165199
|
+
let stmt = distinctModelStatements.get(db);
|
|
165200
|
+
if (!stmt) {
|
|
165201
|
+
stmt = db.prepare(`SELECT DISTINCT model_id AS modelId
|
|
165202
|
+
FROM compartment_chunk_embeddings
|
|
165203
|
+
WHERE project_path = ?`);
|
|
165204
|
+
distinctModelStatements.set(db, stmt);
|
|
165205
|
+
}
|
|
165206
|
+
return stmt;
|
|
165207
|
+
}
|
|
165208
|
+
function getClearProjectStatement(db) {
|
|
165209
|
+
let stmt = clearProjectStatements.get(db);
|
|
165210
|
+
if (!stmt) {
|
|
165211
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ?");
|
|
165212
|
+
clearProjectStatements.set(db, stmt);
|
|
165213
|
+
}
|
|
165214
|
+
return stmt;
|
|
165215
|
+
}
|
|
165216
|
+
function getClearProjectModelStatement(db) {
|
|
165217
|
+
let stmt = clearProjectModelStatements.get(db);
|
|
165218
|
+
if (!stmt) {
|
|
165219
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ? AND model_id = ?");
|
|
165220
|
+
clearProjectModelStatements.set(db, stmt);
|
|
165221
|
+
}
|
|
165222
|
+
return stmt;
|
|
165223
|
+
}
|
|
165224
|
+
function getSearchRowsStatement(db, withModel) {
|
|
165225
|
+
const map2 = withModel ? searchRowsByModelStatements : searchRowsStatements;
|
|
165226
|
+
let stmt = map2.get(db);
|
|
165227
|
+
if (!stmt) {
|
|
165228
|
+
stmt = db.prepare(`SELECT e.compartment_id AS compartmentId,
|
|
165229
|
+
e.session_id AS sessionId,
|
|
165230
|
+
c.title AS title,
|
|
165231
|
+
c.start_message AS compartmentStart,
|
|
165232
|
+
c.end_message AS compartmentEnd,
|
|
165233
|
+
e.window_index AS windowIndex,
|
|
165234
|
+
e.start_ordinal AS windowStart,
|
|
165235
|
+
e.end_ordinal AS windowEnd,
|
|
165236
|
+
e.chunk_hash AS chunkHash,
|
|
165237
|
+
e.model_id AS modelId,
|
|
165238
|
+
e.dims AS dims,
|
|
165239
|
+
e.vector AS vector
|
|
165240
|
+
FROM compartment_chunk_embeddings e
|
|
165241
|
+
JOIN compartments c ON c.id = e.compartment_id
|
|
165242
|
+
WHERE e.session_id = ?
|
|
165243
|
+
AND e.project_path = ?
|
|
165244
|
+
${withModel ? "AND e.model_id = ?" : ""}
|
|
165245
|
+
ORDER BY e.compartment_id ASC, e.window_index ASC`);
|
|
165246
|
+
map2.set(db, stmt);
|
|
165247
|
+
}
|
|
165248
|
+
return stmt;
|
|
165249
|
+
}
|
|
165250
|
+
function isFinitePositiveInteger(value) {
|
|
165251
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
165252
|
+
}
|
|
165253
|
+
function normalizeCompartmentChunkMaxInputTokens(value) {
|
|
165254
|
+
if (!isFinitePositiveInteger(value)) {
|
|
165255
|
+
return DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS;
|
|
165256
|
+
}
|
|
165257
|
+
return Math.max(1, Math.floor(value));
|
|
165258
|
+
}
|
|
165259
|
+
function normalizeContent(text) {
|
|
165260
|
+
return text.replace(/\s+/g, " ").trim();
|
|
165261
|
+
}
|
|
165262
|
+
function formatOrdinalRange(start, end) {
|
|
165263
|
+
return start === end ? `[${start}]` : `[${start}-${end}]`;
|
|
165264
|
+
}
|
|
165265
|
+
function rolePrefix(role) {
|
|
165266
|
+
if (role === "user")
|
|
165267
|
+
return "U";
|
|
165268
|
+
if (role === "assistant")
|
|
165269
|
+
return "A";
|
|
165270
|
+
return null;
|
|
165271
|
+
}
|
|
165272
|
+
function parseOrdinal(value) {
|
|
165273
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
165274
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
165275
|
+
}
|
|
165276
|
+
function parseCanonicalLineRange(line) {
|
|
165277
|
+
const match = /^\[(\d+)(?:-(\d+))?\]\s+[UA]:/.exec(line.trim());
|
|
165278
|
+
if (!match)
|
|
165279
|
+
return null;
|
|
165280
|
+
const start = Number.parseInt(match[1], 10);
|
|
165281
|
+
const end = match[2] ? Number.parseInt(match[2], 10) : start;
|
|
165282
|
+
if (!Number.isFinite(start) || !Number.isFinite(end))
|
|
165283
|
+
return null;
|
|
165284
|
+
return { start, end };
|
|
165285
|
+
}
|
|
165286
|
+
function hashChunkText(text) {
|
|
165287
|
+
return createHash8("sha256").update(text).digest("hex");
|
|
165288
|
+
}
|
|
165289
|
+
function vectorBlob(vector) {
|
|
165290
|
+
return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
|
|
165291
|
+
}
|
|
165292
|
+
function toFloat32Array2(blob) {
|
|
165293
|
+
if (blob instanceof Uint8Array) {
|
|
165294
|
+
const buffer2 = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
165295
|
+
return new Float32Array(buffer2);
|
|
165296
|
+
}
|
|
165297
|
+
return new Float32Array(blob.slice(0));
|
|
165298
|
+
}
|
|
165299
|
+
function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal) {
|
|
165300
|
+
if (endOrdinal < startOrdinal)
|
|
165301
|
+
return "";
|
|
165302
|
+
const rows = getLoadFtsRowsStatement(db).all(sessionId, startOrdinal, endOrdinal).map((row) => row);
|
|
165303
|
+
const lines = [];
|
|
165304
|
+
let current = null;
|
|
165305
|
+
const flush2 = () => {
|
|
165306
|
+
if (!current || current.parts.length === 0)
|
|
165307
|
+
return;
|
|
165308
|
+
lines.push(`${formatOrdinalRange(current.start, current.end)} ${current.role}: ${current.parts.join(" / ")}`);
|
|
165309
|
+
current = null;
|
|
165310
|
+
};
|
|
165311
|
+
for (const row of rows) {
|
|
165312
|
+
const ordinal = parseOrdinal(row.messageOrdinal);
|
|
165313
|
+
const prefix = rolePrefix(row.role);
|
|
165314
|
+
const content = typeof row.content === "string" ? normalizeContent(row.content) : "";
|
|
165315
|
+
if (ordinal === null || prefix === null || content.length === 0)
|
|
165316
|
+
continue;
|
|
165317
|
+
if (current && current.role === prefix) {
|
|
165318
|
+
current.end = ordinal;
|
|
165319
|
+
current.parts.push(content);
|
|
165320
|
+
continue;
|
|
165321
|
+
}
|
|
165322
|
+
flush2();
|
|
165323
|
+
current = { role: prefix, start: ordinal, end: ordinal, parts: [content] };
|
|
165324
|
+
}
|
|
165325
|
+
flush2();
|
|
165326
|
+
return lines.join(`
|
|
165327
|
+
`);
|
|
165328
|
+
}
|
|
165329
|
+
function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
|
|
165330
|
+
const lines = [];
|
|
165331
|
+
for (const rawLine of chunkText.split(/\r?\n/)) {
|
|
165332
|
+
const line = rawLine.trim();
|
|
165333
|
+
const match = /^(\[(\d+)(?:-(\d+))?\]\s+[UA]:)\s*(.*)$/.exec(line);
|
|
165334
|
+
if (!match)
|
|
165335
|
+
continue;
|
|
165336
|
+
const lineStart = Number.parseInt(match[2], 10);
|
|
165337
|
+
const lineEnd = match[3] ? Number.parseInt(match[3], 10) : lineStart;
|
|
165338
|
+
if (startOrdinal != null && lineEnd < startOrdinal)
|
|
165339
|
+
continue;
|
|
165340
|
+
if (endOrdinal != null && lineStart > endOrdinal)
|
|
165341
|
+
continue;
|
|
165342
|
+
const rawParts = match[4].split(" / ").map((part) => normalizeContent(part)).filter((part) => part.length > 0);
|
|
165343
|
+
const ordinalSpan = lineEnd - lineStart + 1;
|
|
165344
|
+
const roleLabel = match[1].slice(match[1].indexOf("]") + 2);
|
|
165345
|
+
if (ordinalSpan === rawParts.length) {
|
|
165346
|
+
const retained = rawParts.map((part, index) => ({ ordinal: lineStart + index, part })).filter(({ ordinal, part }) => {
|
|
165347
|
+
if (part.startsWith("TC:"))
|
|
165348
|
+
return false;
|
|
165349
|
+
if (startOrdinal != null && ordinal < startOrdinal)
|
|
165350
|
+
return false;
|
|
165351
|
+
if (endOrdinal != null && ordinal > endOrdinal)
|
|
165352
|
+
return false;
|
|
165353
|
+
return true;
|
|
165354
|
+
});
|
|
165355
|
+
if (retained.length === 0)
|
|
165356
|
+
continue;
|
|
165357
|
+
const retainedStart = retained[0].ordinal;
|
|
165358
|
+
const retainedEnd = retained[retained.length - 1].ordinal;
|
|
165359
|
+
lines.push(`${formatOrdinalRange(retainedStart, retainedEnd)} ${roleLabel} ${retained.map(({ part }) => part).join(" / ")}`);
|
|
165360
|
+
continue;
|
|
165361
|
+
}
|
|
165362
|
+
const parts = rawParts.filter((part) => !part.startsWith("TC:"));
|
|
165363
|
+
if (parts.length === 0)
|
|
165364
|
+
continue;
|
|
165365
|
+
lines.push(`${match[1]} ${parts.join(" / ")}`);
|
|
165366
|
+
}
|
|
165367
|
+
return lines.join(`
|
|
165368
|
+
`);
|
|
165369
|
+
}
|
|
165370
|
+
function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTokens) {
|
|
165371
|
+
const lines = canonicalText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
165372
|
+
if (lines.length === 0 || endOrdinal < startOrdinal)
|
|
165373
|
+
return [];
|
|
165374
|
+
const normalizedMax = normalizeCompartmentChunkMaxInputTokens(maxInputTokens);
|
|
165375
|
+
const fullText = lines.join(`
|
|
165376
|
+
`);
|
|
165377
|
+
if (estimateTokens(fullText) <= normalizedMax) {
|
|
165378
|
+
return [
|
|
165379
|
+
{
|
|
165380
|
+
windowIndex: 0,
|
|
165381
|
+
startOrdinal,
|
|
165382
|
+
endOrdinal,
|
|
165383
|
+
text: fullText,
|
|
165384
|
+
chunkHash: hashChunkText(fullText)
|
|
165385
|
+
}
|
|
165386
|
+
];
|
|
165387
|
+
}
|
|
165388
|
+
const windows = [];
|
|
165389
|
+
let currentLines = [];
|
|
165390
|
+
let currentStart = null;
|
|
165391
|
+
let currentEnd = null;
|
|
165392
|
+
let currentTokens = 0;
|
|
165393
|
+
const flush2 = () => {
|
|
165394
|
+
if (currentLines.length === 0 || currentStart === null || currentEnd === null)
|
|
165395
|
+
return;
|
|
165396
|
+
const text = currentLines.join(`
|
|
165397
|
+
`);
|
|
165398
|
+
windows.push({
|
|
165399
|
+
windowIndex: windows.length + 1,
|
|
165400
|
+
startOrdinal: currentStart,
|
|
165401
|
+
endOrdinal: currentEnd,
|
|
165402
|
+
text,
|
|
165403
|
+
chunkHash: hashChunkText(text)
|
|
165404
|
+
});
|
|
165405
|
+
currentLines = [];
|
|
165406
|
+
currentStart = null;
|
|
165407
|
+
currentEnd = null;
|
|
165408
|
+
currentTokens = 0;
|
|
165409
|
+
};
|
|
165410
|
+
for (const line of lines) {
|
|
165411
|
+
const range = parseCanonicalLineRange(line);
|
|
165412
|
+
const lineStart = range?.start ?? startOrdinal;
|
|
165413
|
+
const lineEnd = range?.end ?? lineStart;
|
|
165414
|
+
const lineTokens = estimateTokens(line);
|
|
165415
|
+
if (currentLines.length > 0 && currentTokens + lineTokens > normalizedMax) {
|
|
165416
|
+
flush2();
|
|
165417
|
+
}
|
|
165418
|
+
if (currentLines.length === 0) {
|
|
165419
|
+
currentStart = lineStart;
|
|
165420
|
+
}
|
|
165421
|
+
currentLines.push(line);
|
|
165422
|
+
currentEnd = lineEnd;
|
|
165423
|
+
currentTokens += lineTokens;
|
|
165424
|
+
}
|
|
165425
|
+
flush2();
|
|
165426
|
+
return windows;
|
|
165427
|
+
}
|
|
165428
|
+
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
165429
|
+
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
165430
|
+
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
165431
|
+
return new Map(rows.filter((row) => typeof row.windowIndex === "number" && typeof row.chunkHash === "string").map((row) => [row.windowIndex, row.chunkHash]));
|
|
165432
|
+
}
|
|
165433
|
+
function chunkEmbeddingWindowsAreCurrent(db, compartmentId, modelId, windows, projectPath) {
|
|
165434
|
+
const existing = getExistingChunkHashes(db, compartmentId, modelId, projectPath);
|
|
165435
|
+
if (existing.size !== windows.length)
|
|
165436
|
+
return false;
|
|
165437
|
+
return windows.every((window) => existing.get(window.windowIndex) === window.chunkHash);
|
|
165438
|
+
}
|
|
165439
|
+
function replaceCompartmentChunkEmbeddings(db, rows) {
|
|
165440
|
+
if (rows.length === 0)
|
|
165441
|
+
return;
|
|
165442
|
+
const compartmentId = rows[0].compartmentId;
|
|
165443
|
+
const now = Date.now();
|
|
165444
|
+
db.transaction(() => {
|
|
165445
|
+
getDeleteByCompartmentStatement(db).run(compartmentId);
|
|
165446
|
+
const insert = getInsertEmbeddingStatement(db);
|
|
165447
|
+
for (const row of rows) {
|
|
165448
|
+
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);
|
|
165449
|
+
}
|
|
165450
|
+
})();
|
|
165451
|
+
}
|
|
165452
|
+
function getDistinctChunkEmbeddingModelIds(db, projectPath) {
|
|
165453
|
+
const rows = getDistinctModelStatement(db).all(projectPath);
|
|
165454
|
+
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
165455
|
+
}
|
|
165456
|
+
function clearChunkEmbeddingsForProject(db, projectPath, modelId) {
|
|
165457
|
+
if (modelId) {
|
|
165458
|
+
return getClearProjectModelStatement(db).run(projectPath, modelId).changes;
|
|
165459
|
+
}
|
|
165460
|
+
return getClearProjectStatement(db).run(projectPath).changes;
|
|
165461
|
+
}
|
|
165462
|
+
function loadCompartmentChunkEmbeddingsForSearch(db, sessionId, projectPath, modelId) {
|
|
165463
|
+
const rows = modelId ? getSearchRowsStatement(db, true).all(sessionId, projectPath, modelId) : getSearchRowsStatement(db, false).all(sessionId, projectPath);
|
|
165464
|
+
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) => ({
|
|
165465
|
+
compartmentId: row.compartmentId,
|
|
165466
|
+
sessionId: row.sessionId,
|
|
165467
|
+
title: row.title,
|
|
165468
|
+
startOrdinal: row.compartmentStart,
|
|
165469
|
+
endOrdinal: row.compartmentEnd,
|
|
165470
|
+
windowIndex: row.windowIndex,
|
|
165471
|
+
windowStartOrdinal: row.windowStart,
|
|
165472
|
+
windowEndOrdinal: row.windowEnd,
|
|
165473
|
+
chunkHash: row.chunkHash,
|
|
165474
|
+
modelId: row.modelId,
|
|
165475
|
+
dims: row.dims,
|
|
165476
|
+
vector: toFloat32Array2(row.vector)
|
|
165477
|
+
}));
|
|
165478
|
+
}
|
|
165479
|
+
function mapBackfillCandidateRows(rows) {
|
|
165480
|
+
return rows.filter((row) => {
|
|
165481
|
+
if (row === null || typeof row !== "object")
|
|
165482
|
+
return false;
|
|
165483
|
+
const candidate = row;
|
|
165484
|
+
return typeof candidate.id === "number" && typeof candidate.sessionId === "string" && typeof candidate.startMessage === "number" && typeof candidate.endMessage === "number" && typeof candidate.title === "string";
|
|
165485
|
+
}).map((row) => ({
|
|
165486
|
+
id: row.id,
|
|
165487
|
+
sessionId: row.sessionId,
|
|
165488
|
+
startMessage: row.startMessage,
|
|
165489
|
+
endMessage: row.endMessage,
|
|
165490
|
+
title: row.title
|
|
165491
|
+
}));
|
|
165492
|
+
}
|
|
165493
|
+
function loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelId, limit, excludeIds) {
|
|
165494
|
+
if (excludeIds && excludeIds.length > 0) {
|
|
165495
|
+
const placeholders3 = excludeIds.map(() => "?").join(", ");
|
|
165496
|
+
const stmt2 = db.prepare(`SELECT c.id AS id,
|
|
165497
|
+
c.session_id AS sessionId,
|
|
165498
|
+
c.start_message AS startMessage,
|
|
165499
|
+
c.end_message AS endMessage,
|
|
165500
|
+
c.title AS title
|
|
165501
|
+
FROM compartments c
|
|
165502
|
+
JOIN session_projects sp
|
|
165503
|
+
ON sp.session_id = c.session_id
|
|
165504
|
+
AND sp.harness = c.harness
|
|
165505
|
+
AND sp.project_path = ?
|
|
165506
|
+
WHERE c.session_id = ?
|
|
165507
|
+
AND c.start_message IS NOT NULL
|
|
165508
|
+
AND c.end_message IS NOT NULL
|
|
165509
|
+
AND c.id NOT IN (${placeholders3})
|
|
165510
|
+
AND NOT EXISTS (
|
|
165511
|
+
SELECT 1
|
|
165512
|
+
FROM compartment_chunk_embeddings current
|
|
165513
|
+
WHERE current.compartment_id = c.id
|
|
165514
|
+
AND current.project_path = ?
|
|
165515
|
+
AND current.model_id = ?
|
|
165516
|
+
)
|
|
165517
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
165518
|
+
LIMIT ?`);
|
|
165519
|
+
const rows2 = stmt2.all(projectPath, sessionId, ...excludeIds, projectPath, modelId, Math.max(1, limit));
|
|
165520
|
+
return mapBackfillCandidateRows(rows2);
|
|
165521
|
+
}
|
|
165522
|
+
let stmt = sessionBackfillCandidateStatements.get(db);
|
|
165523
|
+
if (!stmt) {
|
|
165524
|
+
stmt = db.prepare(`SELECT c.id AS id,
|
|
165525
|
+
c.session_id AS sessionId,
|
|
165526
|
+
c.start_message AS startMessage,
|
|
165527
|
+
c.end_message AS endMessage,
|
|
165528
|
+
c.title AS title
|
|
165529
|
+
FROM compartments c
|
|
165530
|
+
JOIN session_projects sp
|
|
165531
|
+
ON sp.session_id = c.session_id
|
|
165532
|
+
AND sp.harness = c.harness
|
|
165533
|
+
AND sp.project_path = ?
|
|
165534
|
+
WHERE c.session_id = ?
|
|
165535
|
+
AND c.start_message IS NOT NULL
|
|
165536
|
+
AND c.end_message IS NOT NULL
|
|
165537
|
+
AND NOT EXISTS (
|
|
165538
|
+
SELECT 1
|
|
165539
|
+
FROM compartment_chunk_embeddings current
|
|
165540
|
+
WHERE current.compartment_id = c.id
|
|
165541
|
+
AND current.project_path = ?
|
|
165542
|
+
AND current.model_id = ?
|
|
165543
|
+
)
|
|
165544
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
165545
|
+
LIMIT ?`);
|
|
165546
|
+
sessionBackfillCandidateStatements.set(db, stmt);
|
|
165547
|
+
}
|
|
165548
|
+
const rows = stmt.all(projectPath, sessionId, projectPath, modelId, Math.max(1, limit));
|
|
165549
|
+
return mapBackfillCandidateRows(rows);
|
|
165550
|
+
}
|
|
165551
|
+
function countUnembeddedSessionCompartments(db, projectPath, sessionId, modelId) {
|
|
165552
|
+
const row = db.prepare(`SELECT COUNT(*) AS n
|
|
165553
|
+
FROM compartments c
|
|
165554
|
+
JOIN session_projects sp
|
|
165555
|
+
ON sp.session_id = c.session_id
|
|
165556
|
+
AND sp.harness = c.harness
|
|
165557
|
+
AND sp.project_path = ?
|
|
165558
|
+
WHERE c.session_id = ?
|
|
165559
|
+
AND c.start_message IS NOT NULL
|
|
165560
|
+
AND c.end_message IS NOT NULL
|
|
165561
|
+
AND NOT EXISTS (
|
|
165562
|
+
SELECT 1
|
|
165563
|
+
FROM compartment_chunk_embeddings current
|
|
165564
|
+
WHERE current.compartment_id = c.id
|
|
165565
|
+
AND current.project_path = ?
|
|
165566
|
+
AND current.model_id = ?
|
|
165567
|
+
)`).get(projectPath, sessionId, projectPath, modelId);
|
|
165568
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
165569
|
+
}
|
|
165570
|
+
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512, loadFtsRowsStatements, existingHashStatements, existingHashByProjectStatements, deleteByCompartmentStatements, insertEmbeddingStatements, distinctModelStatements, clearProjectStatements, clearProjectModelStatements, searchRowsStatements, searchRowsByModelStatements, backfillCandidateStatements, sessionBackfillCandidateStatements;
|
|
165571
|
+
var init_compartment_chunk_embedding = __esm(() => {
|
|
165572
|
+
init_read_session_formatting();
|
|
165573
|
+
loadFtsRowsStatements = new WeakMap;
|
|
165574
|
+
existingHashStatements = new WeakMap;
|
|
165575
|
+
existingHashByProjectStatements = new WeakMap;
|
|
165576
|
+
deleteByCompartmentStatements = new WeakMap;
|
|
165577
|
+
insertEmbeddingStatements = new WeakMap;
|
|
165578
|
+
distinctModelStatements = new WeakMap;
|
|
165579
|
+
clearProjectStatements = new WeakMap;
|
|
165580
|
+
clearProjectModelStatements = new WeakMap;
|
|
165581
|
+
searchRowsStatements = new WeakMap;
|
|
165582
|
+
searchRowsByModelStatements = new WeakMap;
|
|
165583
|
+
backfillCandidateStatements = new WeakMap;
|
|
165584
|
+
sessionBackfillCandidateStatements = new WeakMap;
|
|
165585
|
+
});
|
|
165586
|
+
|
|
164481
165587
|
// src/features/magic-context/memory/cosine-similarity.ts
|
|
164482
165588
|
function cosineSimilarity(a, b) {
|
|
164483
165589
|
if (a.length !== b.length) {
|
|
@@ -164635,19 +165741,19 @@ function isArrayLikeNumber(value) {
|
|
|
164635
165741
|
}
|
|
164636
165742
|
return arr.length === 0 || typeof arr[0] === "number";
|
|
164637
165743
|
}
|
|
164638
|
-
function
|
|
165744
|
+
function toFloat32Array3(values) {
|
|
164639
165745
|
return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
|
|
164640
165746
|
}
|
|
164641
165747
|
function extractBatchEmbeddings(result, expectedCount) {
|
|
164642
165748
|
const { data } = result;
|
|
164643
165749
|
if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
|
|
164644
|
-
return data.map((entry) =>
|
|
165750
|
+
return data.map((entry) => toFloat32Array3(entry));
|
|
164645
165751
|
}
|
|
164646
165752
|
if (!isArrayLikeNumber(data)) {
|
|
164647
165753
|
log("[magic-context] embedding batch returned unexpected data shape");
|
|
164648
165754
|
return Array.from({ length: expectedCount }, () => null);
|
|
164649
165755
|
}
|
|
164650
|
-
const flatData =
|
|
165756
|
+
const flatData = toFloat32Array3(data);
|
|
164651
165757
|
const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
|
|
164652
165758
|
if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
|
|
164653
165759
|
log("[magic-context] embedding batch returned invalid dimensions");
|
|
@@ -164662,6 +165768,7 @@ function extractBatchEmbeddings(result, expectedCount) {
|
|
|
164662
165768
|
|
|
164663
165769
|
class LocalEmbeddingProvider {
|
|
164664
165770
|
modelId;
|
|
165771
|
+
maxInputTokens;
|
|
164665
165772
|
model;
|
|
164666
165773
|
pipeline = null;
|
|
164667
165774
|
initPromise = null;
|
|
@@ -164669,8 +165776,9 @@ class LocalEmbeddingProvider {
|
|
|
164669
165776
|
disposing = false;
|
|
164670
165777
|
disposePromise = null;
|
|
164671
165778
|
inFlightWaiters = [];
|
|
164672
|
-
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
165779
|
+
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
|
|
164673
165780
|
this.model = model;
|
|
165781
|
+
this.maxInputTokens = maxInputTokens;
|
|
164674
165782
|
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
164675
165783
|
}
|
|
164676
165784
|
async initialize() {
|
|
@@ -164930,6 +166038,7 @@ function normalizeEndpoint3(endpoint) {
|
|
|
164930
166038
|
|
|
164931
166039
|
class OpenAICompatibleEmbeddingProvider {
|
|
164932
166040
|
modelId;
|
|
166041
|
+
maxInputTokens;
|
|
164933
166042
|
endpoint;
|
|
164934
166043
|
model;
|
|
164935
166044
|
apiKey;
|
|
@@ -164946,11 +166055,13 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164946
166055
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
164947
166056
|
this.inputType = options.inputType?.trim() ?? "";
|
|
164948
166057
|
this.truncate = options.truncate?.trim() ?? "";
|
|
166058
|
+
this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
|
|
164949
166059
|
this.modelId = getEmbeddingProviderIdentity({
|
|
164950
166060
|
provider: "openai-compatible",
|
|
164951
166061
|
endpoint: this.endpoint,
|
|
164952
166062
|
model: this.model,
|
|
164953
|
-
...this.apiKey ? { api_key: this.apiKey } : {}
|
|
166063
|
+
...this.apiKey ? { api_key: this.apiKey } : {},
|
|
166064
|
+
...this.inputType ? { input_type: this.inputType } : {}
|
|
164954
166065
|
});
|
|
164955
166066
|
}
|
|
164956
166067
|
async initialize() {
|
|
@@ -165194,12 +166305,12 @@ function getCountEmbeddedStatement(db) {
|
|
|
165194
166305
|
}
|
|
165195
166306
|
return stmt;
|
|
165196
166307
|
}
|
|
165197
|
-
function
|
|
165198
|
-
let stmt =
|
|
166308
|
+
function getClearProjectStatement2(db) {
|
|
166309
|
+
let stmt = clearProjectStatements2.get(db);
|
|
165199
166310
|
if (!stmt) {
|
|
165200
166311
|
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
165201
166312
|
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
165202
|
-
|
|
166313
|
+
clearProjectStatements2.set(db, stmt);
|
|
165203
166314
|
}
|
|
165204
166315
|
return stmt;
|
|
165205
166316
|
}
|
|
@@ -165235,19 +166346,19 @@ function countEmbeddedCommits(db, projectPath) {
|
|
|
165235
166346
|
return row?.count ?? 0;
|
|
165236
166347
|
}
|
|
165237
166348
|
function clearProjectCommitEmbeddings(db, projectPath) {
|
|
165238
|
-
return
|
|
166349
|
+
return getClearProjectStatement2(db).run(projectPath).changes;
|
|
165239
166350
|
}
|
|
165240
166351
|
function getDistinctCommitEmbeddingModelIds(db, projectPath) {
|
|
165241
166352
|
const rows = getDistinctModelIdStatement(db).all(projectPath);
|
|
165242
166353
|
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
165243
166354
|
}
|
|
165244
|
-
var saveStatements, loadProjectStatements, loadUnembeddedStatements, countEmbeddedStatements,
|
|
166355
|
+
var saveStatements, loadProjectStatements, loadUnembeddedStatements, countEmbeddedStatements, clearProjectStatements2, distinctModelIdStatements;
|
|
165245
166356
|
var init_storage_git_commit_embeddings = __esm(() => {
|
|
165246
166357
|
saveStatements = new WeakMap;
|
|
165247
166358
|
loadProjectStatements = new WeakMap;
|
|
165248
166359
|
loadUnembeddedStatements = new WeakMap;
|
|
165249
166360
|
countEmbeddedStatements = new WeakMap;
|
|
165250
|
-
|
|
166361
|
+
clearProjectStatements2 = new WeakMap;
|
|
165251
166362
|
distinctModelIdStatements = new WeakMap;
|
|
165252
166363
|
});
|
|
165253
166364
|
|
|
@@ -165373,13 +166484,90 @@ var init_sweep_coordinator = __esm(() => {
|
|
|
165373
166484
|
GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
|
|
165374
166485
|
});
|
|
165375
166486
|
|
|
166487
|
+
// src/features/magic-context/session-project-storage.ts
|
|
166488
|
+
function getUpsertSessionProjectStatement(db) {
|
|
166489
|
+
let stmt = upsertSessionProjectStatements.get(db);
|
|
166490
|
+
if (!stmt) {
|
|
166491
|
+
stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
|
|
166492
|
+
VALUES (?, ?, ?, ?)
|
|
166493
|
+
ON CONFLICT(session_id, harness) DO UPDATE SET
|
|
166494
|
+
project_path = excluded.project_path,
|
|
166495
|
+
updated_at = excluded.updated_at
|
|
166496
|
+
WHERE session_projects.project_path <> excluded.project_path`);
|
|
166497
|
+
upsertSessionProjectStatements.set(db, stmt);
|
|
166498
|
+
}
|
|
166499
|
+
return stmt;
|
|
166500
|
+
}
|
|
166501
|
+
function getRepairSessionChunkProjectStatement(db) {
|
|
166502
|
+
let stmt = repairSessionChunkProjectStatements.get(db);
|
|
166503
|
+
if (!stmt) {
|
|
166504
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
166505
|
+
SET project_path = ?
|
|
166506
|
+
WHERE session_id = ?
|
|
166507
|
+
AND harness = ?
|
|
166508
|
+
AND project_path <> ?`);
|
|
166509
|
+
repairSessionChunkProjectStatements.set(db, stmt);
|
|
166510
|
+
}
|
|
166511
|
+
return stmt;
|
|
166512
|
+
}
|
|
166513
|
+
function getRepairProjectChunkProjectStatement(db) {
|
|
166514
|
+
let stmt = repairProjectChunkProjectStatements.get(db);
|
|
166515
|
+
if (!stmt) {
|
|
166516
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
166517
|
+
SET project_path = (
|
|
166518
|
+
SELECT sp.project_path
|
|
166519
|
+
FROM session_projects sp
|
|
166520
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
166521
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
166522
|
+
LIMIT 1
|
|
166523
|
+
)
|
|
166524
|
+
WHERE EXISTS (
|
|
166525
|
+
SELECT 1
|
|
166526
|
+
FROM session_projects sp
|
|
166527
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
166528
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
166529
|
+
AND sp.project_path <> compartment_chunk_embeddings.project_path
|
|
166530
|
+
AND (
|
|
166531
|
+
sp.project_path = ?
|
|
166532
|
+
OR compartment_chunk_embeddings.project_path = ?
|
|
166533
|
+
)
|
|
166534
|
+
)`);
|
|
166535
|
+
repairProjectChunkProjectStatements.set(db, stmt);
|
|
166536
|
+
}
|
|
166537
|
+
return stmt;
|
|
166538
|
+
}
|
|
166539
|
+
function recordSessionProjectIdentity(db, sessionId, projectPath) {
|
|
166540
|
+
if (!sessionId || !projectPath)
|
|
166541
|
+
return;
|
|
166542
|
+
const harness = getHarness();
|
|
166543
|
+
const now = Date.now();
|
|
166544
|
+
db.transaction(() => {
|
|
166545
|
+
getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
|
|
166546
|
+
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
|
|
166547
|
+
})();
|
|
166548
|
+
}
|
|
166549
|
+
function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
166550
|
+
if (!projectPath)
|
|
166551
|
+
return 0;
|
|
166552
|
+
return getRepairProjectChunkProjectStatement(db).run(projectPath, projectPath).changes;
|
|
166553
|
+
}
|
|
166554
|
+
var upsertSessionProjectStatements, repairSessionChunkProjectStatements, repairProjectChunkProjectStatements;
|
|
166555
|
+
var init_session_project_storage = __esm(() => {
|
|
166556
|
+
upsertSessionProjectStatements = new WeakMap;
|
|
166557
|
+
repairSessionChunkProjectStatements = new WeakMap;
|
|
166558
|
+
repairProjectChunkProjectStatements = new WeakMap;
|
|
166559
|
+
});
|
|
166560
|
+
|
|
165376
166561
|
// src/features/magic-context/project-embedding-registry.ts
|
|
165377
|
-
import { createHash as
|
|
166562
|
+
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
165378
166563
|
function resolveEmbeddingConfig(config2) {
|
|
165379
166564
|
if (!config2 || config2.provider === "local") {
|
|
165380
166565
|
return {
|
|
165381
166566
|
provider: "local",
|
|
165382
|
-
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
166567
|
+
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
166568
|
+
...config2?.max_input_tokens ? {
|
|
166569
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
166570
|
+
} : {}
|
|
165383
166571
|
};
|
|
165384
166572
|
}
|
|
165385
166573
|
if (config2.provider === "openai-compatible") {
|
|
@@ -165392,7 +166580,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
165392
166580
|
endpoint: config2.endpoint.trim(),
|
|
165393
166581
|
...apiKey ? { api_key: apiKey } : {},
|
|
165394
166582
|
...inputType ? { input_type: inputType } : {},
|
|
165395
|
-
...truncate ? { truncate } : {}
|
|
166583
|
+
...truncate ? { truncate } : {},
|
|
166584
|
+
...config2.max_input_tokens ? {
|
|
166585
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
166586
|
+
} : {}
|
|
165396
166587
|
};
|
|
165397
166588
|
}
|
|
165398
166589
|
return { provider: "off" };
|
|
@@ -165410,10 +166601,11 @@ function createProvider(config2) {
|
|
|
165410
166601
|
model: config2.model,
|
|
165411
166602
|
apiKey: config2.api_key,
|
|
165412
166603
|
inputType: config2.input_type,
|
|
165413
|
-
truncate: config2.truncate
|
|
166604
|
+
truncate: config2.truncate,
|
|
166605
|
+
maxInputTokens: config2.max_input_tokens
|
|
165414
166606
|
});
|
|
165415
166607
|
}
|
|
165416
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
166608
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
165417
166609
|
}
|
|
165418
166610
|
function stableStringify2(value) {
|
|
165419
166611
|
if (Array.isArray(value)) {
|
|
@@ -165426,7 +166618,7 @@ function stableStringify2(value) {
|
|
|
165426
166618
|
return JSON.stringify(value);
|
|
165427
166619
|
}
|
|
165428
166620
|
function sha256Prefix(value, length = 16) {
|
|
165429
|
-
return
|
|
166621
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, length);
|
|
165430
166622
|
}
|
|
165431
166623
|
function getRuntimeFingerprint(config2) {
|
|
165432
166624
|
if (config2.provider === "off") {
|
|
@@ -165434,6 +166626,18 @@ function getRuntimeFingerprint(config2) {
|
|
|
165434
166626
|
}
|
|
165435
166627
|
return `${getEmbeddingProviderIdentity(config2)}:${sha256Prefix(stableStringify2(config2))}`;
|
|
165436
166628
|
}
|
|
166629
|
+
function getChunkEmbeddingModelId(config2, providerIdentity) {
|
|
166630
|
+
if (config2.provider === "off") {
|
|
166631
|
+
return OFF_PROVIDER_IDENTITY;
|
|
166632
|
+
}
|
|
166633
|
+
const chunkIdentity = {
|
|
166634
|
+
providerIdentity,
|
|
166635
|
+
chunkerVersion: 1,
|
|
166636
|
+
maxInputTokens: normalizeCompartmentChunkMaxInputTokens("max_input_tokens" in config2 ? config2.max_input_tokens : undefined),
|
|
166637
|
+
truncate: config2.provider === "openai-compatible" ? config2.truncate ?? "" : ""
|
|
166638
|
+
};
|
|
166639
|
+
return `${providerIdentity}:chunk:${sha256Prefix(stableStringify2(chunkIdentity))}`;
|
|
166640
|
+
}
|
|
165437
166641
|
function sameFeatures(a, b) {
|
|
165438
166642
|
return a.memoryEnabled === b.memoryEnabled && a.gitCommitEnabled === b.gitCommitEnabled;
|
|
165439
166643
|
}
|
|
@@ -165450,7 +166654,8 @@ function snapshotFor(registration) {
|
|
|
165450
166654
|
features: { ...registration.features },
|
|
165451
166655
|
enabled,
|
|
165452
166656
|
gitCommitEnabled,
|
|
165453
|
-
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId
|
|
166657
|
+
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
|
|
166658
|
+
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId
|
|
165454
166659
|
};
|
|
165455
166660
|
}
|
|
165456
166661
|
function disposeProvider(provider) {
|
|
@@ -165470,7 +166675,7 @@ function anyStoredModelIdIsStale(storedIds, currentId) {
|
|
|
165470
166675
|
}
|
|
165471
166676
|
return false;
|
|
165472
166677
|
}
|
|
165473
|
-
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, features) {
|
|
166678
|
+
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, currentChunkIdentity, features) {
|
|
165474
166679
|
if (currentProviderIdentity === OFF_PROVIDER_IDENTITY) {
|
|
165475
166680
|
return false;
|
|
165476
166681
|
}
|
|
@@ -165491,6 +166696,14 @@ function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity,
|
|
|
165491
166696
|
wiped = true;
|
|
165492
166697
|
}
|
|
165493
166698
|
}
|
|
166699
|
+
if (features.memoryEnabled) {
|
|
166700
|
+
repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectIdentity);
|
|
166701
|
+
const chunkIds = getDistinctChunkEmbeddingModelIds(db, projectIdentity);
|
|
166702
|
+
if (anyStoredModelIdIsStale(chunkIds, currentChunkIdentity)) {
|
|
166703
|
+
clearChunkEmbeddingsForProject(db, projectIdentity);
|
|
166704
|
+
wiped = true;
|
|
166705
|
+
}
|
|
166706
|
+
}
|
|
165494
166707
|
})();
|
|
165495
166708
|
return wiped;
|
|
165496
166709
|
}
|
|
@@ -165498,10 +166711,11 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
165498
166711
|
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
165499
166712
|
const providerIdentity = getEmbeddingProviderIdentity(resolvedConfig);
|
|
165500
166713
|
const runtimeFingerprint = getRuntimeFingerprint(resolvedConfig);
|
|
166714
|
+
const chunkModelId = getChunkEmbeddingModelId(resolvedConfig, providerIdentity);
|
|
165501
166715
|
const prior = projectRegistrations.get(projectIdentity);
|
|
165502
166716
|
const canReuseProvider = prior !== undefined && !prior.observationMode && prior.runtimeFingerprint === runtimeFingerprint && prior.providerIdentity === providerIdentity;
|
|
165503
|
-
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, features);
|
|
165504
|
-
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || !sameFeatures(prior.features, features) || wiped;
|
|
166717
|
+
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, chunkModelId, features);
|
|
166718
|
+
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || prior.chunkModelId !== chunkModelId || !sameFeatures(prior.features, features) || wiped;
|
|
165505
166719
|
const generation = generationChanged ? ++globalRegistrationGeneration : prior.generation;
|
|
165506
166720
|
const registration = {
|
|
165507
166721
|
projectIdentity,
|
|
@@ -165513,6 +166727,7 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
165513
166727
|
generation,
|
|
165514
166728
|
features: { ...features },
|
|
165515
166729
|
modelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : providerIdentity,
|
|
166730
|
+
chunkModelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : chunkModelId,
|
|
165516
166731
|
observationMode: false
|
|
165517
166732
|
};
|
|
165518
166733
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -165535,6 +166750,7 @@ function registerProjectInObservationMode(db, projectIdentity, sourceDirectory,
|
|
|
165535
166750
|
generation,
|
|
165536
166751
|
features: { memoryEnabled: false, gitCommitEnabled: false },
|
|
165537
166752
|
modelId: "off",
|
|
166753
|
+
chunkModelId: "off",
|
|
165538
166754
|
observationMode: true
|
|
165539
166755
|
};
|
|
165540
166756
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -165545,6 +166761,15 @@ function getProjectEmbeddingSnapshot(projectIdentity) {
|
|
|
165545
166761
|
const registration = projectRegistrations.get(projectIdentity);
|
|
165546
166762
|
return registration ? snapshotFor(registration) : null;
|
|
165547
166763
|
}
|
|
166764
|
+
function getProjectChunkEmbeddingModelId(projectIdentity) {
|
|
166765
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
166766
|
+
return registration && !registration.observationMode ? registration.chunkModelId : "off";
|
|
166767
|
+
}
|
|
166768
|
+
function getProjectEmbeddingMaxInputTokens(projectIdentity) {
|
|
166769
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
166770
|
+
const configMax = registration?.config && "max_input_tokens" in registration.config ? registration.config.max_input_tokens : undefined;
|
|
166771
|
+
return normalizeCompartmentChunkMaxInputTokens(registration?.provider?.maxInputTokens ?? configMax);
|
|
166772
|
+
}
|
|
165548
166773
|
function getOrCreateProjectProvider(registration) {
|
|
165549
166774
|
if (registration.providerIdentity === OFF_PROVIDER_IDENTITY || registration.observationMode) {
|
|
165550
166775
|
return null;
|
|
@@ -165639,10 +166864,136 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
165639
166864
|
return 0;
|
|
165640
166865
|
}
|
|
165641
166866
|
}
|
|
165642
|
-
|
|
166867
|
+
async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal) {
|
|
166868
|
+
const noWork = [];
|
|
166869
|
+
if (candidates.length === 0)
|
|
166870
|
+
return { embedded: 0, noWork };
|
|
166871
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
|
|
166872
|
+
const prepared = [];
|
|
166873
|
+
for (const candidate of candidates) {
|
|
166874
|
+
const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
|
|
166875
|
+
if (canonicalText.length === 0) {
|
|
166876
|
+
noWork.push(candidate.id);
|
|
166877
|
+
continue;
|
|
166878
|
+
}
|
|
166879
|
+
const windows = chunkCanonicalText(canonicalText, candidate.startMessage, candidate.endMessage, maxInputTokens);
|
|
166880
|
+
if (windows.length === 0 || chunkEmbeddingWindowsAreCurrent(db, candidate.id, modelId, windows, projectIdentity)) {
|
|
166881
|
+
noWork.push(candidate.id);
|
|
166882
|
+
continue;
|
|
166883
|
+
}
|
|
166884
|
+
prepared.push({ candidate, windows });
|
|
166885
|
+
}
|
|
166886
|
+
if (prepared.length === 0)
|
|
166887
|
+
return { embedded: 0, noWork };
|
|
166888
|
+
let embedded = 0;
|
|
166889
|
+
let i = 0;
|
|
166890
|
+
while (i < prepared.length) {
|
|
166891
|
+
if (signal?.aborted)
|
|
166892
|
+
break;
|
|
166893
|
+
const slice = [];
|
|
166894
|
+
let windowCount = 0;
|
|
166895
|
+
do {
|
|
166896
|
+
const item = prepared[i];
|
|
166897
|
+
slice.push(item);
|
|
166898
|
+
windowCount += item.windows.length;
|
|
166899
|
+
i += 1;
|
|
166900
|
+
} while (i < prepared.length && windowCount + prepared[i].windows.length <= MAX_WINDOWS_PER_EMBED_CALL);
|
|
166901
|
+
const texts = [];
|
|
166902
|
+
for (const item of slice)
|
|
166903
|
+
texts.push(...item.windows.map((w) => w.text));
|
|
166904
|
+
try {
|
|
166905
|
+
const result = await embedBatchForProject(projectIdentity, texts, signal);
|
|
166906
|
+
if (!result)
|
|
166907
|
+
continue;
|
|
166908
|
+
if (signal?.aborted)
|
|
166909
|
+
break;
|
|
166910
|
+
let offset = 0;
|
|
166911
|
+
for (const item of slice) {
|
|
166912
|
+
const vectors = result.vectors.slice(offset, offset + item.windows.length);
|
|
166913
|
+
offset += item.windows.length;
|
|
166914
|
+
if (vectors.length !== item.windows.length || vectors.some((v) => !v)) {
|
|
166915
|
+
continue;
|
|
166916
|
+
}
|
|
166917
|
+
const rows = item.windows.map((window, index) => ({
|
|
166918
|
+
compartmentId: item.candidate.id,
|
|
166919
|
+
sessionId: item.candidate.sessionId,
|
|
166920
|
+
projectPath: projectIdentity,
|
|
166921
|
+
window,
|
|
166922
|
+
modelId,
|
|
166923
|
+
vector: vectors[index]
|
|
166924
|
+
}));
|
|
166925
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
166926
|
+
embedded += 1;
|
|
166927
|
+
}
|
|
166928
|
+
} catch (error51) {
|
|
166929
|
+
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
166930
|
+
}
|
|
166931
|
+
}
|
|
166932
|
+
return { embedded, noWork };
|
|
166933
|
+
}
|
|
166934
|
+
async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, options) {
|
|
166935
|
+
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
166936
|
+
if (!snapshot?.enabled || snapshot.chunkModelId === "off") {
|
|
166937
|
+
return { status: "disabled", embedded: 0, total: 0 };
|
|
166938
|
+
}
|
|
166939
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
166940
|
+
const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId);
|
|
166941
|
+
if (total === 0)
|
|
166942
|
+
return { status: "nothing", embedded: 0, total: 0 };
|
|
166943
|
+
const holderId = `session-embed-${randomUUID()}`;
|
|
166944
|
+
const lease2 = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
|
|
166945
|
+
if (!lease2.acquired)
|
|
166946
|
+
return { status: "busy", embedded: 0, total };
|
|
166947
|
+
const renewal = setInterval(() => {
|
|
166948
|
+
try {
|
|
166949
|
+
renewGitSweepLease(db, projectIdentity, holderId);
|
|
166950
|
+
} catch {}
|
|
166951
|
+
}, SESSION_EMBED_LEASE_RENEWAL_MS);
|
|
166952
|
+
renewal.unref?.();
|
|
166953
|
+
const batchSize = Math.max(1, options?.batchSize ?? CHUNK_DRAIN_BATCH_SIZE);
|
|
166954
|
+
const skipIds = [];
|
|
166955
|
+
let embedded = 0;
|
|
166956
|
+
let aborted2 = false;
|
|
166957
|
+
let providerStalled = false;
|
|
166958
|
+
try {
|
|
166959
|
+
options?.onProgress?.({ embedded, total });
|
|
166960
|
+
for (;; ) {
|
|
166961
|
+
if (options?.signal?.aborted) {
|
|
166962
|
+
aborted2 = true;
|
|
166963
|
+
break;
|
|
166964
|
+
}
|
|
166965
|
+
const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, skipIds);
|
|
166966
|
+
if (candidates.length === 0)
|
|
166967
|
+
break;
|
|
166968
|
+
const { embedded: n, noWork } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, options?.signal);
|
|
166969
|
+
for (const id of noWork)
|
|
166970
|
+
skipIds.push(id);
|
|
166971
|
+
if (n === 0 && noWork.length === 0) {
|
|
166972
|
+
providerStalled = true;
|
|
166973
|
+
break;
|
|
166974
|
+
}
|
|
166975
|
+
embedded += n;
|
|
166976
|
+
options?.onProgress?.({ embedded: Math.min(embedded, total), total });
|
|
166977
|
+
await new Promise((resolve6) => setTimeout(resolve6, 0));
|
|
166978
|
+
}
|
|
166979
|
+
} finally {
|
|
166980
|
+
clearInterval(renewal);
|
|
166981
|
+
releaseGitSweepLease(db, projectIdentity, holderId);
|
|
166982
|
+
}
|
|
166983
|
+
if (aborted2)
|
|
166984
|
+
return { status: "aborted", embedded, total };
|
|
166985
|
+
if (providerStalled) {
|
|
166986
|
+
const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId) - skipIds.length);
|
|
166987
|
+
if (remaining > 0)
|
|
166988
|
+
return { status: "stalled", embedded, total, remaining };
|
|
166989
|
+
}
|
|
166990
|
+
return { status: "done", embedded, total };
|
|
166991
|
+
}
|
|
166992
|
+
var OFF_PROVIDER_IDENTITY = "embedding-provider:off", SWEEP_MAX_WALL_CLOCK_MS, CHUNK_DRAIN_BATCH_SIZE = 8, MAX_WINDOWS_PER_EMBED_CALL = 16, SESSION_EMBED_LEASE_RENEWAL_MS, projectRegistrations, loadUnembeddedMemoriesStatements, globalRegistrationGeneration = 0, testProviderFactory = null;
|
|
165643
166993
|
var init_project_embedding_registry = __esm(() => {
|
|
165644
166994
|
init_magic_context();
|
|
165645
166995
|
init_logger();
|
|
166996
|
+
init_compartment_chunk_embedding();
|
|
165646
166997
|
init_storage_git_commit_embeddings();
|
|
165647
166998
|
init_sweep_coordinator();
|
|
165648
166999
|
init_embedding_cache();
|
|
@@ -165650,7 +167001,9 @@ var init_project_embedding_registry = __esm(() => {
|
|
|
165650
167001
|
init_embedding_local();
|
|
165651
167002
|
init_embedding_openai();
|
|
165652
167003
|
init_storage_memory_embeddings();
|
|
167004
|
+
init_session_project_storage();
|
|
165653
167005
|
SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
167006
|
+
SESSION_EMBED_LEASE_RENEWAL_MS = 60 * 1000;
|
|
165654
167007
|
projectRegistrations = new Map;
|
|
165655
167008
|
loadUnembeddedMemoriesStatements = new WeakMap;
|
|
165656
167009
|
});
|
|
@@ -165666,10 +167019,11 @@ function createProvider2(config2) {
|
|
|
165666
167019
|
model: config2.model,
|
|
165667
167020
|
apiKey: config2.api_key,
|
|
165668
167021
|
inputType: config2.input_type,
|
|
165669
|
-
truncate: config2.truncate
|
|
167022
|
+
truncate: config2.truncate,
|
|
167023
|
+
maxInputTokens: config2.max_input_tokens
|
|
165670
167024
|
});
|
|
165671
167025
|
}
|
|
165672
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
167026
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
165673
167027
|
}
|
|
165674
167028
|
function getOrCreateProvider() {
|
|
165675
167029
|
if (provider) {
|
|
@@ -165695,6 +167049,7 @@ var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMe
|
|
|
165695
167049
|
var init_embedding = __esm(() => {
|
|
165696
167050
|
init_magic_context();
|
|
165697
167051
|
init_logger();
|
|
167052
|
+
init_compartment_chunk_embedding();
|
|
165698
167053
|
init_embedding_identity();
|
|
165699
167054
|
init_embedding_local();
|
|
165700
167055
|
init_embedding_openai();
|
|
@@ -165718,6 +167073,23 @@ function getSearchStatement(db) {
|
|
|
165718
167073
|
}
|
|
165719
167074
|
return stmt;
|
|
165720
167075
|
}
|
|
167076
|
+
function getUnionSearchStatement(db, arity) {
|
|
167077
|
+
let statements = unionSearchStatements.get(arity);
|
|
167078
|
+
if (!statements) {
|
|
167079
|
+
statements = new WeakMap;
|
|
167080
|
+
unionSearchStatements.set(arity, statements);
|
|
167081
|
+
}
|
|
167082
|
+
let stmt = statements.get(db);
|
|
167083
|
+
if (!stmt) {
|
|
167084
|
+
const placeholders3 = Array.from({ length: arity }, () => "?").join(", ");
|
|
167085
|
+
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 ?`);
|
|
167086
|
+
statements.set(db, stmt);
|
|
167087
|
+
}
|
|
167088
|
+
return stmt;
|
|
167089
|
+
}
|
|
167090
|
+
function uniqueProjectPaths2(projectPaths) {
|
|
167091
|
+
return [...new Set(projectPaths.filter((path6) => path6.length > 0))];
|
|
167092
|
+
}
|
|
165721
167093
|
function sanitizeFtsQuery(query) {
|
|
165722
167094
|
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
165723
167095
|
if (tokens.length === 0)
|
|
@@ -165736,10 +167108,33 @@ function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT)
|
|
|
165736
167108
|
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
165737
167109
|
return rows.map(toMemory);
|
|
165738
167110
|
}
|
|
165739
|
-
|
|
167111
|
+
function searchMemoriesFTSUnion(db, projectPaths, query, limit = DEFAULT_SEARCH_LIMIT, ownIdentities, shareCategories) {
|
|
167112
|
+
const identities = uniqueProjectPaths2(projectPaths);
|
|
167113
|
+
if (identities.length === 0)
|
|
167114
|
+
return [];
|
|
167115
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
167116
|
+
identities,
|
|
167117
|
+
ownIdentities,
|
|
167118
|
+
shareCategories,
|
|
167119
|
+
tableName: "memories"
|
|
167120
|
+
});
|
|
167121
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
167122
|
+
return searchMemoriesFTS(db, identities[0], query, limit);
|
|
167123
|
+
}
|
|
167124
|
+
const trimmedQuery = query.trim();
|
|
167125
|
+
if (trimmedQuery.length === 0 || limit <= 0)
|
|
167126
|
+
return [];
|
|
167127
|
+
const sanitized = sanitizeFtsQuery(trimmedQuery);
|
|
167128
|
+
if (sanitized.length === 0)
|
|
167129
|
+
return [];
|
|
167130
|
+
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);
|
|
167131
|
+
return rows.map(toMemory);
|
|
167132
|
+
}
|
|
167133
|
+
var DEFAULT_SEARCH_LIMIT = 10, searchStatements, unionSearchStatements;
|
|
165740
167134
|
var init_storage_memory_fts = __esm(() => {
|
|
165741
167135
|
init_storage_memory();
|
|
165742
167136
|
searchStatements = new WeakMap;
|
|
167137
|
+
unionSearchStatements = new Map;
|
|
165743
167138
|
});
|
|
165744
167139
|
|
|
165745
167140
|
// src/shared/models-dev-cache.ts
|
|
@@ -165933,26 +167328,54 @@ var init_rpc_notifications = __esm(() => {
|
|
|
165933
167328
|
});
|
|
165934
167329
|
|
|
165935
167330
|
// src/features/magic-context/compartment-embedding.ts
|
|
165936
|
-
async function
|
|
167331
|
+
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
165937
167332
|
if (compartments.length === 0)
|
|
165938
167333
|
return;
|
|
165939
|
-
const
|
|
165940
|
-
for (const
|
|
165941
|
-
if (!c.p1 || c.p1.length === 0)
|
|
165942
|
-
continue;
|
|
167334
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
167335
|
+
for (const compartment of compartments) {
|
|
165943
167336
|
try {
|
|
165944
|
-
const
|
|
165945
|
-
|
|
165946
|
-
|
|
165947
|
-
|
|
167337
|
+
const fromMemory = compartment.sourceChunkText ? canonicalizeInMemoryChunkTextForEmbedding(compartment.sourceChunkText, compartment.startMessage, compartment.endMessage) : "";
|
|
167338
|
+
const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage);
|
|
167339
|
+
if (canonicalText.length === 0)
|
|
167340
|
+
continue;
|
|
167341
|
+
const windows = chunkCanonicalText(canonicalText, compartment.startMessage, compartment.endMessage, maxInputTokens);
|
|
167342
|
+
if (windows.length === 0)
|
|
167343
|
+
continue;
|
|
167344
|
+
const currentModelId = getProjectChunkEmbeddingModelId(projectPath);
|
|
167345
|
+
if (currentModelId !== "off" && chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
167346
|
+
continue;
|
|
167347
|
+
}
|
|
167348
|
+
const result = await embedBatchForProject(projectPath, windows.map((window) => window.text));
|
|
167349
|
+
if (!result)
|
|
167350
|
+
continue;
|
|
167351
|
+
if (chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
167352
|
+
continue;
|
|
167353
|
+
}
|
|
167354
|
+
const rows = [];
|
|
167355
|
+
for (const [index, window] of windows.entries()) {
|
|
167356
|
+
const vector = result.vectors[index];
|
|
167357
|
+
if (!vector)
|
|
167358
|
+
continue;
|
|
167359
|
+
rows.push({
|
|
167360
|
+
compartmentId: compartment.id,
|
|
167361
|
+
sessionId,
|
|
167362
|
+
projectPath,
|
|
167363
|
+
window,
|
|
167364
|
+
modelId: currentModelId,
|
|
167365
|
+
vector
|
|
167366
|
+
});
|
|
167367
|
+
}
|
|
167368
|
+
if (rows.length === windows.length) {
|
|
167369
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
165948
167370
|
}
|
|
165949
167371
|
} catch (error51) {
|
|
165950
|
-
sessionLog(sessionId, `compartment embedding failed for compartment ${
|
|
167372
|
+
sessionLog(sessionId, `compartment chunk embedding failed for compartment ${compartment.id}:`, error51);
|
|
165951
167373
|
}
|
|
165952
167374
|
}
|
|
165953
167375
|
}
|
|
165954
167376
|
var init_compartment_embedding = __esm(() => {
|
|
165955
167377
|
init_logger();
|
|
167378
|
+
init_compartment_chunk_embedding();
|
|
165956
167379
|
init_project_embedding_registry();
|
|
165957
167380
|
});
|
|
165958
167381
|
|
|
@@ -167066,55 +168489,6 @@ var init_historian_state_file = __esm(() => {
|
|
|
167066
168489
|
init_data_path();
|
|
167067
168490
|
});
|
|
167068
168491
|
|
|
167069
|
-
// src/features/magic-context/memory/constants.ts
|
|
167070
|
-
var V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
167071
|
-
var init_constants = __esm(() => {
|
|
167072
|
-
V2_MEMORY_CATEGORIES = [
|
|
167073
|
-
"PROJECT_RULES",
|
|
167074
|
-
"ARCHITECTURE",
|
|
167075
|
-
"CONSTRAINTS",
|
|
167076
|
-
"CONFIG_VALUES",
|
|
167077
|
-
"NAMING"
|
|
167078
|
-
];
|
|
167079
|
-
PROMOTABLE_CATEGORIES = [
|
|
167080
|
-
"PROJECT_RULES",
|
|
167081
|
-
"ARCHITECTURE",
|
|
167082
|
-
"CONSTRAINTS",
|
|
167083
|
-
"CONFIG_VALUES",
|
|
167084
|
-
"NAMING",
|
|
167085
|
-
"ARCHITECTURE_DECISIONS",
|
|
167086
|
-
"CONFIG_DEFAULTS",
|
|
167087
|
-
"USER_PREFERENCES",
|
|
167088
|
-
"USER_DIRECTIVES",
|
|
167089
|
-
"ENVIRONMENT",
|
|
167090
|
-
"WORKFLOW_RULES",
|
|
167091
|
-
"KNOWN_ISSUES"
|
|
167092
|
-
];
|
|
167093
|
-
CATEGORY_PRIORITY = [
|
|
167094
|
-
"PROJECT_RULES",
|
|
167095
|
-
"ARCHITECTURE",
|
|
167096
|
-
"CONSTRAINTS",
|
|
167097
|
-
"CONFIG_VALUES",
|
|
167098
|
-
"NAMING",
|
|
167099
|
-
"USER_DIRECTIVES",
|
|
167100
|
-
"USER_PREFERENCES",
|
|
167101
|
-
"CONFIG_DEFAULTS",
|
|
167102
|
-
"ARCHITECTURE_DECISIONS",
|
|
167103
|
-
"ENVIRONMENT",
|
|
167104
|
-
"WORKFLOW_RULES",
|
|
167105
|
-
"KNOWN_ISSUES"
|
|
167106
|
-
];
|
|
167107
|
-
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
167108
|
-
acc[category] = index;
|
|
167109
|
-
return acc;
|
|
167110
|
-
}, {});
|
|
167111
|
-
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
167112
|
-
CATEGORY_DEFAULT_TTL = {
|
|
167113
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
167114
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
167115
|
-
};
|
|
167116
|
-
});
|
|
167117
|
-
|
|
167118
168492
|
// src/features/magic-context/memory/embedding-backfill.ts
|
|
167119
168493
|
async function ensureMemoryEmbeddings(args) {
|
|
167120
168494
|
const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -167138,7 +168512,7 @@ async function ensureMemoryEmbeddings(args) {
|
|
|
167138
168512
|
continue;
|
|
167139
168513
|
}
|
|
167140
168514
|
saveEmbedding(args.db, memory.id, embedding, result.modelId);
|
|
167141
|
-
staged.set(memory.id, embedding);
|
|
168515
|
+
staged.set(memory.id, { embedding, modelId: result.modelId });
|
|
167142
168516
|
}
|
|
167143
168517
|
})();
|
|
167144
168518
|
const currentSnapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -167935,6 +169309,71 @@ function lastCompartmentBoundaryId(compartments) {
|
|
|
167935
169309
|
const last = compartments.at(-1);
|
|
167936
169310
|
return last?.endMessageId && last.endMessageId.length > 0 ? last.endMessageId : null;
|
|
167937
169311
|
}
|
|
169312
|
+
function resolveWorkspaceRenderContext(args) {
|
|
169313
|
+
if (!args.projectPath) {
|
|
169314
|
+
return {
|
|
169315
|
+
identities: [],
|
|
169316
|
+
expandedIdentities: [],
|
|
169317
|
+
ownIdentities: [],
|
|
169318
|
+
shareCategories: null,
|
|
169319
|
+
namesByIdentity: new Map,
|
|
169320
|
+
canonicalIdentityByStoredPath: new Map,
|
|
169321
|
+
isWorkspaced: false
|
|
169322
|
+
};
|
|
169323
|
+
}
|
|
169324
|
+
const identitySet = args.workspaceIdentitySet ?? resolveWorkspaceIdentitySet(args.db, args.projectPath);
|
|
169325
|
+
const isWorkspaced = identitySet.identities.length > 1;
|
|
169326
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(args.db, identitySet.identities);
|
|
169327
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : identitySet.identities;
|
|
169328
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(identitySet.identities.map((identity) => [identity, identity]));
|
|
169329
|
+
let ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === args.projectPath);
|
|
169330
|
+
if (ownIdentities.length === 0 && expandedIdentities.includes(args.projectPath)) {
|
|
169331
|
+
ownIdentities = [args.projectPath];
|
|
169332
|
+
}
|
|
169333
|
+
return {
|
|
169334
|
+
identities: identitySet.identities,
|
|
169335
|
+
expandedIdentities,
|
|
169336
|
+
ownIdentities,
|
|
169337
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(args.db, args.projectPath) : null,
|
|
169338
|
+
namesByIdentity: identitySet.namesByIdentity,
|
|
169339
|
+
canonicalIdentityByStoredPath,
|
|
169340
|
+
isWorkspaced
|
|
169341
|
+
};
|
|
169342
|
+
}
|
|
169343
|
+
function sourceNamesForMemories(args) {
|
|
169344
|
+
if (!args.projectPath || !args.workspace.isWorkspaced)
|
|
169345
|
+
return;
|
|
169346
|
+
const names = new Map;
|
|
169347
|
+
for (const memory of args.memories) {
|
|
169348
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
169349
|
+
if (source)
|
|
169350
|
+
names.set(memory.id, source);
|
|
169351
|
+
}
|
|
169352
|
+
return names.size > 0 ? names : undefined;
|
|
169353
|
+
}
|
|
169354
|
+
function memoryCanonicalIdentity(memory, workspace) {
|
|
169355
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
169356
|
+
}
|
|
169357
|
+
function memorySelectionOrder(left, right) {
|
|
169358
|
+
if (left.status === "permanent" && right.status !== "permanent")
|
|
169359
|
+
return -1;
|
|
169360
|
+
if (right.status === "permanent" && left.status !== "permanent")
|
|
169361
|
+
return 1;
|
|
169362
|
+
const leftImportance = left.importance ?? Number.NEGATIVE_INFINITY;
|
|
169363
|
+
const rightImportance = right.importance ?? Number.NEGATIVE_INFINITY;
|
|
169364
|
+
const importanceDiff = rightImportance - leftImportance;
|
|
169365
|
+
if (importanceDiff !== 0)
|
|
169366
|
+
return importanceDiff;
|
|
169367
|
+
return left.id - right.id;
|
|
169368
|
+
}
|
|
169369
|
+
function memoryRenderOrder(left, right) {
|
|
169370
|
+
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[left.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
169371
|
+
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[right.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
169372
|
+
const categoryDiff = aPriority - bPriority;
|
|
169373
|
+
if (categoryDiff !== 0)
|
|
169374
|
+
return categoryDiff;
|
|
169375
|
+
return left.id - right.id;
|
|
169376
|
+
}
|
|
167938
169377
|
function cachedStatement(cache, db, sql) {
|
|
167939
169378
|
let stmt = cache.get(db);
|
|
167940
169379
|
if (!stmt) {
|
|
@@ -167977,19 +169416,24 @@ function getGlobalUserProfileVersion(db) {
|
|
|
167977
169416
|
function readCurrentM0SnapshotMarkers(args) {
|
|
167978
169417
|
const projectDirectory = args.projectDirectory ?? args.projectPath ?? "";
|
|
167979
169418
|
const hard = args.hardSignals ?? EMPTY_HARD_SIGNALS;
|
|
169419
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
169420
|
+
db: args.db,
|
|
169421
|
+
projectPath: args.projectPath,
|
|
169422
|
+
workspaceIdentitySet: args.workspaceIdentitySet
|
|
169423
|
+
});
|
|
167980
169424
|
return {
|
|
167981
169425
|
projectMemoryEpoch: getProjectMemoryEpoch(args.db, args.projectPath),
|
|
169426
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(args.db, workspace.identities) : null,
|
|
167982
169427
|
projectUserProfileVersion: getGlobalUserProfileVersion(args.db),
|
|
167983
169428
|
maxCompartmentSeq: getMaxCompartmentSeq(args.db, args.sessionId),
|
|
167984
|
-
maxMemoryId: getMaxMemoryId(args.db, args.projectPath),
|
|
169429
|
+
maxMemoryId: workspace.isWorkspaced ? getMaxMemoryIdForProjects(args.db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryId(args.db, args.projectPath),
|
|
167985
169430
|
maxMutationId: getMaxM0MutationId(args.db, args.sessionId) ?? 0,
|
|
167986
|
-
maxMemoryMutationId: args.projectPath ? getMaxMemoryMutationId(args.db, args.projectPath) ?? 0 : 0,
|
|
169431
|
+
maxMemoryMutationId: workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(args.db, workspace.expandedIdentities) ?? 0 : args.projectPath ? getMaxMemoryMutationId(args.db, args.projectPath) ?? 0 : 0,
|
|
167987
169432
|
projectDocsHash: projectDirectory ? computeProjectDocsHash(projectDirectory) : "",
|
|
167988
169433
|
materializedAt: Date.now(),
|
|
167989
169434
|
sessionFactsVersion: getSessionFactsVersion(args.db, args.sessionId),
|
|
167990
169435
|
upgradeState: getUpgradeState(args.db, args.sessionId),
|
|
167991
169436
|
systemHash: hard.systemHash,
|
|
167992
|
-
toolSetHash: hard.toolSetHash,
|
|
167993
169437
|
modelKey: hard.modelKey
|
|
167994
169438
|
};
|
|
167995
169439
|
}
|
|
@@ -168012,6 +169456,7 @@ function snapshotMarkersFromCachedM0(state) {
|
|
|
168012
169456
|
return null;
|
|
168013
169457
|
return {
|
|
168014
169458
|
projectMemoryEpoch: state.cachedM0ProjectMemoryEpoch,
|
|
169459
|
+
workspaceFingerprint: state.cachedM0WorkspaceFingerprint,
|
|
168015
169460
|
projectUserProfileVersion: state.cachedM0ProjectUserProfileVersion,
|
|
168016
169461
|
maxCompartmentSeq: state.cachedM0MaxCompartmentSeq,
|
|
168017
169462
|
maxMemoryId: state.cachedM0MaxMemoryId,
|
|
@@ -168022,7 +169467,6 @@ function snapshotMarkersFromCachedM0(state) {
|
|
|
168022
169467
|
sessionFactsVersion: state.cachedM0SessionFactsVersion,
|
|
168023
169468
|
upgradeState: state.cachedM0UpgradeState,
|
|
168024
169469
|
systemHash: state.cachedM0SystemHash ?? "",
|
|
168025
|
-
toolSetHash: state.cachedM0ToolSetHash ?? "",
|
|
168026
169470
|
modelKey: state.cachedM0ModelKey ?? ""
|
|
168027
169471
|
};
|
|
168028
169472
|
}
|
|
@@ -168039,41 +169483,30 @@ function mustMaterialize(args) {
|
|
|
168039
169483
|
if (hard.systemHash !== "" && hard.systemHash !== (args.state.cachedM0SystemHash ?? "")) {
|
|
168040
169484
|
return { value: true, reason: "system_hash" };
|
|
168041
169485
|
}
|
|
168042
|
-
if (hard.toolSetHash !== "" && hard.toolSetHash !== (args.state.cachedM0ToolSetHash ?? "")) {
|
|
168043
|
-
return { value: true, reason: "tool_set_hash" };
|
|
168044
|
-
}
|
|
168045
169486
|
if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (args.state.cachedM0MaterializedAt ?? 0)) {
|
|
168046
169487
|
return { value: true, reason: "ttl_idle" };
|
|
168047
169488
|
}
|
|
168048
|
-
if (args.state.
|
|
169489
|
+
if (current.workspaceFingerprint !== null || (args.state.cachedM0WorkspaceFingerprint ?? null) !== null) {
|
|
169490
|
+
if ((args.state.cachedM0WorkspaceFingerprint ?? null) !== current.workspaceFingerprint) {
|
|
169491
|
+
return { value: true, reason: "project_memory_epoch" };
|
|
169492
|
+
}
|
|
169493
|
+
} else if (args.state.cachedM0ProjectMemoryEpoch !== current.projectMemoryEpoch) {
|
|
168049
169494
|
return { value: true, reason: "project_memory_epoch" };
|
|
168050
169495
|
}
|
|
168051
169496
|
if (args.state.cachedM0MaxMutationId !== current.maxMutationId) {
|
|
168052
169497
|
return { value: true, reason: "max_mutation_id" };
|
|
168053
169498
|
}
|
|
168054
|
-
if ((args.state.cachedM0ProjectDocsHash ?? "") !== current.projectDocsHash) {
|
|
168055
|
-
return { value: true, reason: "project_docs_hash" };
|
|
168056
|
-
}
|
|
168057
169499
|
if ((args.state.cachedM0UpgradeState ?? null) !== current.upgradeState) {
|
|
168058
169500
|
return { value: true, reason: "upgrade_state" };
|
|
168059
169501
|
}
|
|
168060
169502
|
return { value: false, reason: null };
|
|
168061
169503
|
}
|
|
168062
|
-
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
168063
|
-
const selectionOrder = [...memories].sort(
|
|
168064
|
-
if (a.status === "permanent" && b.status !== "permanent")
|
|
168065
|
-
return -1;
|
|
168066
|
-
if (b.status === "permanent" && a.status !== "permanent")
|
|
168067
|
-
return 1;
|
|
168068
|
-
const importanceDiff = (b.importance ?? 50) - (a.importance ?? 50);
|
|
168069
|
-
if (importanceDiff !== 0)
|
|
168070
|
-
return importanceDiff;
|
|
168071
|
-
return a.id - b.id;
|
|
168072
|
-
});
|
|
169504
|
+
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions = {}) {
|
|
169505
|
+
const selectionOrder = [...memories].sort(memorySelectionOrder);
|
|
168073
169506
|
const selected = [];
|
|
168074
169507
|
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
168075
169508
|
for (const memory of selectionOrder) {
|
|
168076
|
-
const memoryTokens = estimateTokens(renderMemoryLineV2(memory));
|
|
169509
|
+
const memoryTokens = estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
168077
169510
|
if (usedTokens + memoryTokens > budgetTokens)
|
|
168078
169511
|
continue;
|
|
168079
169512
|
selected.push(memory);
|
|
@@ -168082,16 +169515,70 @@ function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
|
168082
169515
|
if (selected.length < memories.length) {
|
|
168083
169516
|
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
168084
169517
|
}
|
|
168085
|
-
const renderOrder = [...selected].sort(
|
|
168086
|
-
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[a.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
168087
|
-
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[b.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
168088
|
-
const categoryDiff = aPriority - bPriority;
|
|
168089
|
-
if (categoryDiff !== 0)
|
|
168090
|
-
return categoryDiff;
|
|
168091
|
-
return a.id - b.id;
|
|
168092
|
-
});
|
|
169518
|
+
const renderOrder = [...selected].sort(memoryRenderOrder);
|
|
168093
169519
|
return { selected, renderOrder };
|
|
168094
169520
|
}
|
|
169521
|
+
function trimWorkspaceMemoriesToBudgetV2(sessionId, memories, budgetTokens, workspace, renderOptions = {}) {
|
|
169522
|
+
if (!workspace.isWorkspaced) {
|
|
169523
|
+
return trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions);
|
|
169524
|
+
}
|
|
169525
|
+
const selected = [];
|
|
169526
|
+
const selectedIds = new Set;
|
|
169527
|
+
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
169528
|
+
const tokenCost = (memory) => estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
169529
|
+
const trySelect = (memory) => {
|
|
169530
|
+
if (selectedIds.has(memory.id))
|
|
169531
|
+
return false;
|
|
169532
|
+
const tokens = tokenCost(memory);
|
|
169533
|
+
if (usedTokens + tokens > budgetTokens)
|
|
169534
|
+
return false;
|
|
169535
|
+
selected.push(memory);
|
|
169536
|
+
selectedIds.add(memory.id);
|
|
169537
|
+
usedTokens += tokens;
|
|
169538
|
+
return true;
|
|
169539
|
+
};
|
|
169540
|
+
for (const memory of memories.filter((candidate) => candidate.status === "permanent").sort(memorySelectionOrder)) {
|
|
169541
|
+
trySelect(memory);
|
|
169542
|
+
}
|
|
169543
|
+
const remainingAfterPermanent = Math.max(0, budgetTokens - usedTokens);
|
|
169544
|
+
const floorTokens = remainingAfterPermanent / Math.max(1, workspace.identities.length);
|
|
169545
|
+
const byIdentity = new Map;
|
|
169546
|
+
for (const memory of memories) {
|
|
169547
|
+
if (memory.status === "permanent")
|
|
169548
|
+
continue;
|
|
169549
|
+
const identity = memoryCanonicalIdentity(memory, workspace);
|
|
169550
|
+
if (!identity)
|
|
169551
|
+
continue;
|
|
169552
|
+
const list = byIdentity.get(identity) ?? [];
|
|
169553
|
+
list.push(memory);
|
|
169554
|
+
byIdentity.set(identity, list);
|
|
169555
|
+
}
|
|
169556
|
+
for (const identity of workspace.identities) {
|
|
169557
|
+
let memberTokens = 0;
|
|
169558
|
+
const candidates = (byIdentity.get(identity) ?? []).sort(memorySelectionOrder);
|
|
169559
|
+
for (const memory of candidates) {
|
|
169560
|
+
if (selectedIds.has(memory.id))
|
|
169561
|
+
continue;
|
|
169562
|
+
const tokens = tokenCost(memory);
|
|
169563
|
+
if (memberTokens + tokens > floorTokens)
|
|
169564
|
+
continue;
|
|
169565
|
+
if (usedTokens + tokens > budgetTokens)
|
|
169566
|
+
continue;
|
|
169567
|
+
selected.push(memory);
|
|
169568
|
+
selectedIds.add(memory.id);
|
|
169569
|
+
usedTokens += tokens;
|
|
169570
|
+
memberTokens += tokens;
|
|
169571
|
+
}
|
|
169572
|
+
}
|
|
169573
|
+
const remaining = memories.filter((memory) => !selectedIds.has(memory.id)).sort(memorySelectionOrder);
|
|
169574
|
+
for (const memory of remaining) {
|
|
169575
|
+
trySelect(memory);
|
|
169576
|
+
}
|
|
169577
|
+
if (selected.length < memories.length) {
|
|
169578
|
+
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
169579
|
+
}
|
|
169580
|
+
return { selected, renderOrder: [...selected].sort(memoryRenderOrder) };
|
|
169581
|
+
}
|
|
168095
169582
|
function safeGetActiveUserMemories(db) {
|
|
168096
169583
|
try {
|
|
168097
169584
|
return getActiveUserMemories(db);
|
|
@@ -168167,15 +169654,16 @@ function readNewMemoriesForM1(db, projectPath, afterId, expiryCutoff) {
|
|
|
168167
169654
|
ORDER BY ${MEMORY_CATEGORY_ORDER_SQL}, id ASC`).all(projectPath, afterId, expiryCutoff).filter(isMemoryRow);
|
|
168168
169655
|
return rows.map((row) => ({ ...row }));
|
|
168169
169656
|
}
|
|
168170
|
-
function renderMemoryLineV2(memory) {
|
|
168171
|
-
|
|
169657
|
+
function renderMemoryLineV2(memory, sourceName) {
|
|
169658
|
+
const sourceAttr = sourceName ? ` source="${escapeXmlAttr(sourceName)}"` : "";
|
|
169659
|
+
return ` <memory id="${memory.id}" category="${escapeXmlAttr(memory.category)}"${sourceAttr} importance="${memory.importance ?? 50}">${escapeXmlContent(memory.content)}</memory>`;
|
|
168172
169660
|
}
|
|
168173
|
-
function renderMemoryBlockV2(memories, wrapper = "project-memory") {
|
|
169661
|
+
function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions = {}) {
|
|
168174
169662
|
if (memories.length === 0)
|
|
168175
169663
|
return "";
|
|
168176
169664
|
const lines = [`<${wrapper}>`];
|
|
168177
169665
|
for (const memory of memories) {
|
|
168178
|
-
lines.push(renderMemoryLineV2(memory));
|
|
169666
|
+
lines.push(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
168179
169667
|
}
|
|
168180
169668
|
lines.push(`</${wrapper}>`);
|
|
168181
169669
|
return lines.join(`
|
|
@@ -168214,7 +169702,7 @@ function renderM0(args) {
|
|
|
168214
169702
|
sections.push(sessionHistory.length > 0 ? `<session-history>
|
|
168215
169703
|
${sessionHistory}
|
|
168216
169704
|
</session-history>` : M0_EMPTY_BODY);
|
|
168217
|
-
const memoriesBlock = renderMemoryBlockV2(args.memories);
|
|
169705
|
+
const memoriesBlock = renderMemoryBlockV2(args.memories, "project-memory", args.memoryRenderOptions);
|
|
168218
169706
|
if (memoriesBlock)
|
|
168219
169707
|
sections.push(memoriesBlock);
|
|
168220
169708
|
return sections.join(`
|
|
@@ -168226,6 +169714,7 @@ function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
|
|
|
168226
169714
|
if (m1Bytes)
|
|
168227
169715
|
state.cachedM1Bytes = m1Bytes;
|
|
168228
169716
|
state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
|
|
169717
|
+
state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
|
|
168229
169718
|
state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
|
|
168230
169719
|
state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
|
|
168231
169720
|
state.cachedM0MaxMemoryId = markers.maxMemoryId;
|
|
@@ -168236,7 +169725,6 @@ function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
|
|
|
168236
169725
|
state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
|
|
168237
169726
|
state.cachedM0UpgradeState = markers.upgradeState;
|
|
168238
169727
|
state.cachedM0SystemHash = markers.systemHash;
|
|
168239
|
-
state.cachedM0ToolSetHash = markers.toolSetHash;
|
|
168240
169728
|
state.cachedM0ModelKey = markers.modelKey;
|
|
168241
169729
|
state.snapshotMarkers = markers;
|
|
168242
169730
|
}
|
|
@@ -168252,24 +169740,38 @@ function materializeM0(options) {
|
|
|
168252
169740
|
let facts = [];
|
|
168253
169741
|
let memories = [];
|
|
168254
169742
|
let userMemories = [];
|
|
169743
|
+
let workspace = resolveWorkspaceRenderContext({
|
|
169744
|
+
db: options.db,
|
|
169745
|
+
projectPath,
|
|
169746
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169747
|
+
});
|
|
168255
169748
|
let docs = {
|
|
168256
169749
|
renderedBlock: "",
|
|
168257
169750
|
canonicalHash: ""
|
|
168258
169751
|
};
|
|
168259
169752
|
options.db.exec("BEGIN");
|
|
168260
169753
|
try {
|
|
169754
|
+
workspace = resolveWorkspaceRenderContext({
|
|
169755
|
+
db: options.db,
|
|
169756
|
+
projectPath,
|
|
169757
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169758
|
+
});
|
|
168261
169759
|
snapshotMarkers = readCurrentM0SnapshotMarkers({
|
|
168262
169760
|
db: options.db,
|
|
168263
169761
|
sessionId: options.sessionId,
|
|
168264
169762
|
projectPath,
|
|
168265
169763
|
projectDirectory,
|
|
168266
|
-
hardSignals: options.hardSignals
|
|
169764
|
+
hardSignals: options.hardSignals,
|
|
169765
|
+
workspaceIdentitySet: {
|
|
169766
|
+
identities: workspace.identities,
|
|
169767
|
+
namesByIdentity: workspace.namesByIdentity
|
|
169768
|
+
}
|
|
168267
169769
|
});
|
|
168268
169770
|
docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
|
|
168269
169771
|
snapshotMarkers.projectDocsHash = docs.canonicalHash;
|
|
168270
169772
|
compartments = readM0Compartments(options.db, options.sessionId);
|
|
168271
169773
|
facts = [];
|
|
168272
|
-
memories = projectPath ? getMemoriesByProject(options.db, projectPath, ["active", "permanent"]) : [];
|
|
169774
|
+
memories = projectPath ? workspace.isWorkspaced ? getMemoriesByProjects(options.db, workspace.expandedIdentities, ["active", "permanent"], Date.now(), workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(options.db, projectPath, ["active", "permanent"]) : [];
|
|
168273
169775
|
userMemories = safeGetActiveUserMemories(options.db);
|
|
168274
169776
|
options.db.exec("COMMIT");
|
|
168275
169777
|
} catch (error51) {
|
|
@@ -168279,7 +169781,14 @@ function materializeM0(options) {
|
|
|
168279
169781
|
throw error51;
|
|
168280
169782
|
}
|
|
168281
169783
|
const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
168282
|
-
const
|
|
169784
|
+
const memoryRenderOptions = {
|
|
169785
|
+
sourceNameByMemoryId: sourceNamesForMemories({
|
|
169786
|
+
memories,
|
|
169787
|
+
projectPath,
|
|
169788
|
+
workspace
|
|
169789
|
+
})
|
|
169790
|
+
};
|
|
169791
|
+
const trimmed = workspace.isWorkspaced ? trimWorkspaceMemoriesToBudgetV2(options.sessionId, memories, memoryBudget, workspace, memoryRenderOptions) : trimMemoriesToBudgetV2(options.sessionId, memories, memoryBudget);
|
|
168283
169792
|
let decayPressureMultiplier = 1;
|
|
168284
169793
|
let m0Text = renderM0({
|
|
168285
169794
|
projectDocs: docs.renderedBlock,
|
|
@@ -168287,6 +169796,7 @@ function materializeM0(options) {
|
|
|
168287
169796
|
compartments,
|
|
168288
169797
|
memories: trimmed.renderOrder,
|
|
168289
169798
|
facts,
|
|
169799
|
+
memoryRenderOptions,
|
|
168290
169800
|
historyBudgetTokens: options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS,
|
|
168291
169801
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168292
169802
|
decayPressureMultiplier
|
|
@@ -168301,6 +169811,7 @@ function materializeM0(options) {
|
|
|
168301
169811
|
compartments,
|
|
168302
169812
|
memories: trimmed.renderOrder,
|
|
168303
169813
|
facts,
|
|
169814
|
+
memoryRenderOptions,
|
|
168304
169815
|
historyBudgetTokens: budget,
|
|
168305
169816
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168306
169817
|
decayPressureMultiplier
|
|
@@ -168319,32 +169830,46 @@ function materializeM0(options) {
|
|
|
168319
169830
|
let m1Bytes = Buffer4.from(m1Text, "utf8");
|
|
168320
169831
|
options.db.exec("BEGIN IMMEDIATE");
|
|
168321
169832
|
try {
|
|
169833
|
+
const currentWorkspace = resolveWorkspaceRenderContext({
|
|
169834
|
+
db: options.db,
|
|
169835
|
+
projectPath,
|
|
169836
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169837
|
+
});
|
|
168322
169838
|
const current = {
|
|
168323
169839
|
projectMemoryEpoch: getProjectMemoryEpoch(options.db, projectPath),
|
|
169840
|
+
workspaceFingerprint: currentWorkspace.isWorkspaced ? computeWorkspaceEpochFingerprint(options.db, currentWorkspace.identities) : null,
|
|
168324
169841
|
projectUserProfileVersion: getGlobalUserProfileVersion(options.db),
|
|
168325
169842
|
maxCompartmentSeq: getMaxCompartmentSeq(options.db, options.sessionId),
|
|
168326
|
-
maxMemoryId: getMaxMemoryId(options.db, projectPath),
|
|
169843
|
+
maxMemoryId: currentWorkspace.isWorkspaced ? getMaxMemoryIdForProjects(options.db, currentWorkspace.expandedIdentities, currentWorkspace.ownIdentities, currentWorkspace.shareCategories) : getMaxMemoryId(options.db, projectPath),
|
|
168327
169844
|
maxMutationId: getMaxM0MutationId(options.db, options.sessionId) ?? 0,
|
|
168328
|
-
maxMemoryMutationId: projectPath ? getMaxMemoryMutationId(options.db, projectPath) ?? 0 : 0,
|
|
169845
|
+
maxMemoryMutationId: currentWorkspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(options.db, currentWorkspace.expandedIdentities) ?? 0 : projectPath ? getMaxMemoryMutationId(options.db, projectPath) ?? 0 : 0,
|
|
168329
169846
|
projectDocsHash: phase3ProjectDocsHash,
|
|
168330
169847
|
materializedAt: Date.now(),
|
|
168331
169848
|
sessionFactsVersion: getSessionFactsVersion(options.db, options.sessionId),
|
|
168332
169849
|
upgradeState: getUpgradeState(options.db, options.sessionId),
|
|
168333
169850
|
systemHash: snapshotMarkers.systemHash,
|
|
168334
|
-
toolSetHash: snapshotMarkers.toolSetHash,
|
|
168335
169851
|
modelKey: snapshotMarkers.modelKey
|
|
168336
169852
|
};
|
|
168337
|
-
const
|
|
169853
|
+
const memoryEpochStale = current.workspaceFingerprint !== null || snapshotMarkers.workspaceFingerprint !== null ? current.workspaceFingerprint !== snapshotMarkers.workspaceFingerprint : current.projectMemoryEpoch !== snapshotMarkers.projectMemoryEpoch;
|
|
169854
|
+
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;
|
|
168338
169855
|
if (stale) {
|
|
168339
169856
|
options.db.exec("ROLLBACK");
|
|
168340
169857
|
throw new MaterializeContentionError({ reason: "snapshot changed before Phase 3" });
|
|
168341
169858
|
}
|
|
168342
|
-
const m1Render = renderM1WithMetadata({
|
|
169859
|
+
const m1Render = renderM1WithMetadata({
|
|
169860
|
+
...options,
|
|
169861
|
+
preRenderedKeyFilesBlock,
|
|
169862
|
+
workspaceIdentitySet: {
|
|
169863
|
+
identities: workspace.identities,
|
|
169864
|
+
namesByIdentity: workspace.namesByIdentity
|
|
169865
|
+
}
|
|
169866
|
+
}, snapshotMarkers, renderedMemoryIds);
|
|
168343
169867
|
m1Text = m1Render.text;
|
|
168344
169868
|
m1Bytes = Buffer4.from(m1Text, "utf8");
|
|
168345
169869
|
persistCachedM0(options.db, options.sessionId, {
|
|
168346
169870
|
m0Bytes,
|
|
168347
169871
|
projectMemoryEpoch: snapshotMarkers.projectMemoryEpoch,
|
|
169872
|
+
workspaceFingerprint: snapshotMarkers.workspaceFingerprint,
|
|
168348
169873
|
projectUserProfileVersion: snapshotMarkers.projectUserProfileVersion,
|
|
168349
169874
|
maxCompartmentSeq: snapshotMarkers.maxCompartmentSeq,
|
|
168350
169875
|
maxMemoryId: snapshotMarkers.maxMemoryId,
|
|
@@ -168356,7 +169881,6 @@ function materializeM0(options) {
|
|
|
168356
169881
|
sessionFactsVersion: snapshotMarkers.sessionFactsVersion,
|
|
168357
169882
|
upgradeState: snapshotMarkers.upgradeState,
|
|
168358
169883
|
systemHash: snapshotMarkers.systemHash,
|
|
168359
|
-
toolSetHash: snapshotMarkers.toolSetHash,
|
|
168360
169884
|
modelKey: snapshotMarkers.modelKey
|
|
168361
169885
|
});
|
|
168362
169886
|
options.db.prepare("UPDATE session_meta SET memory_block_count = ?, memory_block_ids = ? WHERE session_id = ?").run(renderedMemoryIds.length, JSON.stringify(renderedMemoryIds), options.sessionId);
|
|
@@ -168408,7 +169932,7 @@ function renderMemoryUpdatesBlock(args) {
|
|
|
168408
169932
|
return { block: "", count: 0 };
|
|
168409
169933
|
}
|
|
168410
169934
|
const renderedIds = new Set(args.renderedMemoryIds);
|
|
168411
|
-
const mutations = getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
169935
|
+
const mutations = args.workspace.isWorkspaced ? getMemoryMutationsForRenderByProjects(args.db, args.workspace.expandedIdentities, args.afterId, args.renderedMemoryIds) : getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
168412
169936
|
if (mutations.length === 0)
|
|
168413
169937
|
return { block: "", count: 0 };
|
|
168414
169938
|
const lines = ["These memories changed since the snapshot below — trust these:"];
|
|
@@ -168440,12 +169964,18 @@ function renderM1WithMetadata(options, markers, renderedMemoryIds) {
|
|
|
168440
169964
|
throw new RenderM1InvalidMarkersError(options.sessionId);
|
|
168441
169965
|
}
|
|
168442
169966
|
const blocks = [];
|
|
169967
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
169968
|
+
db: options.db,
|
|
169969
|
+
projectPath: options.projectPath,
|
|
169970
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169971
|
+
});
|
|
168443
169972
|
const keyFiles = renderedKeyFilesBlock(options);
|
|
168444
169973
|
if (keyFiles)
|
|
168445
169974
|
blocks.push(keyFiles);
|
|
168446
169975
|
const memoryUpdates = renderMemoryUpdatesBlock({
|
|
168447
169976
|
db: options.db,
|
|
168448
169977
|
projectPath: options.projectPath,
|
|
169978
|
+
workspace,
|
|
168449
169979
|
afterId: markers.maxMemoryMutationId,
|
|
168450
169980
|
renderedMemoryIds
|
|
168451
169981
|
});
|
|
@@ -168459,9 +169989,16 @@ ${newCompartments.map((compartment) => renderCompartmentAtTier(compartment, 1)).
|
|
|
168459
169989
|
`)}
|
|
168460
169990
|
</new-compartments>`);
|
|
168461
169991
|
}
|
|
168462
|
-
const newMemories = readNewMemoriesForM1(options.db, options.projectPath, markers.maxMemoryId, markers.materializedAt);
|
|
168463
|
-
const
|
|
168464
|
-
|
|
169992
|
+
const newMemories = workspace.isWorkspaced ? readNewMemoriesForM1Union(options.db, workspace.expandedIdentities, markers.maxMemoryId, markers.materializedAt, workspace.ownIdentities, workspace.shareCategories) : readNewMemoriesForM1(options.db, options.projectPath, markers.maxMemoryId, markers.materializedAt);
|
|
169993
|
+
const newMemoryRenderOptions = {
|
|
169994
|
+
sourceNameByMemoryId: sourceNamesForMemories({
|
|
169995
|
+
memories: newMemories,
|
|
169996
|
+
projectPath: options.projectPath,
|
|
169997
|
+
workspace
|
|
169998
|
+
})
|
|
169999
|
+
};
|
|
170000
|
+
const trimmedNewMemories = trimMemoriesToBudgetV2(options.sessionId, newMemories, Math.max(1, Math.floor((options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS) * 0.25)), newMemoryRenderOptions).renderOrder;
|
|
170001
|
+
const newMemoriesBlock = renderMemoryBlockV2(trimmedNewMemories, "new-memories", newMemoryRenderOptions);
|
|
168465
170002
|
if (newMemoriesBlock)
|
|
168466
170003
|
blocks.push(newMemoriesBlock);
|
|
168467
170004
|
const currentUserProfileVersion = getGlobalUserProfileVersion(options.db);
|
|
@@ -168509,6 +170046,7 @@ function parseMemoryBlockIds(raw) {
|
|
|
168509
170046
|
function readCachedM0M1Row(db, sessionId) {
|
|
168510
170047
|
return db.prepare(`SELECT cached_m0_bytes, cached_m1_bytes,
|
|
168511
170048
|
cached_m0_project_memory_epoch,
|
|
170049
|
+
cached_m0_workspace_fingerprint,
|
|
168512
170050
|
cached_m0_project_user_profile_version,
|
|
168513
170051
|
cached_m0_max_compartment_seq,
|
|
168514
170052
|
cached_m0_max_memory_id,
|
|
@@ -168519,7 +170057,6 @@ function readCachedM0M1Row(db, sessionId) {
|
|
|
168519
170057
|
cached_m0_session_facts_version,
|
|
168520
170058
|
cached_m0_upgrade_state,
|
|
168521
170059
|
cached_m0_system_hash,
|
|
168522
|
-
cached_m0_tool_set_hash,
|
|
168523
170060
|
cached_m0_model_key,
|
|
168524
170061
|
memory_block_ids
|
|
168525
170062
|
FROM session_meta
|
|
@@ -168544,6 +170081,7 @@ function markersFromCachedRow(row) {
|
|
|
168544
170081
|
return null;
|
|
168545
170082
|
return {
|
|
168546
170083
|
projectMemoryEpoch: row.cached_m0_project_memory_epoch,
|
|
170084
|
+
workspaceFingerprint: row.cached_m0_workspace_fingerprint,
|
|
168547
170085
|
projectUserProfileVersion: row.cached_m0_project_user_profile_version,
|
|
168548
170086
|
maxCompartmentSeq: row.cached_m0_max_compartment_seq,
|
|
168549
170087
|
maxMemoryId: row.cached_m0_max_memory_id,
|
|
@@ -168554,12 +170092,11 @@ function markersFromCachedRow(row) {
|
|
|
168554
170092
|
sessionFactsVersion: row.cached_m0_session_facts_version,
|
|
168555
170093
|
upgradeState: row.cached_m0_upgrade_state,
|
|
168556
170094
|
systemHash: row.cached_m0_system_hash ?? "",
|
|
168557
|
-
toolSetHash: row.cached_m0_tool_set_hash ?? "",
|
|
168558
170095
|
modelKey: row.cached_m0_model_key ?? ""
|
|
168559
170096
|
};
|
|
168560
170097
|
}
|
|
168561
170098
|
function cachedRowMatchesState(row, state) {
|
|
168562
|
-
return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId &&
|
|
170099
|
+
return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state.cachedM0SystemHash ?? "") && (row.cached_m0_model_key ?? "") === (state.cachedM0ModelKey ?? "");
|
|
168563
170100
|
}
|
|
168564
170101
|
function applyCachedRowToState(state, row) {
|
|
168565
170102
|
const markers = markersFromCachedRow(row);
|
|
@@ -168569,6 +170106,7 @@ function applyCachedRowToState(state, row) {
|
|
|
168569
170106
|
state.cachedM0Bytes = toBuffer(row.cached_m0_bytes);
|
|
168570
170107
|
state.cachedM1Bytes = toBuffer(row.cached_m1_bytes);
|
|
168571
170108
|
state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
|
|
170109
|
+
state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
|
|
168572
170110
|
state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
|
|
168573
170111
|
state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
|
|
168574
170112
|
state.cachedM0MaxMemoryId = markers.maxMemoryId;
|
|
@@ -168579,7 +170117,6 @@ function applyCachedRowToState(state, row) {
|
|
|
168579
170117
|
state.cachedM0SessionFactsVersion = markers.sessionFactsVersion;
|
|
168580
170118
|
state.cachedM0UpgradeState = markers.upgradeState;
|
|
168581
170119
|
state.cachedM0SystemHash = markers.systemHash;
|
|
168582
|
-
state.cachedM0ToolSetHash = markers.toolSetHash;
|
|
168583
170120
|
state.cachedM0ModelKey = markers.modelKey;
|
|
168584
170121
|
state.snapshotMarkers = markers;
|
|
168585
170122
|
}
|
|
@@ -168633,20 +170170,36 @@ function prependM0M1Messages(sessionId, messages, m0Text, m1Text) {
|
|
|
168633
170170
|
function renderFreshM0NonPersisted(options) {
|
|
168634
170171
|
const projectPath = options.projectPath;
|
|
168635
170172
|
const projectDirectory = options.projectDirectory;
|
|
170173
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
170174
|
+
db: options.db,
|
|
170175
|
+
projectPath,
|
|
170176
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
170177
|
+
});
|
|
168636
170178
|
const snapshotMarkers = readCurrentM0SnapshotMarkers({
|
|
168637
170179
|
db: options.db,
|
|
168638
170180
|
sessionId: options.sessionId,
|
|
168639
170181
|
projectPath,
|
|
168640
|
-
projectDirectory
|
|
170182
|
+
projectDirectory,
|
|
170183
|
+
workspaceIdentitySet: {
|
|
170184
|
+
identities: workspace.identities,
|
|
170185
|
+
namesByIdentity: workspace.namesByIdentity
|
|
170186
|
+
}
|
|
168641
170187
|
});
|
|
168642
170188
|
const docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
|
|
168643
170189
|
snapshotMarkers.projectDocsHash = docs.canonicalHash;
|
|
168644
170190
|
snapshotMarkers.materializedAt = options.state.cachedM0MaterializedAt ?? 0;
|
|
168645
170191
|
const compartments = readM0Compartments(options.db, options.sessionId);
|
|
168646
|
-
const memories = projectPath ? getMemoriesByProject(options.db, projectPath, ["active", "permanent"], snapshotMarkers.materializedAt) : [];
|
|
170192
|
+
const memories = projectPath ? workspace.isWorkspaced ? getMemoriesByProjects(options.db, workspace.expandedIdentities, ["active", "permanent"], snapshotMarkers.materializedAt, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(options.db, projectPath, ["active", "permanent"], snapshotMarkers.materializedAt) : [];
|
|
168647
170193
|
const userMemories = safeGetActiveUserMemories(options.db);
|
|
168648
170194
|
const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
168649
|
-
const
|
|
170195
|
+
const memoryRenderOptions = {
|
|
170196
|
+
sourceNameByMemoryId: sourceNamesForMemories({
|
|
170197
|
+
memories,
|
|
170198
|
+
projectPath,
|
|
170199
|
+
workspace
|
|
170200
|
+
})
|
|
170201
|
+
};
|
|
170202
|
+
const trimmed = workspace.isWorkspaced ? trimWorkspaceMemoriesToBudgetV2(options.sessionId, memories, memoryBudget, workspace, memoryRenderOptions) : trimMemoriesToBudgetV2(options.sessionId, memories, memoryBudget);
|
|
168650
170203
|
const budget = options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
168651
170204
|
let decayPressureMultiplier = 1;
|
|
168652
170205
|
let m0Text = renderM0({
|
|
@@ -168655,6 +170208,7 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168655
170208
|
compartments,
|
|
168656
170209
|
memories: trimmed.renderOrder,
|
|
168657
170210
|
facts: [],
|
|
170211
|
+
memoryRenderOptions,
|
|
168658
170212
|
historyBudgetTokens: budget,
|
|
168659
170213
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168660
170214
|
decayPressureMultiplier
|
|
@@ -168668,6 +170222,7 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168668
170222
|
compartments,
|
|
168669
170223
|
memories: trimmed.renderOrder,
|
|
168670
170224
|
facts: [],
|
|
170225
|
+
memoryRenderOptions,
|
|
168671
170226
|
historyBudgetTokens: budget,
|
|
168672
170227
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168673
170228
|
decayPressureMultiplier
|
|
@@ -168683,6 +170238,12 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168683
170238
|
};
|
|
168684
170239
|
}
|
|
168685
170240
|
function injectM0M1(options) {
|
|
170241
|
+
if (!options.workspaceIdentitySet && options.projectPath) {
|
|
170242
|
+
options = {
|
|
170243
|
+
...options,
|
|
170244
|
+
workspaceIdentitySet: resolveWorkspaceIdentitySet(options.db, options.projectPath)
|
|
170245
|
+
};
|
|
170246
|
+
}
|
|
168686
170247
|
const skipped = {
|
|
168687
170248
|
injected: false,
|
|
168688
170249
|
m0RematerializedThisPass: false,
|
|
@@ -168699,7 +170260,8 @@ function injectM0M1(options) {
|
|
|
168699
170260
|
state: options.state,
|
|
168700
170261
|
projectPath: options.projectPath,
|
|
168701
170262
|
projectDirectory: options.projectDirectory,
|
|
168702
|
-
hardSignals: options.hardSignals
|
|
170263
|
+
hardSignals: options.hardSignals,
|
|
170264
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
168703
170265
|
});
|
|
168704
170266
|
let rematerialized = false;
|
|
168705
170267
|
let contentionExhausted = false;
|
|
@@ -168793,6 +170355,7 @@ var init_inject_compartments = __esm(async () => {
|
|
|
168793
170355
|
init_compartment_storage();
|
|
168794
170356
|
init_constants();
|
|
168795
170357
|
init_storage_memory();
|
|
170358
|
+
init_workspaces();
|
|
168796
170359
|
init_logger();
|
|
168797
170360
|
init_decay_render();
|
|
168798
170361
|
init_key_files_block();
|
|
@@ -168806,7 +170369,6 @@ var init_inject_compartments = __esm(async () => {
|
|
|
168806
170369
|
CONSTRAINT_KEYWORDS = /\b(must|never|always|cannot|should not|must not)\b/i;
|
|
168807
170370
|
EMPTY_HARD_SIGNALS = {
|
|
168808
170371
|
systemHash: "",
|
|
168809
|
-
toolSetHash: "",
|
|
168810
170372
|
modelKey: "",
|
|
168811
170373
|
cacheExpired: false,
|
|
168812
170374
|
lastResponseTime: 0
|
|
@@ -171933,18 +173495,38 @@ async function runCompartmentAgent(deps) {
|
|
|
171933
173495
|
return;
|
|
171934
173496
|
}
|
|
171935
173497
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
171936
|
-
|
|
173498
|
+
let boundarySnapshot = deps.boundarySnapshot ?? null;
|
|
171937
173499
|
if (!boundarySnapshot) {
|
|
171938
173500
|
telemetry.failureReason = "missing protected-tail boundary snapshot";
|
|
171939
173501
|
sessionLog(sessionId, "historian no-op: missing protected-tail boundary snapshot from trigger decision");
|
|
171940
173502
|
rollbackDrainReservation();
|
|
171941
173503
|
return;
|
|
171942
173504
|
}
|
|
171943
|
-
|
|
173505
|
+
let validation = boundarySnapshot.rawRangeFingerprint.length > 0 ? validateBoundarySnapshot({
|
|
171944
173506
|
db,
|
|
171945
173507
|
snapshot: boundarySnapshot,
|
|
171946
173508
|
currentContextLimit: deps.currentContextLimit ?? boundarySnapshot.contextLimit
|
|
171947
173509
|
}) : { ok: true };
|
|
173510
|
+
if (!validation.ok && validation.reason === "stale_snapshot") {
|
|
173511
|
+
const refreshed = resolveOpenCodeProtectedTailBoundary({
|
|
173512
|
+
db,
|
|
173513
|
+
sessionId,
|
|
173514
|
+
mode: "incremental-runner",
|
|
173515
|
+
contextLimit: deps.currentContextLimit ?? boundarySnapshot.contextLimit,
|
|
173516
|
+
executeThresholdPercentage: boundarySnapshot.executeThresholdPercentage,
|
|
173517
|
+
usage: {
|
|
173518
|
+
percentage: boundarySnapshot.usagePercentage,
|
|
173519
|
+
inputTokens: boundarySnapshot.usageInputTokens
|
|
173520
|
+
},
|
|
173521
|
+
usageSource: boundarySnapshot.usageSource,
|
|
173522
|
+
emergencyTailScale: boundarySnapshot.emergencyTailScale
|
|
173523
|
+
});
|
|
173524
|
+
if (hasRunnableCompartmentWindow(refreshed)) {
|
|
173525
|
+
sessionLog(sessionId, `historian: refreshed stale protected-tail snapshot at run time (was: ${validation.detail ?? "stale"}) — eligible head ${refreshed.offset}-${refreshed.eligibleEndOrdinal - 1}`);
|
|
173526
|
+
boundarySnapshot = refreshed;
|
|
173527
|
+
validation = { ok: true };
|
|
173528
|
+
}
|
|
173529
|
+
}
|
|
171948
173530
|
if (!validation.ok) {
|
|
171949
173531
|
sessionLog(sessionId, `historian no-op: stale protected-tail snapshot (${validation.detail ?? validation.reason ?? "unknown"})`);
|
|
171950
173532
|
telemetry.status = "noop";
|
|
@@ -172013,6 +173595,7 @@ async function runCompartmentAgent(deps) {
|
|
|
172013
173595
|
rollbackDrainReservation();
|
|
172014
173596
|
return;
|
|
172015
173597
|
}
|
|
173598
|
+
deps.onHistorianRunStarted?.();
|
|
172016
173599
|
const projectPath = resolveProjectIdentity(directory ?? process.cwd());
|
|
172017
173600
|
const memories = getMemoriesByProject(db, projectPath, ["active", "permanent"]);
|
|
172018
173601
|
const projectMemory = renderMemoryBlock(memories) ?? "";
|
|
@@ -172145,8 +173728,13 @@ ${chunkText}`,
|
|
|
172145
173728
|
}
|
|
172146
173729
|
if (embeddingActive) {
|
|
172147
173730
|
const projectIdentity = resolveProjectIdentity(promotionDirectory);
|
|
172148
|
-
const
|
|
172149
|
-
|
|
173731
|
+
const chunksToEmbed = persistedCompartments.map((c, i) => ({
|
|
173732
|
+
id: persistedIds[i],
|
|
173733
|
+
startMessage: c.startMessage,
|
|
173734
|
+
endMessage: c.endMessage,
|
|
173735
|
+
sourceChunkText: chunk.text
|
|
173736
|
+
})).filter((c) => typeof c.id === "number");
|
|
173737
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
172150
173738
|
}
|
|
172151
173739
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
172152
173740
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
@@ -172377,8 +173965,12 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
172377
173965
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172378
173966
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
172379
173967
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172380
|
-
const
|
|
172381
|
-
|
|
173968
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
173969
|
+
id: c.id,
|
|
173970
|
+
startMessage: c.startMessage,
|
|
173971
|
+
endMessage: c.endMessage
|
|
173972
|
+
}));
|
|
173973
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
172382
173974
|
}
|
|
172383
173975
|
const lastCompartmentEnd2 = promoted2.compartments[promoted2.compartments.length - 1]?.endMessage ?? 0;
|
|
172384
173976
|
if (lastCompartmentEnd2 > 0) {
|
|
@@ -172591,8 +174183,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
172591
174183
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172592
174184
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
172593
174185
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172594
|
-
const
|
|
172595
|
-
|
|
174186
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
174187
|
+
id: c.id,
|
|
174188
|
+
startMessage: c.startMessage,
|
|
174189
|
+
endMessage: c.endMessage
|
|
174190
|
+
}));
|
|
174191
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
172596
174192
|
}
|
|
172597
174193
|
if (lastCompartmentEnd > 0) {
|
|
172598
174194
|
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
@@ -172773,8 +174369,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
172773
174369
|
if (deps.memoryEnabled !== false) {
|
|
172774
174370
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172775
174371
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172776
|
-
const
|
|
172777
|
-
|
|
174372
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
174373
|
+
id: c.id,
|
|
174374
|
+
startMessage: c.startMessage,
|
|
174375
|
+
endMessage: c.endMessage
|
|
174376
|
+
}));
|
|
174377
|
+
Promise.resolve(deps.ensureProjectRegistered?.(sessionDirectory, db)).then(() => embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed));
|
|
172778
174378
|
}
|
|
172779
174379
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
172780
174380
|
if (lastEnd > 0) {
|
|
@@ -174996,7 +176596,14 @@ function startCompartmentAgent(deps) {
|
|
|
174996
176596
|
return;
|
|
174997
176597
|
}
|
|
174998
176598
|
const renewal = startLeaseRenewal(deps, holderId);
|
|
174999
|
-
|
|
176599
|
+
let realRunStarted = false;
|
|
176600
|
+
const runnerDeps = withPublishedCallback({
|
|
176601
|
+
...deps,
|
|
176602
|
+
compartmentLeaseHolderId: holderId,
|
|
176603
|
+
onHistorianRunStarted: () => {
|
|
176604
|
+
realRunStarted = true;
|
|
176605
|
+
}
|
|
176606
|
+
});
|
|
175000
176607
|
const promise2 = runCompartmentAgent(runnerDeps).catch((err) => {
|
|
175001
176608
|
sessionLog(deps.sessionId, "compartment agent: unhandled rejection:", err);
|
|
175002
176609
|
try {
|
|
@@ -175010,6 +176617,9 @@ function startCompartmentAgent(deps) {
|
|
|
175010
176617
|
}
|
|
175011
176618
|
});
|
|
175012
176619
|
activeRuns.set(deps.sessionId, { promise: promise2, published: false });
|
|
176620
|
+
if (!realRunStarted && activeRuns.get(deps.sessionId)?.promise === promise2) {
|
|
176621
|
+
activeRuns.delete(deps.sessionId);
|
|
176622
|
+
}
|
|
175013
176623
|
}
|
|
175014
176624
|
async function executeContextRecompWithResult(deps, options = {}) {
|
|
175015
176625
|
const { sessionId } = deps;
|
|
@@ -175144,7 +176754,7 @@ function applyMemoryMigration(db, projectPath, result) {
|
|
|
175144
176754
|
inserted++;
|
|
175145
176755
|
}
|
|
175146
176756
|
if (removed > 0 || inserted > 0) {
|
|
175147
|
-
|
|
176757
|
+
bumpEpochsForWorkspaceMembers(db, projectPath);
|
|
175148
176758
|
}
|
|
175149
176759
|
})();
|
|
175150
176760
|
return { removed, inserted };
|
|
@@ -175602,15 +177212,15 @@ function shouldShowAnnouncement() {
|
|
|
175602
177212
|
}
|
|
175603
177213
|
return state.version !== ANNOUNCEMENT_VERSION;
|
|
175604
177214
|
}
|
|
175605
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
177215
|
+
var ANNOUNCEMENT_VERSION = "0.24.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
|
|
175606
177216
|
var init_announcement = __esm(() => {
|
|
175607
177217
|
init_data_path();
|
|
175608
177218
|
ANNOUNCEMENT_FEATURES = [
|
|
175609
|
-
"
|
|
175610
|
-
"
|
|
175611
|
-
"
|
|
175612
|
-
"
|
|
175613
|
-
"
|
|
177219
|
+
"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).",
|
|
177220
|
+
"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.",
|
|
177221
|
+
"Pi: fixed sessions overflowing the model context while still showing moderate usage — Pi now sheds context before a tool-heavy turn overflows.",
|
|
177222
|
+
"Fewer prompt-cache busts: doc edits, processed screenshots, and a rebuild-then-bust-again case no longer re-bill large prompt prefixes.",
|
|
177223
|
+
"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)."
|
|
175614
177224
|
];
|
|
175615
177225
|
});
|
|
175616
177226
|
// src/agents/permissions.ts
|
|
@@ -176338,6 +177948,10 @@ function getMagicContextBuiltinCommands() {
|
|
|
176338
177948
|
"ctx-dream": {
|
|
176339
177949
|
template: "ctx-dream",
|
|
176340
177950
|
description: "Run the hidden dreamer maintenance pass for this project now"
|
|
177951
|
+
},
|
|
177952
|
+
"ctx-embed-history": {
|
|
177953
|
+
template: "ctx-embed-history",
|
|
177954
|
+
description: "Embed all of this session's history compartments for semantic search, in one pass"
|
|
176341
177955
|
}
|
|
176342
177956
|
};
|
|
176343
177957
|
}
|
|
@@ -176831,7 +178445,7 @@ await init_storage_db();
|
|
|
176831
178445
|
// src/features/magic-context/v22-deferred-backfill.ts
|
|
176832
178446
|
init_logger();
|
|
176833
178447
|
init_project_identity();
|
|
176834
|
-
import { createHash as
|
|
178448
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
176835
178449
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
176836
178450
|
import path5 from "node:path";
|
|
176837
178451
|
var BATCH_SIZE = 25;
|
|
@@ -176885,7 +178499,7 @@ function computeLegacyRustDirIdentity(rawProjectPath) {
|
|
|
176885
178499
|
} catch {
|
|
176886
178500
|
canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
|
|
176887
178501
|
}
|
|
176888
|
-
return `dir:${
|
|
178502
|
+
return `dir:${createHash6("sha256").update(canonical, "utf8").digest("hex")}`;
|
|
176889
178503
|
}
|
|
176890
178504
|
function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
|
|
176891
178505
|
db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
|
|
@@ -179426,7 +181040,7 @@ init_project_identity();
|
|
|
179426
181040
|
// src/plugin/embedding-bootstrap-helpers.ts
|
|
179427
181041
|
init_embedding();
|
|
179428
181042
|
init_logger();
|
|
179429
|
-
import { createHash as
|
|
181043
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
179430
181044
|
var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
179431
181045
|
"embedding.api_key",
|
|
179432
181046
|
"embedding.endpoint",
|
|
@@ -179447,7 +181061,7 @@ var EMBEDDING_WARNING_TERMS = [
|
|
|
179447
181061
|
];
|
|
179448
181062
|
var loggedFailureSignatures = new Map;
|
|
179449
181063
|
function sha256Prefix2(value, length = 16) {
|
|
179450
|
-
return
|
|
181064
|
+
return createHash10("sha256").update(value).digest("hex").slice(0, length);
|
|
179451
181065
|
}
|
|
179452
181066
|
function warningLooksEmbeddingRelated(message) {
|
|
179453
181067
|
const lower = message.toLowerCase();
|
|
@@ -180083,7 +181697,7 @@ function createTagger() {
|
|
|
180083
181697
|
// src/hooks/magic-context/hook.ts
|
|
180084
181698
|
init_magic_context();
|
|
180085
181699
|
init_project_identity();
|
|
180086
|
-
|
|
181700
|
+
init_project_embedding_registry();
|
|
180087
181701
|
await init_storage();
|
|
180088
181702
|
init_logger();
|
|
180089
181703
|
init_resolve_fallbacks();
|
|
@@ -180677,6 +182291,7 @@ function createMagicContextCommandHandler(deps) {
|
|
|
180677
182291
|
const isAugCommand = (command) => command === "ctx-aug";
|
|
180678
182292
|
const isDreamCommand = (command) => command === "ctx-dream";
|
|
180679
182293
|
const isSessionUpgradeCommand = (command) => command === "ctx-session-upgrade";
|
|
182294
|
+
const isEmbedHistoryCommand = (command) => command === "ctx-embed-history";
|
|
180680
182295
|
return {
|
|
180681
182296
|
"command.execute.before": async (input, _output, _params) => {
|
|
180682
182297
|
const isStatus = isStatusCommand(input.command);
|
|
@@ -180685,7 +182300,8 @@ function createMagicContextCommandHandler(deps) {
|
|
|
180685
182300
|
const isAug = isAugCommand(input.command);
|
|
180686
182301
|
const isDream = isDreamCommand(input.command);
|
|
180687
182302
|
const isSessionUpgrade = isSessionUpgradeCommand(input.command);
|
|
180688
|
-
|
|
182303
|
+
const isEmbedHistory = isEmbedHistoryCommand(input.command);
|
|
182304
|
+
if (!isStatus && !isFlush && !isRecomp && !isAug && !isDream && !isSessionUpgrade && !isEmbedHistory) {
|
|
180689
182305
|
return;
|
|
180690
182306
|
}
|
|
180691
182307
|
const sessionId = input.sessionID;
|
|
@@ -180698,6 +182314,11 @@ function createMagicContextCommandHandler(deps) {
|
|
|
180698
182314
|
await executeDreaming(deps, sessionId);
|
|
180699
182315
|
return;
|
|
180700
182316
|
}
|
|
182317
|
+
if (isEmbedHistory) {
|
|
182318
|
+
const summary = deps.executeEmbedHistory ? await deps.executeEmbedHistory(sessionId) : "Semantic embedding is not configured for this project, so there is nothing to embed.";
|
|
182319
|
+
await deps.sendNotification(sessionId, summary, {});
|
|
182320
|
+
throwSentinel(input.command);
|
|
182321
|
+
}
|
|
180701
182322
|
if (isFlush) {
|
|
180702
182323
|
result = executeFlush(deps.db, sessionId);
|
|
180703
182324
|
clearCachedM0M1(deps.db, sessionId);
|
|
@@ -181438,6 +183059,7 @@ await init_read_session_chunk();
|
|
|
181438
183059
|
// src/hooks/magic-context/transform.ts
|
|
181439
183060
|
init_project_identity();
|
|
181440
183061
|
import * as crypto2 from "node:crypto";
|
|
183062
|
+
init_session_project_storage();
|
|
181441
183063
|
init_storage_meta_persisted();
|
|
181442
183064
|
init_logger();
|
|
181443
183065
|
await init_storage();
|
|
@@ -181819,6 +183441,63 @@ function replayCavemanCompression(sessionId, db, targets, tags) {
|
|
|
181819
183441
|
|
|
181820
183442
|
// src/hooks/magic-context/transform.ts
|
|
181821
183443
|
await init_compartment_runner();
|
|
183444
|
+
|
|
183445
|
+
// src/hooks/magic-context/ctx-reduce-availability.ts
|
|
183446
|
+
init_logger();
|
|
183447
|
+
await init_read_session_db();
|
|
183448
|
+
var availabilityBySession = new BoundedSessionMap(500);
|
|
183449
|
+
function verdictFromToolsMap(tools) {
|
|
183450
|
+
if (tools === null || typeof tools !== "object" || Array.isArray(tools))
|
|
183451
|
+
return null;
|
|
183452
|
+
const map2 = tools;
|
|
183453
|
+
if (map2.ctx_reduce === true)
|
|
183454
|
+
return true;
|
|
183455
|
+
if (map2.ctx_reduce === false)
|
|
183456
|
+
return false;
|
|
183457
|
+
if (map2["*"] === false)
|
|
183458
|
+
return false;
|
|
183459
|
+
return null;
|
|
183460
|
+
}
|
|
183461
|
+
function resolveCtxReduceAvailabilityFromMessages(sessionId, messages) {
|
|
183462
|
+
const cached2 = availabilityBySession.get(sessionId);
|
|
183463
|
+
if (cached2 !== undefined)
|
|
183464
|
+
return cached2;
|
|
183465
|
+
for (const message of messages) {
|
|
183466
|
+
if (message.info?.role !== "user")
|
|
183467
|
+
continue;
|
|
183468
|
+
const verdict = verdictFromToolsMap(message.info.tools);
|
|
183469
|
+
if (verdict !== null) {
|
|
183470
|
+
availabilityBySession.set(sessionId, verdict);
|
|
183471
|
+
return verdict;
|
|
183472
|
+
}
|
|
183473
|
+
break;
|
|
183474
|
+
}
|
|
183475
|
+
availabilityBySession.set(sessionId, true);
|
|
183476
|
+
return true;
|
|
183477
|
+
}
|
|
183478
|
+
function resolveCtxReduceAvailability(sessionId) {
|
|
183479
|
+
const cached2 = availabilityBySession.get(sessionId);
|
|
183480
|
+
if (cached2 !== undefined)
|
|
183481
|
+
return cached2;
|
|
183482
|
+
if (!openCodeDbExists())
|
|
183483
|
+
return true;
|
|
183484
|
+
try {
|
|
183485
|
+
const row = withReadOnlySessionDb((db) => db.prepare(`SELECT json_extract(data, '$.tools') AS tools FROM message
|
|
183486
|
+
WHERE session_id = ? AND json_extract(data, '$.role') = 'user'
|
|
183487
|
+
ORDER BY time_created ASC LIMIT 1`).get(sessionId));
|
|
183488
|
+
if (!row)
|
|
183489
|
+
return true;
|
|
183490
|
+
const verdict = row.tools === null ? null : verdictFromToolsMap(JSON.parse(row.tools));
|
|
183491
|
+
const resolved = verdict ?? true;
|
|
183492
|
+
availabilityBySession.set(sessionId, resolved);
|
|
183493
|
+
return resolved;
|
|
183494
|
+
} catch (error51) {
|
|
183495
|
+
sessionLog(sessionId, "ctx_reduce availability read failed (fail-open):", error51);
|
|
183496
|
+
return true;
|
|
183497
|
+
}
|
|
183498
|
+
}
|
|
183499
|
+
|
|
183500
|
+
// src/hooks/magic-context/transform.ts
|
|
181822
183501
|
init_derive_budgets();
|
|
181823
183502
|
|
|
181824
183503
|
// src/hooks/magic-context/image-token-estimate.ts
|
|
@@ -181981,6 +183660,7 @@ await __promiseAll([
|
|
|
181981
183660
|
init_read_session_chunk(),
|
|
181982
183661
|
init_read_session_db()
|
|
181983
183662
|
]);
|
|
183663
|
+
|
|
181984
183664
|
// src/hooks/magic-context/sentinel.ts
|
|
181985
183665
|
var WHOLE_MESSAGE_PLACEHOLDER_TEXT = "[dropped]";
|
|
181986
183666
|
function modelAcceptsEmptyContent(providerID) {
|
|
@@ -182038,7 +183718,6 @@ function replaySentinelByMessageIds(messages, ids, providerID) {
|
|
|
182038
183718
|
missingIds.push(id);
|
|
182039
183719
|
return { replayed, missingIds };
|
|
182040
183720
|
}
|
|
182041
|
-
|
|
182042
183721
|
// src/hooks/magic-context/strip-content.ts
|
|
182043
183722
|
var DROPPED_PLACEHOLDER_PATTERN = /^\[dropped §\d+§\]$/;
|
|
182044
183723
|
var TAG_PREFIX_PATTERN = /^§\d+§\s*/;
|
|
@@ -182391,8 +184070,10 @@ function stripReasoningFromMergedAssistants(messages, providerID) {
|
|
|
182391
184070
|
}
|
|
182392
184071
|
return stripped;
|
|
182393
184072
|
}
|
|
182394
|
-
function stripProcessedImages(messages,
|
|
184073
|
+
function stripProcessedImages(messages, frozenIds, options) {
|
|
184074
|
+
const { detect, watermark, messageTagNumbers } = options;
|
|
182395
184075
|
let stripped = 0;
|
|
184076
|
+
const newlyStrippedIds = [];
|
|
182396
184077
|
let hasAssistantResponse = false;
|
|
182397
184078
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
182398
184079
|
const msg = messages[i];
|
|
@@ -182400,13 +184081,17 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
182400
184081
|
hasAssistantResponse = true;
|
|
182401
184082
|
continue;
|
|
182402
184083
|
}
|
|
182403
|
-
if (msg.info.role !== "user"
|
|
184084
|
+
if (msg.info.role !== "user") {
|
|
182404
184085
|
continue;
|
|
182405
184086
|
}
|
|
184087
|
+
const id = typeof msg.info.id === "string" ? msg.info.id : undefined;
|
|
184088
|
+
const inFrozen = id !== undefined && frozenIds.has(id);
|
|
182406
184089
|
const maxTag = messageTagNumbers.get(msg) ?? 0;
|
|
182407
|
-
|
|
184090
|
+
const isNewDetection = !inFrozen && detect && hasAssistantResponse && id !== undefined && maxTag <= watermark;
|
|
184091
|
+
if (!inFrozen && !isNewDetection) {
|
|
182408
184092
|
continue;
|
|
182409
184093
|
}
|
|
184094
|
+
let touchedThisMsg = false;
|
|
182410
184095
|
for (let j = 0;j < msg.parts.length; j++) {
|
|
182411
184096
|
const part = msg.parts[j];
|
|
182412
184097
|
if (!isRecord(part) || part.type !== "file") {
|
|
@@ -182418,10 +184103,14 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
182418
184103
|
if (typeof part.url === "string" && part.url.startsWith("data:") && part.url.length > 200) {
|
|
182419
184104
|
msg.parts[j] = makeSentinel(part);
|
|
182420
184105
|
stripped++;
|
|
184106
|
+
touchedThisMsg = true;
|
|
182421
184107
|
}
|
|
182422
184108
|
}
|
|
184109
|
+
if (touchedThisMsg && isNewDetection && id !== undefined) {
|
|
184110
|
+
newlyStrippedIds.push(id);
|
|
184111
|
+
}
|
|
182423
184112
|
}
|
|
182424
|
-
return stripped;
|
|
184113
|
+
return { stripped, newlyStrippedIds };
|
|
182425
184114
|
}
|
|
182426
184115
|
|
|
182427
184116
|
// src/hooks/magic-context/transform.ts
|
|
@@ -182737,6 +184426,7 @@ function appendReminderToUserMessage(message, reminder) {
|
|
|
182737
184426
|
init_tag_part_guards();
|
|
182738
184427
|
await init_storage();
|
|
182739
184428
|
var USER_DROP_PREVIEW_CHARS = 250;
|
|
184429
|
+
var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
182740
184430
|
function buildReplacementContent(tagId, target) {
|
|
182741
184431
|
const role = target.message?.info.role;
|
|
182742
184432
|
if (role !== "user") {
|
|
@@ -182762,6 +184452,7 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
182762
184452
|
const tagTypeById = new Map(tags.map((tag) => [tag.tagNumber, tag.type]));
|
|
182763
184453
|
const protectedTagIds = protectedTags > 0 ? new Set(tags.filter((tag) => tag.status === "active").map((tag) => tag.tagNumber).sort((left, right) => right - left).slice(0, protectedTags)) : new Set;
|
|
182764
184454
|
const pendingOps = preloadedPendingOps ?? getPendingOps(db, sessionId);
|
|
184455
|
+
const skeletonWindow = new Set(tags.filter((tag) => tag.type === "tool").map((tag) => tag.tagNumber).sort((left, right) => right - left).slice(0, RECENT_TOOL_SKELETON_WINDOW));
|
|
182765
184456
|
for (const pendingOp of pendingOps) {
|
|
182766
184457
|
const tagStatus = tagStatusById.get(pendingOp.tagId);
|
|
182767
184458
|
if (tagStatus === "compacted" || tagStatus === "dropped") {
|
|
@@ -182774,14 +184465,25 @@ function applyPendingOperations(sessionId, db, targets, protectedTags = 0, prelo
|
|
|
182774
184465
|
const target = targets.get(pendingOp.tagId);
|
|
182775
184466
|
const isToolTag = tagTypeById.get(pendingOp.tagId) === "tool";
|
|
182776
184467
|
if (isToolTag) {
|
|
182777
|
-
|
|
182778
|
-
|
|
182779
|
-
|
|
182780
|
-
|
|
182781
|
-
|
|
182782
|
-
|
|
184468
|
+
if (skeletonWindow.has(pendingOp.tagId)) {
|
|
184469
|
+
const truncResult = target?.truncate?.() ?? "absent";
|
|
184470
|
+
if (truncResult === "incomplete") {
|
|
184471
|
+
continue;
|
|
184472
|
+
}
|
|
184473
|
+
if (truncResult === "truncated") {
|
|
184474
|
+
didMutateMessage = true;
|
|
184475
|
+
}
|
|
184476
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, "truncated");
|
|
184477
|
+
} else {
|
|
184478
|
+
const dropResult = target?.drop?.() ?? "absent";
|
|
184479
|
+
if (dropResult === "incomplete") {
|
|
184480
|
+
continue;
|
|
184481
|
+
}
|
|
184482
|
+
if (dropResult === "removed") {
|
|
184483
|
+
didMutateMessage = true;
|
|
184484
|
+
}
|
|
184485
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, "full");
|
|
182783
184486
|
}
|
|
182784
|
-
updateTagDropMode(db, sessionId, pendingOp.tagId, "full");
|
|
182785
184487
|
} else if (target) {
|
|
182786
184488
|
const changed = target.setContent(buildReplacementContent(pendingOp.tagId, target));
|
|
182787
184489
|
if (changed)
|
|
@@ -183351,6 +185053,7 @@ init_embedding();
|
|
|
183351
185053
|
|
|
183352
185054
|
// src/features/magic-context/search.ts
|
|
183353
185055
|
init_logger();
|
|
185056
|
+
init_compartment_chunk_embedding();
|
|
183354
185057
|
|
|
183355
185058
|
// src/features/magic-context/literal-probes.ts
|
|
183356
185059
|
var MAX_PROBES = 5;
|
|
@@ -183412,6 +185115,7 @@ function containsProbeVerbatim(text, probes) {
|
|
|
183412
185115
|
init_memory();
|
|
183413
185116
|
init_embedding();
|
|
183414
185117
|
init_storage_memory_fts();
|
|
185118
|
+
init_workspaces();
|
|
183415
185119
|
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
183416
185120
|
var FTS_SEMANTIC_CANDIDATE_LIMIT = 50;
|
|
183417
185121
|
var SEMANTIC_WEIGHT = 0.7;
|
|
@@ -183441,6 +185145,37 @@ function previewText(text) {
|
|
|
183441
185145
|
}
|
|
183442
185146
|
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}…`;
|
|
183443
185147
|
}
|
|
185148
|
+
function resolveSearchWorkspaceContext(db, projectPath, identitySet) {
|
|
185149
|
+
const resolved = identitySet ?? resolveWorkspaceIdentitySet(db, projectPath);
|
|
185150
|
+
const isWorkspaced = resolved.identities.length > 1;
|
|
185151
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(db, resolved.identities);
|
|
185152
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : resolved.identities;
|
|
185153
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(resolved.identities.map((identity) => [identity, identity]));
|
|
185154
|
+
const ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === projectPath);
|
|
185155
|
+
return {
|
|
185156
|
+
identities: resolved.identities,
|
|
185157
|
+
expandedIdentities,
|
|
185158
|
+
ownIdentities,
|
|
185159
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(db, projectPath) : null,
|
|
185160
|
+
namesByIdentity: resolved.namesByIdentity,
|
|
185161
|
+
canonicalIdentityByStoredPath,
|
|
185162
|
+
isWorkspaced
|
|
185163
|
+
};
|
|
185164
|
+
}
|
|
185165
|
+
function memoryWorkspaceIdentity(memory, workspace) {
|
|
185166
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
185167
|
+
}
|
|
185168
|
+
function sourceNamesForSearchMemories(args) {
|
|
185169
|
+
if (!args.workspace.isWorkspaced)
|
|
185170
|
+
return;
|
|
185171
|
+
const sourceNames = new Map;
|
|
185172
|
+
for (const memory of args.memories) {
|
|
185173
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
185174
|
+
if (source)
|
|
185175
|
+
sourceNames.set(memory.id, source);
|
|
185176
|
+
}
|
|
185177
|
+
return sourceNames.size > 0 ? sourceNames : undefined;
|
|
185178
|
+
}
|
|
183444
185179
|
function getMessageSearchStatement(db) {
|
|
183445
185180
|
let stmt = messageSearchStatements.get(db);
|
|
183446
185181
|
if (!stmt) {
|
|
@@ -183449,6 +185184,30 @@ function getMessageSearchStatement(db) {
|
|
|
183449
185184
|
}
|
|
183450
185185
|
return stmt;
|
|
183451
185186
|
}
|
|
185187
|
+
var ftsRowCountStatements = new WeakMap;
|
|
185188
|
+
var ftsMatchCountStatements = new WeakMap;
|
|
185189
|
+
function getSessionFtsRowCount(db, sessionId) {
|
|
185190
|
+
let stmt = ftsRowCountStatements.get(db);
|
|
185191
|
+
if (!stmt) {
|
|
185192
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ?");
|
|
185193
|
+
ftsRowCountStatements.set(db, stmt);
|
|
185194
|
+
}
|
|
185195
|
+
const row = stmt.get(sessionId);
|
|
185196
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
185197
|
+
}
|
|
185198
|
+
function countSessionFtsMatches(db, sessionId, ftsQuery) {
|
|
185199
|
+
let stmt = ftsMatchCountStatements.get(db);
|
|
185200
|
+
if (!stmt) {
|
|
185201
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ?");
|
|
185202
|
+
ftsMatchCountStatements.set(db, stmt);
|
|
185203
|
+
}
|
|
185204
|
+
try {
|
|
185205
|
+
const row = stmt.get(sessionId, ftsQuery);
|
|
185206
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
185207
|
+
} catch {
|
|
185208
|
+
return 0;
|
|
185209
|
+
}
|
|
185210
|
+
}
|
|
183452
185211
|
function getMessageOrdinal(value) {
|
|
183453
185212
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
183454
185213
|
return value;
|
|
@@ -183464,25 +185223,63 @@ async function getSemanticScores(args) {
|
|
|
183464
185223
|
if (!args.queryEmbedding || args.memories.length === 0) {
|
|
183465
185224
|
return semanticScores;
|
|
183466
185225
|
}
|
|
183467
|
-
|
|
183468
|
-
|
|
183469
|
-
|
|
183470
|
-
|
|
183471
|
-
|
|
183472
|
-
|
|
183473
|
-
|
|
185226
|
+
if (!args.workspace?.isWorkspaced) {
|
|
185227
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
185228
|
+
const embeddings = await ensureMemoryEmbeddings({
|
|
185229
|
+
db: args.db,
|
|
185230
|
+
projectIdentity: args.projectPath,
|
|
185231
|
+
memories: args.memories,
|
|
185232
|
+
existingEmbeddings: cachedEmbeddings
|
|
185233
|
+
});
|
|
185234
|
+
for (const memory of args.memories) {
|
|
185235
|
+
const memoryEmbedding = embeddings.get(memory.id);
|
|
185236
|
+
if (!memoryEmbedding) {
|
|
185237
|
+
continue;
|
|
185238
|
+
}
|
|
185239
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
185240
|
+
}
|
|
185241
|
+
return semanticScores;
|
|
185242
|
+
}
|
|
185243
|
+
if (!args.queryModelId || args.queryModelId === "off") {
|
|
185244
|
+
return semanticScores;
|
|
185245
|
+
}
|
|
185246
|
+
const workspace = args.workspace;
|
|
185247
|
+
const memoriesByIdentity = new Map;
|
|
183474
185248
|
for (const memory of args.memories) {
|
|
183475
|
-
const
|
|
183476
|
-
if (!
|
|
185249
|
+
const identity = memoryWorkspaceIdentity(memory, workspace);
|
|
185250
|
+
if (!identity)
|
|
183477
185251
|
continue;
|
|
185252
|
+
const list = memoriesByIdentity.get(identity) ?? [];
|
|
185253
|
+
list.push(memory);
|
|
185254
|
+
memoriesByIdentity.set(identity, list);
|
|
185255
|
+
}
|
|
185256
|
+
const ownMemories = memoriesByIdentity.get(args.projectPath) ?? [];
|
|
185257
|
+
if (ownMemories.length > 0) {
|
|
185258
|
+
const ownEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
185259
|
+
await ensureMemoryEmbeddings({
|
|
185260
|
+
db: args.db,
|
|
185261
|
+
projectIdentity: args.projectPath,
|
|
185262
|
+
memories: ownMemories,
|
|
185263
|
+
existingEmbeddings: ownEmbeddings
|
|
185264
|
+
});
|
|
185265
|
+
}
|
|
185266
|
+
for (const identity of workspace.identities) {
|
|
185267
|
+
const memberMemories = memoriesByIdentity.get(identity) ?? [];
|
|
185268
|
+
if (memberMemories.length === 0)
|
|
185269
|
+
continue;
|
|
185270
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, identity);
|
|
185271
|
+
for (const memory of memberMemories) {
|
|
185272
|
+
const memoryEmbedding = cachedEmbeddings.get(memory.id);
|
|
185273
|
+
if (!memoryEmbedding || memoryEmbedding.modelId !== args.queryModelId)
|
|
185274
|
+
continue;
|
|
185275
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
183478
185276
|
}
|
|
183479
|
-
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
|
|
183480
185277
|
}
|
|
183481
185278
|
return semanticScores;
|
|
183482
185279
|
}
|
|
183483
185280
|
function getFtsMatches(args) {
|
|
183484
185281
|
try {
|
|
183485
|
-
return searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
185282
|
+
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);
|
|
183486
185283
|
} catch (error51) {
|
|
183487
185284
|
log(`[search] FTS query failed for "${args.query}": ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
183488
185285
|
return [];
|
|
@@ -183496,8 +185293,11 @@ function selectSemanticCandidates(args) {
|
|
|
183496
185293
|
return args.memories;
|
|
183497
185294
|
}
|
|
183498
185295
|
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
183499
|
-
const
|
|
183500
|
-
|
|
185296
|
+
const embeddingProjects = args.workspace?.isWorkspaced ? args.workspace.identities : [args.projectPath];
|
|
185297
|
+
for (const projectPath of embeddingProjects) {
|
|
185298
|
+
const cachedEmbeddings = peekProjectEmbeddings(projectPath);
|
|
185299
|
+
if (!cachedEmbeddings)
|
|
185300
|
+
continue;
|
|
183501
185301
|
for (const memoryId of cachedEmbeddings.keys()) {
|
|
183502
185302
|
candidateIds.add(memoryId);
|
|
183503
185303
|
}
|
|
@@ -183539,7 +185339,8 @@ function mergeMemoryResults(args) {
|
|
|
183539
185339
|
score,
|
|
183540
185340
|
memoryId: memory.id,
|
|
183541
185341
|
category: memory.category,
|
|
183542
|
-
matchType
|
|
185342
|
+
matchType,
|
|
185343
|
+
sourceName: args.sourceNameByMemoryId?.get(memory.id)
|
|
183543
185344
|
});
|
|
183544
185345
|
}
|
|
183545
185346
|
return results.sort((left, right) => {
|
|
@@ -183553,7 +185354,7 @@ async function searchMemories(args) {
|
|
|
183553
185354
|
if (!args.memoryEnabled) {
|
|
183554
185355
|
return [];
|
|
183555
185356
|
}
|
|
183556
|
-
const memories = getMemoriesByProject(args.db, args.projectPath);
|
|
185357
|
+
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);
|
|
183557
185358
|
if (memories.length === 0) {
|
|
183558
185359
|
return [];
|
|
183559
185360
|
}
|
|
@@ -183561,26 +185362,43 @@ async function searchMemories(args) {
|
|
|
183561
185362
|
db: args.db,
|
|
183562
185363
|
projectPath: args.projectPath,
|
|
183563
185364
|
query: args.query,
|
|
183564
|
-
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
185365
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT,
|
|
185366
|
+
workspace: args.workspace
|
|
183565
185367
|
});
|
|
183566
185368
|
const ftsScores = getFtsScores(ftsMatches);
|
|
183567
185369
|
const semanticCandidates = selectSemanticCandidates({
|
|
183568
185370
|
memories,
|
|
183569
185371
|
projectPath: args.projectPath,
|
|
183570
|
-
ftsMatches
|
|
185372
|
+
ftsMatches,
|
|
185373
|
+
workspace: args.workspace
|
|
183571
185374
|
});
|
|
183572
185375
|
const semanticScores = await getSemanticScores({
|
|
183573
185376
|
db: args.db,
|
|
183574
185377
|
projectPath: args.projectPath,
|
|
183575
185378
|
memories: semanticCandidates,
|
|
183576
|
-
queryEmbedding: args.queryEmbedding
|
|
185379
|
+
queryEmbedding: args.queryEmbedding,
|
|
185380
|
+
queryModelId: args.queryModelId,
|
|
185381
|
+
workspace: args.workspace
|
|
183577
185382
|
});
|
|
183578
185383
|
return mergeMemoryResults({
|
|
183579
185384
|
memories,
|
|
183580
185385
|
semanticScores,
|
|
183581
185386
|
ftsScores,
|
|
183582
185387
|
limit: args.limit,
|
|
183583
|
-
visibleMemoryIds: args.visibleMemoryIds
|
|
185388
|
+
visibleMemoryIds: args.visibleMemoryIds,
|
|
185389
|
+
sourceNameByMemoryId: sourceNamesForSearchMemories({
|
|
185390
|
+
memories,
|
|
185391
|
+
projectPath: args.projectPath,
|
|
185392
|
+
workspace: args.workspace ?? {
|
|
185393
|
+
identities: [args.projectPath],
|
|
185394
|
+
expandedIdentities: [args.projectPath],
|
|
185395
|
+
namesByIdentity: new Map,
|
|
185396
|
+
canonicalIdentityByStoredPath: new Map([[args.projectPath, args.projectPath]]),
|
|
185397
|
+
ownIdentities: [args.projectPath],
|
|
185398
|
+
shareCategories: null,
|
|
185399
|
+
isWorkspaced: false
|
|
185400
|
+
}
|
|
185401
|
+
})
|
|
183584
185402
|
});
|
|
183585
185403
|
}
|
|
183586
185404
|
function linearDecayScore(rank, total) {
|
|
@@ -183611,7 +185429,13 @@ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
|
|
|
183611
185429
|
return result;
|
|
183612
185430
|
}
|
|
183613
185431
|
var RRF_K = 60;
|
|
183614
|
-
var
|
|
185432
|
+
var VERBATIM_RANK_BONUS = 1 / RRF_K;
|
|
185433
|
+
var IDF_FALLOFF = 100;
|
|
185434
|
+
function probeDiscriminationWeight(df, corpusSize) {
|
|
185435
|
+
if (corpusSize <= 0 || df <= 0)
|
|
185436
|
+
return 1;
|
|
185437
|
+
return 1 / (1 + IDF_FALLOFF * df / corpusSize);
|
|
185438
|
+
}
|
|
183615
185439
|
function searchMessages(args) {
|
|
183616
185440
|
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
183617
185441
|
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
@@ -183628,20 +185452,31 @@ function searchMessages(args) {
|
|
|
183628
185452
|
role: row.role
|
|
183629
185453
|
}));
|
|
183630
185454
|
}
|
|
185455
|
+
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId);
|
|
183631
185456
|
const queryLists = [];
|
|
183632
185457
|
if (baseQuery.length > 0) {
|
|
183633
|
-
queryLists.push(
|
|
185458
|
+
queryLists.push({
|
|
185459
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff),
|
|
185460
|
+
weight: 1
|
|
185461
|
+
});
|
|
183634
185462
|
}
|
|
185463
|
+
const probeWeights = new Map;
|
|
183635
185464
|
for (const probe of probes) {
|
|
183636
185465
|
const probeQuery = sanitizeFtsQuery(probe);
|
|
183637
185466
|
if (probeQuery.length === 0)
|
|
183638
185467
|
continue;
|
|
183639
|
-
|
|
185468
|
+
const df = countSessionFtsMatches(args.db, args.sessionId, probeQuery);
|
|
185469
|
+
const weight = probeDiscriminationWeight(df, corpusSize);
|
|
185470
|
+
probeWeights.set(probe, weight);
|
|
185471
|
+
queryLists.push({
|
|
185472
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff),
|
|
185473
|
+
weight
|
|
185474
|
+
});
|
|
183640
185475
|
}
|
|
183641
185476
|
const fused = new Map;
|
|
183642
185477
|
for (const list of queryLists) {
|
|
183643
|
-
list.forEach((row, rank) => {
|
|
183644
|
-
const rrf =
|
|
185478
|
+
list.rows.forEach((row, rank) => {
|
|
185479
|
+
const rrf = list.weight / (RRF_K + rank);
|
|
183645
185480
|
const existing = fused.get(row.messageId);
|
|
183646
185481
|
if (existing) {
|
|
183647
185482
|
existing.score += rrf;
|
|
@@ -183651,26 +185486,107 @@ function searchMessages(args) {
|
|
|
183651
185486
|
});
|
|
183652
185487
|
}
|
|
183653
185488
|
for (const entry of fused.values()) {
|
|
183654
|
-
|
|
183655
|
-
|
|
185489
|
+
let best = 0;
|
|
185490
|
+
for (const probe of probes) {
|
|
185491
|
+
const weight = probeWeights.get(probe) ?? 0;
|
|
185492
|
+
if (weight > best && containsProbeVerbatim(entry.row.content, [probe])) {
|
|
185493
|
+
best = weight;
|
|
185494
|
+
}
|
|
185495
|
+
}
|
|
185496
|
+
if (best > 0) {
|
|
185497
|
+
entry.score += best * VERBATIM_RANK_BONUS;
|
|
183656
185498
|
}
|
|
183657
185499
|
}
|
|
183658
185500
|
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);
|
|
183659
|
-
|
|
183660
|
-
return ranked.map((entry) => ({
|
|
185501
|
+
return ranked.map((entry, rank) => ({
|
|
183661
185502
|
source: "message",
|
|
183662
185503
|
content: previewText(entry.row.content),
|
|
183663
|
-
score:
|
|
185504
|
+
score: linearDecayScore(rank, ranked.length),
|
|
183664
185505
|
messageOrdinal: entry.row.messageOrdinal,
|
|
183665
185506
|
messageId: entry.row.messageId,
|
|
183666
185507
|
role: entry.row.role
|
|
183667
185508
|
}));
|
|
183668
185509
|
}
|
|
185510
|
+
function searchCompartmentChunks(args) {
|
|
185511
|
+
if (!args.queryEmbedding || args.limit <= 0)
|
|
185512
|
+
return [];
|
|
185513
|
+
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
185514
|
+
const rows = loadCompartmentChunkEmbeddingsForSearch(args.db, args.sessionId, args.projectPath, args.modelId);
|
|
185515
|
+
if (rows.length === 0)
|
|
185516
|
+
return [];
|
|
185517
|
+
const byCompartment = new Map;
|
|
185518
|
+
for (const row of rows) {
|
|
185519
|
+
if (cutoff !== null && row.endOrdinal > cutoff) {
|
|
185520
|
+
continue;
|
|
185521
|
+
}
|
|
185522
|
+
const score = normalizeCosineScore(cosineSimilarity(args.queryEmbedding, row.vector));
|
|
185523
|
+
if (score <= 0)
|
|
185524
|
+
continue;
|
|
185525
|
+
const existing = byCompartment.get(row.compartmentId);
|
|
185526
|
+
if (!existing || score > existing.score) {
|
|
185527
|
+
byCompartment.set(row.compartmentId, { row, score });
|
|
185528
|
+
}
|
|
185529
|
+
}
|
|
185530
|
+
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 }) => ({
|
|
185531
|
+
source: "compartment",
|
|
185532
|
+
content: previewText(row.title),
|
|
185533
|
+
score: score * SINGLE_SOURCE_PENALTY,
|
|
185534
|
+
compartmentId: row.compartmentId,
|
|
185535
|
+
sessionId: row.sessionId,
|
|
185536
|
+
title: row.title,
|
|
185537
|
+
startOrdinal: row.startOrdinal,
|
|
185538
|
+
endOrdinal: row.endOrdinal,
|
|
185539
|
+
matchType: "semantic"
|
|
185540
|
+
}));
|
|
185541
|
+
}
|
|
185542
|
+
function mergeMessageAndCompartmentResults(args) {
|
|
185543
|
+
if (args.compartments.length === 0)
|
|
185544
|
+
return args.messages;
|
|
185545
|
+
if (args.messages.length === 0)
|
|
185546
|
+
return args.compartments;
|
|
185547
|
+
const fused = new Map;
|
|
185548
|
+
const add = (key, result, score, tieOrdinal) => {
|
|
185549
|
+
const existing = fused.get(key);
|
|
185550
|
+
if (existing) {
|
|
185551
|
+
existing.score += score;
|
|
185552
|
+
return existing;
|
|
185553
|
+
}
|
|
185554
|
+
const entry = { result, score, tieOrdinal, snippetScore: -1 };
|
|
185555
|
+
fused.set(key, entry);
|
|
185556
|
+
return entry;
|
|
185557
|
+
};
|
|
185558
|
+
args.compartments.forEach((compartment, rank) => {
|
|
185559
|
+
add(`compartment:${compartment.compartmentId}`, compartment, 1 / (RRF_K + rank), compartment.startOrdinal);
|
|
185560
|
+
});
|
|
185561
|
+
for (const [rank, message] of args.messages.entries()) {
|
|
185562
|
+
const containing = args.compartments.find((compartment) => message.messageOrdinal >= compartment.startOrdinal && message.messageOrdinal <= compartment.endOrdinal);
|
|
185563
|
+
const contribution = 1 / (RRF_K + rank);
|
|
185564
|
+
if (!containing) {
|
|
185565
|
+
add(`message:${message.messageId}`, message, contribution, message.messageOrdinal);
|
|
185566
|
+
continue;
|
|
185567
|
+
}
|
|
185568
|
+
const entry = add(`compartment:${containing.compartmentId}`, containing, contribution, containing.startOrdinal);
|
|
185569
|
+
if (message.score > entry.snippetScore && entry.result.source === "compartment") {
|
|
185570
|
+
entry.snippetScore = message.score;
|
|
185571
|
+
entry.result = {
|
|
185572
|
+
...entry.result,
|
|
185573
|
+
matchType: "hybrid",
|
|
185574
|
+
snippet: message.content
|
|
185575
|
+
};
|
|
185576
|
+
}
|
|
185577
|
+
}
|
|
185578
|
+
const ranked = [...fused.values()].sort((left, right) => right.score !== left.score ? right.score - left.score : left.tieOrdinal - right.tieOrdinal).slice(0, args.limit);
|
|
185579
|
+
return ranked.map((entry, rank) => ({
|
|
185580
|
+
...entry.result,
|
|
185581
|
+
score: linearDecayScore(rank, ranked.length)
|
|
185582
|
+
}));
|
|
185583
|
+
}
|
|
183669
185584
|
function getSourceBoost(result) {
|
|
183670
185585
|
switch (result.source) {
|
|
183671
185586
|
case "memory":
|
|
183672
185587
|
return MEMORY_SOURCE_BOOST;
|
|
183673
185588
|
case "message":
|
|
185589
|
+
case "compartment":
|
|
183674
185590
|
return MESSAGE_SOURCE_BOOST;
|
|
183675
185591
|
case "git_commit":
|
|
183676
185592
|
return GIT_COMMIT_SOURCE_BOOST;
|
|
@@ -183688,6 +185604,9 @@ function compareUnifiedResults(left, right) {
|
|
|
183688
185604
|
if (left.source === "message" && right.source === "message") {
|
|
183689
185605
|
return left.messageOrdinal - right.messageOrdinal;
|
|
183690
185606
|
}
|
|
185607
|
+
if (left.source === "compartment" && right.source === "compartment") {
|
|
185608
|
+
return left.startOrdinal - right.startOrdinal;
|
|
185609
|
+
}
|
|
183691
185610
|
if (left.source === "git_commit" && right.source === "git_commit") {
|
|
183692
185611
|
return right.committedAtMs - left.committedAtMs;
|
|
183693
185612
|
}
|
|
@@ -183738,10 +185657,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183738
185657
|
const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
|
|
183739
185658
|
const gitCommitsEnabled = options.gitCommitsEnabled ?? false;
|
|
183740
185659
|
const activeSources = resolveSources(options.sources);
|
|
183741
|
-
const
|
|
185660
|
+
const memoryFeatureEnabled = options.memoryEnabled ?? true;
|
|
185661
|
+
const runMemory = activeSources.has("memory") && memoryFeatureEnabled;
|
|
183742
185662
|
const runMessages = activeSources.has("message");
|
|
183743
185663
|
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
183744
|
-
const
|
|
185664
|
+
const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
|
|
185665
|
+
const needsEmbedding = (runMemory || runGitCommits || runCompartmentChunks) && embeddingEnabled && isEmbeddingRuntimeEnabled();
|
|
183745
185666
|
const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error51) => {
|
|
183746
185667
|
log(`[search] query embedding failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
183747
185668
|
return null;
|
|
@@ -183757,6 +185678,24 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183757
185678
|
probes: messageProbes
|
|
183758
185679
|
}) : [];
|
|
183759
185680
|
const queryEmbedding = await queryEmbeddingPromise;
|
|
185681
|
+
const workspace = resolveSearchWorkspaceContext(db, projectPath);
|
|
185682
|
+
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
185683
|
+
const embeddingModelId = embeddingSnapshot?.modelId;
|
|
185684
|
+
const chunkModelId = embeddingSnapshot?.chunkModelId;
|
|
185685
|
+
const compartmentResults = runCompartmentChunks ? searchCompartmentChunks({
|
|
185686
|
+
db,
|
|
185687
|
+
sessionId,
|
|
185688
|
+
projectPath,
|
|
185689
|
+
queryEmbedding,
|
|
185690
|
+
limit: tierLimit,
|
|
185691
|
+
maxOrdinal: options.maxMessageOrdinal,
|
|
185692
|
+
modelId: chunkModelId && chunkModelId !== "off" ? chunkModelId : null
|
|
185693
|
+
}) : [];
|
|
185694
|
+
const messageLikeResults = mergeMessageAndCompartmentResults({
|
|
185695
|
+
messages: messageResults,
|
|
185696
|
+
compartments: compartmentResults,
|
|
185697
|
+
limit: tierLimit
|
|
185698
|
+
});
|
|
183760
185699
|
const [memoryResults, gitCommitResults] = await Promise.all([
|
|
183761
185700
|
runMemory ? searchMemories({
|
|
183762
185701
|
db,
|
|
@@ -183765,6 +185704,8 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183765
185704
|
limit: tierLimit,
|
|
183766
185705
|
memoryEnabled: true,
|
|
183767
185706
|
queryEmbedding,
|
|
185707
|
+
queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null,
|
|
185708
|
+
workspace,
|
|
183768
185709
|
visibleMemoryIds: options.visibleMemoryIds
|
|
183769
185710
|
}) : Promise.resolve([]),
|
|
183770
185711
|
runGitCommits ? Promise.resolve(searchGitCommits({
|
|
@@ -183775,7 +185716,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183775
185716
|
queryEmbedding
|
|
183776
185717
|
})) : Promise.resolve([])
|
|
183777
185718
|
]);
|
|
183778
|
-
const results = [...memoryResults, ...
|
|
185719
|
+
const results = [...memoryResults, ...messageLikeResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
|
|
183779
185720
|
const countRetrievals = options.countRetrievals ?? true;
|
|
183780
185721
|
if (countRetrievals) {
|
|
183781
185722
|
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
@@ -183839,6 +185780,11 @@ function renderFragment(result, charCap) {
|
|
|
183839
185780
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
183840
185781
|
return truncate(compressed, charCap);
|
|
183841
185782
|
}
|
|
185783
|
+
case "compartment": {
|
|
185784
|
+
const source = result.snippet ?? result.title;
|
|
185785
|
+
const compressed = cavemanCompress(source, "ultra");
|
|
185786
|
+
return truncate(compressed, charCap);
|
|
185787
|
+
}
|
|
183842
185788
|
}
|
|
183843
185789
|
}
|
|
183844
185790
|
function buildAutoSearchHint(results, options = {}) {
|
|
@@ -184479,7 +186425,7 @@ function isVisibleNoteReadPart(part) {
|
|
|
184479
186425
|
}
|
|
184480
186426
|
|
|
184481
186427
|
// src/hooks/magic-context/todo-view.ts
|
|
184482
|
-
import { createHash as
|
|
186428
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
184483
186429
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
184484
186430
|
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
184485
186431
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
@@ -184524,7 +186470,7 @@ function buildSyntheticTodoPart(stateJson) {
|
|
|
184524
186470
|
};
|
|
184525
186471
|
}
|
|
184526
186472
|
function computeSyntheticCallId(stateJson) {
|
|
184527
|
-
const hash2 =
|
|
186473
|
+
const hash2 = createHash11("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
184528
186474
|
return `${SYNTHETIC_CALL_ID_PREFIX}${hash2}`;
|
|
184529
186475
|
}
|
|
184530
186476
|
function parseTodoState(stateJson) {
|
|
@@ -184575,15 +186521,25 @@ async function runPostTransformPhase(args) {
|
|
|
184575
186521
|
const emergencyBypassCompartmentGate = forceMaterialization;
|
|
184576
186522
|
const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
184577
186523
|
const materializationRequested = isExplicitFlush || deferredMaterialize;
|
|
184578
|
-
const
|
|
186524
|
+
const m0M1EnabledForFold = args.fullFeatureMode && args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory);
|
|
186525
|
+
const m0HardFoldThisPass = m0M1EnabledForFold && args.m0M1 ? mustMaterialize({
|
|
186526
|
+
db: args.db,
|
|
186527
|
+
sessionId: args.sessionId,
|
|
186528
|
+
state: args.sessionMeta,
|
|
186529
|
+
projectPath: args.m0M1.projectPath,
|
|
186530
|
+
projectDirectory: args.m0M1.projectDirectory,
|
|
186531
|
+
hardSignals: args.m0M1.hardSignals
|
|
186532
|
+
}).value : false;
|
|
186533
|
+
const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning;
|
|
184579
186534
|
const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
|
|
184580
186535
|
const hasPendingUserOps = pendingOps.length > 0;
|
|
184581
|
-
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization) && (!compartmentRunning || emergencyBypassCompartmentGate);
|
|
184582
|
-
const shouldRunHeuristics = (!compartmentRunning || emergencyBypassCompartmentGate) && (materializationRequested || forceMaterialization || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
|
|
186536
|
+
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || emergencyBypassCompartmentGate);
|
|
186537
|
+
const shouldRunHeuristics = (!compartmentRunning || emergencyBypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
|
|
184583
186538
|
const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
|
|
186539
|
+
const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
|
|
184584
186540
|
if (shouldRunHeuristics) {
|
|
184585
186541
|
const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
|
|
184586
|
-
const reason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : subagentRerun ? `scheduler_execute_subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
186542
|
+
const reason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : m0HardFoldThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into known m[0] bust, scheduler=${args.schedulerDecision})` : subagentRerun ? `scheduler_execute_subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
184587
186543
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
|
|
184588
186544
|
}
|
|
184589
186545
|
if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
|
|
@@ -184626,7 +186582,9 @@ async function runPostTransformPhase(args) {
|
|
|
184626
186582
|
logTransformTiming(args.sessionId, "applyHeuristicCleanup", t5, `droppedTools=${cleanup.droppedTools} deduplicatedTools=${cleanup.deduplicatedTools} droppedInjections=${cleanup.droppedInjections} compressedTextTags=${cleanup.compressedTextTags}`);
|
|
184627
186583
|
const t7 = performance.now();
|
|
184628
186584
|
const clearedReasoning = clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge);
|
|
184629
|
-
|
|
186585
|
+
if (canUseEmptySentinels) {
|
|
186586
|
+
stripClearedReasoning(args.messages);
|
|
186587
|
+
}
|
|
184630
186588
|
const strippedInline = stripInlineThinking(args.messages, args.messageTagNumbers, args.clearReasoningAge);
|
|
184631
186589
|
if (clearedReasoning > 0 || strippedInline > 0) {
|
|
184632
186590
|
let maxTag = 0;
|
|
@@ -184672,7 +186630,6 @@ async function runPostTransformPhase(args) {
|
|
|
184672
186630
|
if (args.watermark > 0) {
|
|
184673
186631
|
const tWatermarkCleanup = performance.now();
|
|
184674
186632
|
truncateErroredTools(args.messages, args.watermark, args.messageTagNumbers);
|
|
184675
|
-
stripProcessedImages(args.messages, args.watermark, args.messageTagNumbers);
|
|
184676
186633
|
logTransformTiming(args.sessionId, "watermarkCleanup", tWatermarkCleanup);
|
|
184677
186634
|
}
|
|
184678
186635
|
if (shouldApplyPendingOps) {
|
|
@@ -184682,21 +186639,40 @@ async function runPostTransformPhase(args) {
|
|
|
184682
186639
|
sessionLog(args.sessionId, "transform failed applying pending operations:", error51);
|
|
184683
186640
|
updateSessionMeta(args.db, args.sessionId, { lastTransformError: getErrorMessage(error51) });
|
|
184684
186641
|
}
|
|
184685
|
-
|
|
184686
|
-
|
|
184687
|
-
|
|
184688
|
-
|
|
184689
|
-
|
|
184690
|
-
|
|
184691
|
-
|
|
184692
|
-
|
|
184693
|
-
|
|
186642
|
+
if (canUseEmptySentinels) {
|
|
186643
|
+
try {
|
|
186644
|
+
const t8 = performance.now();
|
|
186645
|
+
const frozenStaleReduceIds = getStaleReduceStrippedIds(args.db, args.sessionId);
|
|
186646
|
+
const staleReduceResult = dropStaleReduceCalls(args.messages, frozenStaleReduceIds, {
|
|
186647
|
+
detect: isCacheBustingPass,
|
|
186648
|
+
protectedCount: args.protectedTags
|
|
186649
|
+
});
|
|
186650
|
+
if (isCacheBustingPass && staleReduceResult.newlyStrippedIds.length > 0) {
|
|
186651
|
+
addStaleReduceStrippedIds(args.db, args.sessionId, staleReduceResult.newlyStrippedIds);
|
|
186652
|
+
}
|
|
186653
|
+
logTransformTiming(args.sessionId, "dropStaleReduceCalls", t8);
|
|
186654
|
+
} catch (error51) {
|
|
186655
|
+
sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error51);
|
|
184694
186656
|
}
|
|
184695
|
-
logTransformTiming(args.sessionId, "dropStaleReduceCalls", t8);
|
|
184696
|
-
} catch (error51) {
|
|
184697
|
-
sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error51);
|
|
184698
186657
|
}
|
|
184699
|
-
|
|
186658
|
+
if (canUseEmptySentinels && args.watermark > 0) {
|
|
186659
|
+
try {
|
|
186660
|
+
const tImg = performance.now();
|
|
186661
|
+
const frozenImageIds = getProcessedImageStrippedIds(args.db, args.sessionId);
|
|
186662
|
+
const imageResult = stripProcessedImages(args.messages, frozenImageIds, {
|
|
186663
|
+
detect: isCacheBustingPass,
|
|
186664
|
+
watermark: args.watermark,
|
|
186665
|
+
messageTagNumbers: args.messageTagNumbers
|
|
186666
|
+
});
|
|
186667
|
+
if (isCacheBustingPass && imageResult.newlyStrippedIds.length > 0) {
|
|
186668
|
+
addProcessedImageStrippedIds(args.db, args.sessionId, imageResult.newlyStrippedIds);
|
|
186669
|
+
}
|
|
186670
|
+
logTransformTiming(args.sessionId, "stripProcessedImages", tImg);
|
|
186671
|
+
} catch (error51) {
|
|
186672
|
+
sessionLog(args.sessionId, "transform failed stripping processed images:", error51);
|
|
186673
|
+
}
|
|
186674
|
+
}
|
|
186675
|
+
const m0M1Enabled = m0M1EnabledForFold;
|
|
184700
186676
|
if (m0M1Enabled && args.m0M1) {
|
|
184701
186677
|
const tInjectM0M1 = performance.now();
|
|
184702
186678
|
try {
|
|
@@ -184743,7 +186719,7 @@ async function runPostTransformPhase(args) {
|
|
|
184743
186719
|
const tPlaceholder = performance.now();
|
|
184744
186720
|
const persistedIds = getStrippedPlaceholderIds(args.db, args.sessionId);
|
|
184745
186721
|
if (persistedIds.size > 0) {
|
|
184746
|
-
const { replayed, missingIds } = replaySentinelByMessageIds(args.messages, persistedIds, args.
|
|
186722
|
+
const { replayed, missingIds } = replaySentinelByMessageIds(args.messages, persistedIds, args.resolvedProviderID);
|
|
184747
186723
|
if (replayed > 0) {
|
|
184748
186724
|
sessionLog(args.sessionId, `sentinel replay: neutralized ${replayed} previously-stripped messages`);
|
|
184749
186725
|
}
|
|
@@ -184754,9 +186730,9 @@ async function runPostTransformPhase(args) {
|
|
|
184754
186730
|
}
|
|
184755
186731
|
}
|
|
184756
186732
|
if (isCacheBustingPass) {
|
|
184757
|
-
const droppedResult = stripDroppedPlaceholderMessages(args.messages, args.
|
|
186733
|
+
const droppedResult = stripDroppedPlaceholderMessages(args.messages, args.resolvedProviderID);
|
|
184758
186734
|
const protectedTailStart = Math.max(0, args.messages.length - args.protectedTags * 2);
|
|
184759
|
-
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart, args.
|
|
186735
|
+
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart, args.resolvedProviderID);
|
|
184760
186736
|
const newlyNeutralized = droppedResult.sentineledIds.length + systemInjectedResult.sentineledIds.length;
|
|
184761
186737
|
if (newlyNeutralized > 0) {
|
|
184762
186738
|
const addedIds = [
|
|
@@ -184956,6 +186932,7 @@ function clearMessageTokensCache(sessionId, messageId) {
|
|
|
184956
186932
|
if (cache)
|
|
184957
186933
|
cache.delete(messageId);
|
|
184958
186934
|
}
|
|
186935
|
+
var recordedSessionProjectIdentity = new BoundedSessionMap(MESSAGE_TOKENS_CACHE_MAX);
|
|
184959
186936
|
function findLastAssistantModel2(messages) {
|
|
184960
186937
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
184961
186938
|
const info = messages[i].info;
|
|
@@ -185001,11 +186978,13 @@ function createTransform(deps) {
|
|
|
185001
186978
|
}
|
|
185002
186979
|
const reducedMode = sessionMeta.isSubagent;
|
|
185003
186980
|
const fullFeatureMode = !reducedMode;
|
|
185004
|
-
const ctxReduceEnabledEffective = deps.ctxReduceEnabled !== false;
|
|
186981
|
+
const ctxReduceEnabledEffective = deps.ctxReduceEnabled !== false && resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
|
|
185005
186982
|
let sessionDirectory = deps.directory ?? "";
|
|
186983
|
+
let sessionDirectoryResolvedFromHost = false;
|
|
185006
186984
|
const cachedDirectory = deps.sessionDirectoryBySession?.get(sessionId);
|
|
185007
186985
|
if (cachedDirectory && cachedDirectory.length > 0) {
|
|
185008
186986
|
sessionDirectory = cachedDirectory;
|
|
186987
|
+
sessionDirectoryResolvedFromHost = true;
|
|
185009
186988
|
} else if (deps.client !== undefined) {
|
|
185010
186989
|
try {
|
|
185011
186990
|
const sessionResponse = await deps.client.session.get({ path: { id: sessionId } }).catch(() => null);
|
|
@@ -185013,6 +186992,7 @@ function createTransform(deps) {
|
|
|
185013
186992
|
if (sessionInfo && typeof sessionInfo.directory === "string" && sessionInfo.directory.length > 0) {
|
|
185014
186993
|
sessionDirectory = sessionInfo.directory;
|
|
185015
186994
|
deps.sessionDirectoryBySession?.set(sessionId, sessionDirectory);
|
|
186995
|
+
sessionDirectoryResolvedFromHost = true;
|
|
185016
186996
|
}
|
|
185017
186997
|
} catch {}
|
|
185018
186998
|
}
|
|
@@ -185107,6 +187087,8 @@ function createTransform(deps) {
|
|
|
185107
187087
|
deps.liveModelBySession?.set(sessionId, recovered);
|
|
185108
187088
|
}
|
|
185109
187089
|
}
|
|
187090
|
+
const resolvedProviderID = modelForBudget?.providerID;
|
|
187091
|
+
const canUseEmptySentinels = modelAcceptsEmptyContent(resolvedProviderID);
|
|
185110
187092
|
const resolvedContextLimit = modelForBudget ? resolveTrustedContextLimit(modelForBudget.providerID, modelForBudget.modelID, {
|
|
185111
187093
|
db,
|
|
185112
187094
|
sessionID: sessionId
|
|
@@ -185271,6 +187253,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185271
187253
|
logTransformTiming(sessionId, "emergencyRecoveryBlock", tFirstPass);
|
|
185272
187254
|
const projectIdentity = deps.memoryConfig?.enabled ? resolveProjectIdentity(compartmentDirectory || process.cwd()) : undefined;
|
|
185273
187255
|
const sessionProjectIdentity = projectIdentity ?? (sessionDirectory ? resolveProjectIdentity(sessionDirectory) : deps.projectPath);
|
|
187256
|
+
if (sessionProjectIdentity && sessionDirectoryResolvedFromHost && recordedSessionProjectIdentity.get(sessionId) !== sessionProjectIdentity) {
|
|
187257
|
+
recordSessionProjectIdentity(db, sessionId, sessionProjectIdentity);
|
|
187258
|
+
recordedSessionProjectIdentity.set(sessionId, sessionProjectIdentity);
|
|
187259
|
+
}
|
|
185274
187260
|
let triggerBoundarySnapshot;
|
|
185275
187261
|
if (fullFeatureMode && historianRunnable && !sessionMeta.compartmentInProgress) {
|
|
185276
187262
|
const tTrigger = performance.now();
|
|
@@ -185365,7 +187351,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185365
187351
|
}
|
|
185366
187352
|
}
|
|
185367
187353
|
const t3 = performance.now();
|
|
185368
|
-
const strippedStructuralNoise = stripStructuralNoise(messages);
|
|
187354
|
+
const strippedStructuralNoise = canUseEmptySentinels ? stripStructuralNoise(messages) : 0;
|
|
185369
187355
|
logTransformTiming(sessionId, "stripStructuralNoise", t3, `strippedParts=${strippedStructuralNoise}`);
|
|
185370
187356
|
const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
|
|
185371
187357
|
if (persistedReasoningWatermark > 0) {
|
|
@@ -185386,18 +187372,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185386
187372
|
logTransformTiming(sessionId, "replayCavemanCompression", tCavemanReplay);
|
|
185387
187373
|
}
|
|
185388
187374
|
const t4 = performance.now();
|
|
185389
|
-
const strippedClearedReasoning = stripClearedReasoning(messages);
|
|
187375
|
+
const strippedClearedReasoning = canUseEmptySentinels ? stripClearedReasoning(messages) : 0;
|
|
185390
187376
|
logTransformTiming(sessionId, "stripClearedReasoning", t4, `strippedParts=${strippedClearedReasoning}`);
|
|
185391
187377
|
const tMergeStrip = performance.now();
|
|
185392
|
-
|
|
185393
|
-
if (liveProviderID === undefined) {
|
|
185394
|
-
const recovered = findLastAssistantModelFromOpenCodeDb(sessionId);
|
|
185395
|
-
if (recovered) {
|
|
185396
|
-
liveProviderID = recovered.providerID;
|
|
185397
|
-
deps.liveModelBySession?.set(sessionId, recovered);
|
|
185398
|
-
}
|
|
185399
|
-
}
|
|
185400
|
-
const strippedMergedReasoning = stripReasoningFromMergedAssistants(messages, liveProviderID);
|
|
187378
|
+
const strippedMergedReasoning = stripReasoningFromMergedAssistants(messages, resolvedProviderID);
|
|
185401
187379
|
if (strippedMergedReasoning > 0) {
|
|
185402
187380
|
sessionLog(sessionId, `stripped ${strippedMergedReasoning} reasoning parts from merged assistants (anthropic groupIntoBlocks workaround)`);
|
|
185403
187381
|
}
|
|
@@ -185454,7 +187432,6 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185454
187432
|
logTransformTiming(sessionId, "compartmentPhase", tCompartmentPhase);
|
|
185455
187433
|
const hardModel = deps.liveModelBySession?.get(sessionId);
|
|
185456
187434
|
const hardModelKey = hardModel ? `${hardModel.providerID}/${hardModel.modelID}` : "";
|
|
185457
|
-
const hardToolSetHash = deps.getToolSetHash?.(sessionId) ?? "";
|
|
185458
187435
|
const hardSystemHash = typeof sessionMeta.systemPromptHash === "string" ? sessionMeta.systemPromptHash : "";
|
|
185459
187436
|
let hardTtlMs = 5 * 60 * 1000;
|
|
185460
187437
|
try {
|
|
@@ -185463,7 +187440,6 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185463
187440
|
const hardCacheExpired = sessionMeta.lastResponseTime > 0 && Date.now() - sessionMeta.lastResponseTime >= hardTtlMs;
|
|
185464
187441
|
const m0HardSignals = {
|
|
185465
187442
|
systemHash: hardSystemHash,
|
|
185466
|
-
toolSetHash: hardToolSetHash,
|
|
185467
187443
|
modelKey: hardModelKey,
|
|
185468
187444
|
cacheExpired: hardCacheExpired,
|
|
185469
187445
|
lastResponseTime: sessionMeta.lastResponseTime
|
|
@@ -185518,7 +187494,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185518
187494
|
sessionDirectory,
|
|
185519
187495
|
autoSearch: deps.autoSearch,
|
|
185520
187496
|
cavemanTextCompression: deps.ctxReduceEnabled === false && !reducedMode ? deps.cavemanTextCompression : undefined,
|
|
185521
|
-
|
|
187497
|
+
resolvedProviderID,
|
|
185522
187498
|
historyRefreshSessions: deps.historyRefreshSessions,
|
|
185523
187499
|
m0M1: {
|
|
185524
187500
|
projectPath: projectIdentity,
|
|
@@ -186371,7 +188347,7 @@ function createToolExecuteAfterHook(args) {
|
|
|
186371
188347
|
init_send_session_notification();
|
|
186372
188348
|
|
|
186373
188349
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
186374
|
-
import { createHash as
|
|
188350
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
186375
188351
|
|
|
186376
188352
|
// src/agents/magic-context-prompt.ts
|
|
186377
188353
|
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
@@ -186487,9 +188463,9 @@ Prefer many small targeted operations over one large blanket operation, and keep
|
|
|
186487
188463
|
|
|
186488
188464
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
186489
188465
|
init_logger();
|
|
188466
|
+
await init_storage();
|
|
186490
188467
|
init_key_files_block();
|
|
186491
188468
|
init_read_session_formatting();
|
|
186492
|
-
await init_storage();
|
|
186493
188469
|
var MAGIC_CONTEXT_MARKER = "## Magic Context";
|
|
186494
188470
|
function clearSystemPromptHashSession(sessionId, handleMaps) {
|
|
186495
188471
|
clearKeyFilesCacheForSession(sessionId);
|
|
@@ -186535,9 +188511,10 @@ function createSystemPromptHashHandler(deps) {
|
|
|
186535
188511
|
sessionLog(sessionId, "system-prompt-hash session meta load failed:", error51);
|
|
186536
188512
|
}
|
|
186537
188513
|
const isSubagentSession = sessionMetaEarly?.isSubagent === true;
|
|
186538
|
-
const
|
|
186539
|
-
const
|
|
186540
|
-
const
|
|
188514
|
+
const ctxReduceCallable = resolveCtxReduceAvailability(sessionId);
|
|
188515
|
+
const subagentReduceMode = isSubagentSession && deps.ctxReduceEnabled !== false && ctxReduceCallable;
|
|
188516
|
+
const effectiveCtxReduceEnabled = isSubagentSession ? false : deps.ctxReduceEnabled !== false && ctxReduceCallable;
|
|
188517
|
+
const skipGuidanceForDisabledSubagent = isSubagentSession && (deps.ctxReduceEnabled === false || !ctxReduceCallable);
|
|
186541
188518
|
const fullPrompt = output.system.join(`
|
|
186542
188519
|
`);
|
|
186543
188520
|
if (fullPrompt.length > 0 && !fullPrompt.includes(MAGIC_CONTEXT_MARKER) && !skipGuidanceForDisabledSubagent) {
|
|
@@ -186570,7 +188547,7 @@ function createSystemPromptHashHandler(deps) {
|
|
|
186570
188547
|
`);
|
|
186571
188548
|
if (systemContent.length === 0)
|
|
186572
188549
|
return;
|
|
186573
|
-
const currentHash =
|
|
188550
|
+
const currentHash = createHash12("md5").update(systemContent).digest("hex");
|
|
186574
188551
|
if (!sessionMetaEarly) {
|
|
186575
188552
|
return;
|
|
186576
188553
|
}
|
|
@@ -186831,6 +188808,46 @@ function createMagicContextHook(deps) {
|
|
|
186831
188808
|
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
186832
188809
|
getNotificationParams: (sid) => getLiveNotificationParams(sid, liveModelBySession, variantBySession, agentBySession)
|
|
186833
188810
|
});
|
|
188811
|
+
const executeEmbedHistory = async (sessionId) => {
|
|
188812
|
+
if (deps.config.memory?.enabled === false) {
|
|
188813
|
+
return "Memory is disabled for this project, so there is no semantic embedding to backfill.";
|
|
188814
|
+
}
|
|
188815
|
+
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
188816
|
+
await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
|
|
188817
|
+
const sessionProjectIdentity = resolveProjectIdentity(directory);
|
|
188818
|
+
setRecompStarting({ recompProgressBySession }, sessionId, "Embedding history…", "embed");
|
|
188819
|
+
const outcome = await embedSessionCompartmentChunks(db, sessionProjectIdentity, sessionId, {
|
|
188820
|
+
onProgress: ({ embedded, total }) => {
|
|
188821
|
+
const cur = recompProgressBySession.get(sessionId);
|
|
188822
|
+
if (!cur || cur.phase !== "recomp")
|
|
188823
|
+
return;
|
|
188824
|
+
recompProgressBySession.set(sessionId, {
|
|
188825
|
+
...cur,
|
|
188826
|
+
processedMessages: embedded,
|
|
188827
|
+
totalMessages: total,
|
|
188828
|
+
updatedAt: Date.now()
|
|
188829
|
+
});
|
|
188830
|
+
}
|
|
188831
|
+
});
|
|
188832
|
+
const terminal = (phase, message) => {
|
|
188833
|
+
setRecompTerminal({ recompProgressBySession }, sessionId, phase, message);
|
|
188834
|
+
return message;
|
|
188835
|
+
};
|
|
188836
|
+
switch (outcome.status) {
|
|
188837
|
+
case "nothing":
|
|
188838
|
+
return terminal("done", "All of this session's history is already embedded.");
|
|
188839
|
+
case "disabled":
|
|
188840
|
+
return terminal("skipped", "No embedding provider is configured, so there is nothing to embed.");
|
|
188841
|
+
case "busy":
|
|
188842
|
+
return terminal("skipped", `Embedding is already running for this project — ${outcome.total} compartment${outcome.total === 1 ? "" : "s"} still pending. Try again shortly.`);
|
|
188843
|
+
case "aborted":
|
|
188844
|
+
return terminal("done", `Embedded ${outcome.embedded} of ${outcome.total} compartments before stopping.`);
|
|
188845
|
+
case "stalled":
|
|
188846
|
+
return terminal("skipped", `Embedded ${outcome.embedded} compartments; ${outcome.remaining} could not be embedded (the provider returned no result). Run /ctx-embed-history again to retry them.`);
|
|
188847
|
+
default:
|
|
188848
|
+
return terminal("done", `Embedded ${outcome.embedded} compartment${outcome.embedded === 1 ? "" : "s"} of history for semantic search.`);
|
|
188849
|
+
}
|
|
188850
|
+
};
|
|
186834
188851
|
const sidekickRunnable = isSidekickRunnable(deps.config);
|
|
186835
188852
|
const sidekickConfig = sidekickRunnable ? deps.config.sidekick : undefined;
|
|
186836
188853
|
const transform2 = createTransform({
|
|
@@ -186869,12 +188886,6 @@ function createMagicContextHook(deps) {
|
|
|
186869
188886
|
const model = liveModelBySession.get(sessionId);
|
|
186870
188887
|
return resolveModelKey(model?.providerID, model?.modelID);
|
|
186871
188888
|
},
|
|
186872
|
-
getToolSetHash: (sessionId) => {
|
|
186873
|
-
const model = liveModelBySession.get(sessionId);
|
|
186874
|
-
if (!model)
|
|
186875
|
-
return "";
|
|
186876
|
-
return getCurrentToolSetHash(model.providerID, model.modelID, agentBySession.get(sessionId));
|
|
186877
|
-
},
|
|
186878
188889
|
getFallbackModelId: (sessionId) => {
|
|
186879
188890
|
const model = liveModelBySession.get(sessionId);
|
|
186880
188891
|
return model ? `${model.providerID}/${model.modelID}` : undefined;
|
|
@@ -186991,6 +189002,7 @@ function createMagicContextHook(deps) {
|
|
|
186991
189002
|
},
|
|
186992
189003
|
executeRecomp: historianRunnable ? async (sessionId, options) => runManagedRecomp(buildManagedRecompCtx(sessionId), sessionId, options) : undefined,
|
|
186993
189004
|
runUpgrade: historianRunnable ? async (sessionId) => runManagedUpgrade(buildManagedRecompCtx(sessionId), sessionId) : undefined,
|
|
189005
|
+
executeEmbedHistory,
|
|
186994
189006
|
sendNotification: async (sessionId, text, params) => {
|
|
186995
189007
|
await sendIgnoredMessage(deps.client, sessionId, text, {
|
|
186996
189008
|
...getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
|
|
@@ -188129,6 +190141,7 @@ init_memory();
|
|
|
188129
190141
|
init_embedding();
|
|
188130
190142
|
init_embedding_cache();
|
|
188131
190143
|
init_normalize_hash();
|
|
190144
|
+
init_workspaces();
|
|
188132
190145
|
init_logger();
|
|
188133
190146
|
await init_storage();
|
|
188134
190147
|
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
@@ -188288,6 +190301,23 @@ function createCtxMemoryTool(deps) {
|
|
|
188288
190301
|
}
|
|
188289
190302
|
const projectPath = deps.resolveProjectPath(toolContext.directory);
|
|
188290
190303
|
await deps.ensureProjectRegistered?.(toolContext.directory, deps.db);
|
|
190304
|
+
const workspaceIdentitySet = resolveWorkspaceIdentitySet(deps.db, projectPath);
|
|
190305
|
+
const expandedWorkspace = expandWorkspaceIdentitySetWithAliases(deps.db, workspaceIdentitySet.identities);
|
|
190306
|
+
const workspaceVisibleIdentities = workspaceIdentitySet.identities.length > 1 ? expandedWorkspace.expandedIdentities : workspaceIdentitySet.identities;
|
|
190307
|
+
const targetIdentityForStoredPath = (rawProjectPath) => workspaceIdentitySet.identities.length > 1 ? resolveStoredPathWorkspaceIdentity(rawProjectPath, workspaceIdentitySet.identities, expandedWorkspace.canonicalIdentityByStoredPath) ?? projectIdentityForStoredPath(rawProjectPath) : projectIdentityForStoredPath(rawProjectPath);
|
|
190308
|
+
const toolShareCategories = workspaceIdentitySet.identities.length > 1 ? resolveWorkspaceShareCategories(deps.db, projectPath) : null;
|
|
190309
|
+
const memoryVisibleToTool = (memory) => {
|
|
190310
|
+
if (workspaceIdentitySet.identities.length <= 1) {
|
|
190311
|
+
return memoryBelongsToProject(memory, projectPath);
|
|
190312
|
+
}
|
|
190313
|
+
if (!storedPathBelongsToWorkspace(memory.projectPath, workspaceIdentitySet.identities, workspaceVisibleIdentities, expandedWorkspace.canonicalIdentityByStoredPath)) {
|
|
190314
|
+
return false;
|
|
190315
|
+
}
|
|
190316
|
+
const isOwn = targetIdentityForStoredPath(memory.projectPath) === projectPath;
|
|
190317
|
+
if (isOwn)
|
|
190318
|
+
return true;
|
|
190319
|
+
return toolShareCategories === null || toolShareCategories.includes(memory.category);
|
|
190320
|
+
};
|
|
188291
190321
|
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
188292
190322
|
if (embeddingSnapshot ? !embeddingSnapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
188293
190323
|
return getDisabledMessage();
|
|
@@ -188344,18 +190374,18 @@ function createCtxMemoryTool(deps) {
|
|
|
188344
190374
|
}
|
|
188345
190375
|
const rawProjectPath = projectPathForMemoryId(deps.db, updateId);
|
|
188346
190376
|
const memory = getMemoryById(deps.db, updateId);
|
|
188347
|
-
if (!memory || !rawProjectPath || !
|
|
190377
|
+
if (!memory || !rawProjectPath || !memoryVisibleToTool(memory)) {
|
|
188348
190378
|
return `Error: Memory with ID ${updateId} was not found.`;
|
|
188349
190379
|
}
|
|
188350
190380
|
if (toolContext.agent !== DREAMER_AGENT && !isPrimaryMutableMemory(memory)) {
|
|
188351
190381
|
return inactiveMemoryError(updateId, "updating");
|
|
188352
190382
|
}
|
|
188353
190383
|
const normalizedHash = computeNormalizedHash(content);
|
|
188354
|
-
const duplicate = getMemoryByHash(deps.db,
|
|
190384
|
+
const duplicate = getMemoryByHash(deps.db, targetIdentityForStoredPath(rawProjectPath), memory.category, normalizedHash);
|
|
188355
190385
|
if (duplicate && duplicate.id !== memory.id) {
|
|
188356
190386
|
return `Error: Memory content already exists as ID ${duplicate.id}; merge or archive duplicates instead.`;
|
|
188357
190387
|
}
|
|
188358
|
-
const projectIdentity =
|
|
190388
|
+
const projectIdentity = targetIdentityForStoredPath(rawProjectPath);
|
|
188359
190389
|
deps.db.transaction(() => {
|
|
188360
190390
|
updateMemoryContentInCurrentTransaction(deps.db, memory, content, normalizedHash);
|
|
188361
190391
|
queueMemoryMutation(deps.db, {
|
|
@@ -188369,7 +190399,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188369
190399
|
queueMemoryEmbedding({
|
|
188370
190400
|
deps,
|
|
188371
190401
|
sessionId: toolContext.sessionID,
|
|
188372
|
-
projectPath,
|
|
190402
|
+
projectPath: projectIdentity,
|
|
188373
190403
|
memoryId: memory.id,
|
|
188374
190404
|
content
|
|
188375
190405
|
});
|
|
@@ -188392,7 +190422,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188392
190422
|
return "Error: One or more source memories were not found.";
|
|
188393
190423
|
}
|
|
188394
190424
|
if (toolContext.agent !== DREAMER_AGENT) {
|
|
188395
|
-
const foreign = sourceMemories.find((memory) => !
|
|
190425
|
+
const foreign = sourceMemories.find((memory) => !memoryVisibleToTool(memory));
|
|
188396
190426
|
if (foreign) {
|
|
188397
190427
|
return `Error: Memory with ID ${foreign.id} was not found.`;
|
|
188398
190428
|
}
|
|
@@ -188476,15 +190506,16 @@ function createCtxMemoryTool(deps) {
|
|
|
188476
190506
|
return `Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`;
|
|
188477
190507
|
}
|
|
188478
190508
|
if (args.action === "archive") {
|
|
188479
|
-
const
|
|
188480
|
-
if (!
|
|
190509
|
+
const rawArchiveIds = args.ids;
|
|
190510
|
+
if (!rawArchiveIds || rawArchiveIds.length === 0 || !rawArchiveIds.every(Number.isInteger)) {
|
|
188481
190511
|
return "Error: 'ids' must contain at least one integer memory ID when action is 'archive'.";
|
|
188482
190512
|
}
|
|
190513
|
+
const archiveIds = [...new Set(rawArchiveIds)];
|
|
188483
190514
|
const targets = [];
|
|
188484
190515
|
for (const memoryId of archiveIds) {
|
|
188485
190516
|
const rawProjectPath = projectPathForMemoryId(deps.db, memoryId);
|
|
188486
190517
|
const memory = getMemoryById(deps.db, memoryId);
|
|
188487
|
-
if (!memory || !rawProjectPath || !
|
|
190518
|
+
if (!memory || !rawProjectPath || !memoryVisibleToTool(memory)) {
|
|
188488
190519
|
return `Error: Memory with ID ${memoryId} was not found.`;
|
|
188489
190520
|
}
|
|
188490
190521
|
if (toolContext.agent !== DREAMER_AGENT && !isPrimaryMutableMemory(memory)) {
|
|
@@ -188492,7 +190523,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188492
190523
|
}
|
|
188493
190524
|
targets.push({
|
|
188494
190525
|
memoryId,
|
|
188495
|
-
projectIdentity:
|
|
190526
|
+
projectIdentity: targetIdentityForStoredPath(rawProjectPath)
|
|
188496
190527
|
});
|
|
188497
190528
|
}
|
|
188498
190529
|
deps.db.transaction(() => {
|
|
@@ -188966,8 +190997,9 @@ function formatAge2(committedAtMs) {
|
|
|
188966
190997
|
}
|
|
188967
190998
|
function formatResult(result, index) {
|
|
188968
190999
|
if (result.source === "memory") {
|
|
191000
|
+
const source = result.sourceName ? ` source=${result.sourceName}` : "";
|
|
188969
191001
|
return [
|
|
188970
|
-
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category} match=${result.matchType}`,
|
|
191002
|
+
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category}${source} match=${result.matchType}`,
|
|
188971
191003
|
result.content
|
|
188972
191004
|
].join(`
|
|
188973
191005
|
`);
|
|
@@ -188977,6 +191009,13 @@ function formatResult(result, index) {
|
|
|
188977
191009
|
`[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge2(result.committedAtMs)} match=${result.matchType}`,
|
|
188978
191010
|
result.content
|
|
188979
191011
|
].join(`
|
|
191012
|
+
`);
|
|
191013
|
+
}
|
|
191014
|
+
if (result.source === "compartment") {
|
|
191015
|
+
return [
|
|
191016
|
+
`[${index}] [message] score=${result.score.toFixed(2)} compartment_id=${result.compartmentId} range=${result.startOrdinal}-${result.endOrdinal} match=${result.matchType} title=${result.title}`,
|
|
191017
|
+
result.snippet ? `Snippet: ${result.snippet}` : result.content
|
|
191018
|
+
].join(`
|
|
188980
191019
|
`);
|
|
188981
191020
|
}
|
|
188982
191021
|
const expandStart = Math.max(1, result.messageOrdinal - 3);
|
|
@@ -188992,7 +191031,7 @@ function formatSearchResults(query, results) {
|
|
|
188992
191031
|
return `No results found for "${query}" across memories, git commits, or message history.`;
|
|
188993
191032
|
}
|
|
188994
191033
|
const bodyParts = results.map((result, index) => formatResult(result, index + 1));
|
|
188995
|
-
if (results.some((result) => result.source === "message")) {
|
|
191034
|
+
if (results.some((result) => result.source === "message" || result.source === "compartment")) {
|
|
188996
191035
|
bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
|
|
188997
191036
|
}
|
|
188998
191037
|
const body = bodyParts.join(`
|
|
@@ -189150,11 +191189,11 @@ import { createServer } from "node:http";
|
|
|
189150
191189
|
import { dirname as dirname5 } from "node:path";
|
|
189151
191190
|
|
|
189152
191191
|
// src/shared/rpc-utils.ts
|
|
189153
|
-
import { createHash as
|
|
191192
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
189154
191193
|
import { join as join20 } from "node:path";
|
|
189155
191194
|
function projectHash(directory) {
|
|
189156
191195
|
const normalized = directory.replace(/\/+$/, "");
|
|
189157
|
-
return
|
|
191196
|
+
return createHash13("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
189158
191197
|
}
|
|
189159
191198
|
function rpcPortDir(storageDir, directory) {
|
|
189160
191199
|
return join20(storageDir, "rpc", projectHash(directory));
|