@wolfx/opencode-magic-context 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 -1
- 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/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/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/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +23 -3
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- 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/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.map +1 -1
- package/dist/index.js +2304 -302
- 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 = ?,
|
|
@@ -15975,7 +15981,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
15975
15981
|
cached_m0_upgrade_state = ?,
|
|
15976
15982
|
cached_m0_system_hash = ?,
|
|
15977
15983
|
cached_m0_model_key = ?
|
|
15978
|
-
WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.modelKey ?? "", sessionId);
|
|
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);
|
|
15979
15985
|
}
|
|
15980
15986
|
function clearCachedM0M1(db, sessionId) {
|
|
15981
15987
|
ensureSessionMetaRow(db, sessionId);
|
|
@@ -15984,6 +15990,7 @@ function clearCachedM0M1(db, sessionId) {
|
|
|
15984
15990
|
["cached_m0_bytes", null],
|
|
15985
15991
|
["cached_m1_bytes", null],
|
|
15986
15992
|
["cached_m0_project_memory_epoch", null],
|
|
15993
|
+
["cached_m0_workspace_fingerprint", null],
|
|
15987
15994
|
["cached_m0_project_user_profile_version", null],
|
|
15988
15995
|
["cached_m0_max_compartment_seq", null],
|
|
15989
15996
|
["cached_m0_max_memory_id", null],
|
|
@@ -16039,6 +16046,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16039
16046
|
"cached_m0_bytes",
|
|
16040
16047
|
"cached_m1_bytes",
|
|
16041
16048
|
"cached_m0_project_memory_epoch",
|
|
16049
|
+
"cached_m0_workspace_fingerprint",
|
|
16042
16050
|
"cached_m0_project_user_profile_version",
|
|
16043
16051
|
"cached_m0_max_compartment_seq",
|
|
16044
16052
|
"cached_m0_max_memory_id",
|
|
@@ -16086,6 +16094,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16086
16094
|
cachedM0Bytes: "cached_m0_bytes",
|
|
16087
16095
|
cachedM1Bytes: "cached_m1_bytes",
|
|
16088
16096
|
cachedM0ProjectMemoryEpoch: "cached_m0_project_memory_epoch",
|
|
16097
|
+
cachedM0WorkspaceFingerprint: "cached_m0_workspace_fingerprint",
|
|
16089
16098
|
cachedM0ProjectUserProfileVersion: "cached_m0_project_user_profile_version",
|
|
16090
16099
|
cachedM0MaxCompartmentSeq: "cached_m0_max_compartment_seq",
|
|
16091
16100
|
cachedM0MaxMemoryId: "cached_m0_max_memory_id",
|
|
@@ -16115,6 +16124,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16115
16124
|
"cachedM0Bytes",
|
|
16116
16125
|
"cachedM1Bytes",
|
|
16117
16126
|
"cachedM0ProjectMemoryEpoch",
|
|
16127
|
+
"cachedM0WorkspaceFingerprint",
|
|
16118
16128
|
"cachedM0ProjectUserProfileVersion",
|
|
16119
16129
|
"cachedM0MaxCompartmentSeq",
|
|
16120
16130
|
"cachedM0MaxMemoryId",
|
|
@@ -150826,6 +150836,35 @@ function initializeDatabase(db) {
|
|
|
150826
150836
|
);
|
|
150827
150837
|
CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
|
|
150828
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
|
+
|
|
150829
150868
|
CREATE TABLE IF NOT EXISTS compartment_events (
|
|
150830
150869
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
150831
150870
|
session_id TEXT NOT NULL,
|
|
@@ -151011,6 +151050,25 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151011
151050
|
rekeyed_at INTEGER NOT NULL
|
|
151012
151051
|
);
|
|
151013
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
|
+
|
|
151014
151072
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
151015
151073
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151016
151074
|
table_name TEXT NOT NULL,
|
|
@@ -151122,6 +151180,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151122
151180
|
deferred_execute_state TEXT,
|
|
151123
151181
|
cached_m0_bytes BLOB,
|
|
151124
151182
|
cached_m0_project_memory_epoch INTEGER,
|
|
151183
|
+
cached_m0_workspace_fingerprint TEXT,
|
|
151125
151184
|
cached_m0_project_user_profile_version INTEGER,
|
|
151126
151185
|
cached_m0_max_compartment_seq INTEGER,
|
|
151127
151186
|
cached_m0_max_memory_id INTEGER,
|
|
@@ -151280,6 +151339,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151280
151339
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
151281
151340
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
151282
151341
|
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
151342
|
+
ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
|
|
151283
151343
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
151284
151344
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
151285
151345
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -151333,6 +151393,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151333
151393
|
ensureColumn(db, "memories", "importance", "INTEGER");
|
|
151334
151394
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
151335
151395
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
151396
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
151336
151397
|
ensureColumn(db, "session_meta", "cached_m0_project_user_profile_version", "INTEGER");
|
|
151337
151398
|
ensureColumn(db, "session_meta", "cached_m0_max_compartment_seq", "INTEGER");
|
|
151338
151399
|
ensureColumn(db, "session_meta", "cached_m0_max_memory_id", "INTEGER");
|
|
@@ -151364,6 +151425,15 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151364
151425
|
project_user_profile_version INTEGER NOT NULL DEFAULT 0,
|
|
151365
151426
|
updated_at INTEGER NOT NULL DEFAULT 0
|
|
151366
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);
|
|
151367
151437
|
CREATE TABLE IF NOT EXISTS m0_mutation_log (
|
|
151368
151438
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151369
151439
|
session_id TEXT NOT NULL,
|
|
@@ -151391,6 +151461,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151391
151461
|
new_project_path TEXT NOT NULL,
|
|
151392
151462
|
rekeyed_at INTEGER NOT NULL
|
|
151393
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);
|
|
151394
151481
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
151395
151482
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151396
151483
|
table_name TEXT NOT NULL,
|
|
@@ -151412,6 +151499,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151412
151499
|
ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151413
151500
|
ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151414
151501
|
ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151502
|
+
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
151415
151503
|
}
|
|
151416
151504
|
function healAllNullColumns(db) {
|
|
151417
151505
|
healNullTextColumns(db);
|
|
@@ -151449,6 +151537,7 @@ function healNullTextColumns(db) {
|
|
|
151449
151537
|
["system_prompt_hash", ""],
|
|
151450
151538
|
["stripped_placeholder_ids", ""],
|
|
151451
151539
|
["stale_reduce_stripped_ids", ""],
|
|
151540
|
+
["processed_image_stripped_ids", ""],
|
|
151452
151541
|
["memory_block_cache", ""],
|
|
151453
151542
|
["memory_block_ids", ""],
|
|
151454
151543
|
["compaction_marker_state", ""],
|
|
@@ -151493,7 +151582,7 @@ function healNullIntegerColumns(db) {
|
|
|
151493
151582
|
}
|
|
151494
151583
|
}
|
|
151495
151584
|
function ensureColumn(db, table, column, definition) {
|
|
151496
|
-
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)) {
|
|
151497
151586
|
throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
|
|
151498
151587
|
}
|
|
151499
151588
|
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
@@ -151579,7 +151668,7 @@ function getDatabasePersistenceError(db) {
|
|
|
151579
151668
|
return null;
|
|
151580
151669
|
return persistenceErrorByDatabase.get(db) ?? null;
|
|
151581
151670
|
}
|
|
151582
|
-
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;
|
|
151583
151672
|
var init_storage_db = __esm(async () => {
|
|
151584
151673
|
init_data_path();
|
|
151585
151674
|
init_logger();
|
|
@@ -151599,10 +151688,302 @@ var init_storage_db = __esm(async () => {
|
|
|
151599
151688
|
};
|
|
151600
151689
|
});
|
|
151601
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
|
+
|
|
151602
151979
|
// src/features/magic-context/migrations.ts
|
|
151603
|
-
function
|
|
151980
|
+
function tableExists2(db, name2) {
|
|
151604
151981
|
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name2));
|
|
151605
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
|
+
}
|
|
151606
151987
|
function ensureMigrationsTable(db) {
|
|
151607
151988
|
db.exec(`
|
|
151608
151989
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
@@ -151671,6 +152052,7 @@ function runMigrations(db) {
|
|
|
151671
152052
|
var MIGRATIONS, LATEST_MIGRATION_VERSION;
|
|
151672
152053
|
var init_migrations = __esm(async () => {
|
|
151673
152054
|
init_logger();
|
|
152055
|
+
init_workspaces();
|
|
151674
152056
|
await init_storage_db();
|
|
151675
152057
|
MIGRATIONS = [
|
|
151676
152058
|
{
|
|
@@ -152130,9 +152512,9 @@ var init_migrations = __esm(async () => {
|
|
|
152130
152512
|
version: 22,
|
|
152131
152513
|
description: "v2.0 cache architecture schema foundation",
|
|
152132
152514
|
up: (db) => {
|
|
152133
|
-
const hasSessionMetaTable =
|
|
152134
|
-
const hasCompartmentsTable =
|
|
152135
|
-
const hasMemoriesTable =
|
|
152515
|
+
const hasSessionMetaTable = tableExists2(db, "session_meta");
|
|
152516
|
+
const hasCompartmentsTable = tableExists2(db, "compartments");
|
|
152517
|
+
const hasMemoriesTable = tableExists2(db, "memories");
|
|
152136
152518
|
if (hasSessionMetaTable) {
|
|
152137
152519
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
152138
152520
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
@@ -152157,7 +152539,7 @@ var init_migrations = __esm(async () => {
|
|
|
152157
152539
|
ensureColumn(db, "compartments", "p1_embedding_model_id", "TEXT");
|
|
152158
152540
|
ensureColumn(db, "compartments", "legacy", "INTEGER NOT NULL DEFAULT 0");
|
|
152159
152541
|
}
|
|
152160
|
-
const hasRecompCompartmentsTable =
|
|
152542
|
+
const hasRecompCompartmentsTable = tableExists2(db, "recomp_compartments");
|
|
152161
152543
|
if (hasRecompCompartmentsTable) {
|
|
152162
152544
|
ensureColumn(db, "recomp_compartments", "p1", "TEXT");
|
|
152163
152545
|
ensureColumn(db, "recomp_compartments", "p2", "TEXT");
|
|
@@ -152468,13 +152850,163 @@ var init_migrations = __esm(async () => {
|
|
|
152468
152850
|
db.prepare("UPDATE session_meta SET force_emergency_bypass_used = 0 WHERE force_emergency_bypass_used IS NULL").run();
|
|
152469
152851
|
db.prepare("UPDATE session_meta SET last_usage_context_limit = 0 WHERE last_usage_context_limit IS NULL").run();
|
|
152470
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
|
+
}
|
|
152471
153003
|
}
|
|
152472
153004
|
];
|
|
152473
153005
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
152474
153006
|
});
|
|
152475
153007
|
|
|
152476
153008
|
// src/features/magic-context/project-docs-hash.ts
|
|
152477
|
-
import { createHash as
|
|
153009
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
152478
153010
|
import { lstatSync, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
|
|
152479
153011
|
import path4 from "node:path";
|
|
152480
153012
|
function canonicalizeDocContent(raw) {
|
|
@@ -152564,7 +153096,7 @@ function hashCanonicalPieces(hashPieces) {
|
|
|
152564
153096
|
if (hashPieces.length === 0) {
|
|
152565
153097
|
return "";
|
|
152566
153098
|
}
|
|
152567
|
-
return
|
|
153099
|
+
return createHash5("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
|
|
152568
153100
|
}
|
|
152569
153101
|
function readProjectDocsCanonical(projectDirectory) {
|
|
152570
153102
|
const canonicalDirectory = path4.resolve(projectDirectory);
|
|
@@ -152602,11 +153134,6 @@ var init_project_docs_hash = __esm(() => {
|
|
|
152602
153134
|
MAX_PROJECT_DOC_BYTES = 256 * 1024;
|
|
152603
153135
|
docsCache = new Map;
|
|
152604
153136
|
});
|
|
152605
|
-
|
|
152606
|
-
// src/features/magic-context/project-identity.ts
|
|
152607
|
-
var init_project_identity2 = __esm(() => {
|
|
152608
|
-
init_project_identity();
|
|
152609
|
-
});
|
|
152610
153137
|
// src/features/magic-context/storage-m0-mutation-log.ts
|
|
152611
153138
|
function assertMutationType(mutationType) {
|
|
152612
153139
|
if (!M0_MUTATION_TYPES.has(mutationType)) {
|
|
@@ -152691,18 +153218,13 @@ function getMemoryMutation(db, id) {
|
|
|
152691
153218
|
WHERE id = ?`).get(id);
|
|
152692
153219
|
return row ? toMemoryMutation(row) : null;
|
|
152693
153220
|
}
|
|
152694
|
-
function
|
|
152695
|
-
|
|
152696
|
-
|
|
152697
|
-
|
|
152698
|
-
|
|
152699
|
-
|
|
152700
|
-
|
|
152701
|
-
FROM memory_mutation_log
|
|
152702
|
-
WHERE project_path = ?
|
|
152703
|
-
AND id > ?
|
|
152704
|
-
AND target_memory_id IN (${placeholders})
|
|
152705
|
-
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) {
|
|
152706
153228
|
const chosenByTarget = new Map;
|
|
152707
153229
|
for (const dbRow of rows) {
|
|
152708
153230
|
const candidate = toMemoryMutation(dbRow);
|
|
@@ -152723,10 +153245,54 @@ function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds
|
|
|
152723
153245
|
}
|
|
152724
153246
|
return [...chosenByTarget.values()].sort((left, right) => left.id - right.id);
|
|
152725
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
|
+
}
|
|
152726
153281
|
function getMaxMemoryMutationId(db, projectPath) {
|
|
152727
153282
|
const row = db.prepare("SELECT MAX(id) AS max_id FROM memory_mutation_log WHERE project_path = ?").get(projectPath);
|
|
152728
153283
|
return row?.max_id ?? null;
|
|
152729
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
|
+
}
|
|
152730
153296
|
var MEMORY_MUTATION_TYPES, TERMINAL_MUTATION_TYPES;
|
|
152731
153297
|
var init_storage_memory_mutation_log = __esm(() => {
|
|
152732
153298
|
MEMORY_MUTATION_TYPES = new Set(["archive", "delete", "update", "superseded"]);
|
|
@@ -153419,6 +153985,36 @@ function addStaleReduceStrippedIds(db, sessionId, ids) {
|
|
|
153419
153985
|
sessionLog(sessionId, `stale_reduce_stripped_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
153420
153986
|
return false;
|
|
153421
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
|
+
}
|
|
153422
154018
|
function isPendingCompactionMarker(value) {
|
|
153423
154019
|
return typeof value === "object" && value !== null && typeof value.ordinal === "number" && typeof value.endMessageId === "string" && typeof value.publishedAt === "number";
|
|
153424
154020
|
}
|
|
@@ -153597,6 +154193,8 @@ function clearSession(db, sessionId) {
|
|
|
153597
154193
|
db.prepare("DELETE FROM source_contents WHERE session_id = ?").run(sessionId);
|
|
153598
154194
|
db.prepare("DELETE FROM tags WHERE session_id = ?").run(sessionId);
|
|
153599
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);
|
|
153600
154198
|
db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
|
|
153601
154199
|
clearCompressionDepth(db, sessionId);
|
|
153602
154200
|
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
@@ -153703,9 +154301,9 @@ function buildStatusClause(status) {
|
|
|
153703
154301
|
if (statuses.length === 0) {
|
|
153704
154302
|
return null;
|
|
153705
154303
|
}
|
|
153706
|
-
const
|
|
154304
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
153707
154305
|
return {
|
|
153708
|
-
sql: `status IN (${
|
|
154306
|
+
sql: `status IN (${placeholders3})`,
|
|
153709
154307
|
params: statuses
|
|
153710
154308
|
};
|
|
153711
154309
|
}
|
|
@@ -153911,19 +154509,6 @@ function getProjectState(db, projectPath) {
|
|
|
153911
154509
|
WHERE project_path = ?`).get(projectPath);
|
|
153912
154510
|
return row ? toProjectState(row) : null;
|
|
153913
154511
|
}
|
|
153914
|
-
function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
|
|
153915
|
-
db.prepare(`INSERT INTO project_state
|
|
153916
|
-
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
153917
|
-
VALUES (?, 1, 0, ?)
|
|
153918
|
-
ON CONFLICT(project_path) DO UPDATE SET
|
|
153919
|
-
project_memory_epoch = project_memory_epoch + 1,
|
|
153920
|
-
updated_at = excluded.updated_at`).run(projectPath, now);
|
|
153921
|
-
const state = getProjectState(db, projectPath);
|
|
153922
|
-
if (!state) {
|
|
153923
|
-
throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
|
|
153924
|
-
}
|
|
153925
|
-
return state;
|
|
153926
|
-
}
|
|
153927
154512
|
function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PROJECT_PATH, now = Date.now()) {
|
|
153928
154513
|
db.prepare(`INSERT INTO project_state
|
|
153929
154514
|
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
@@ -153959,8 +154544,8 @@ function getSourceContents(db, sessionId, tagIds) {
|
|
|
153959
154544
|
if (tagIds.length === 0) {
|
|
153960
154545
|
return new Map;
|
|
153961
154546
|
}
|
|
153962
|
-
const
|
|
153963
|
-
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);
|
|
153964
154549
|
const sources = new Map;
|
|
153965
154550
|
for (const row of rows) {
|
|
153966
154551
|
sources.set(row.tag_id, row.content);
|
|
@@ -154270,8 +154855,8 @@ function getTagsByNumbers(db, sessionId, tagNumbers) {
|
|
|
154270
154855
|
}
|
|
154271
154856
|
return all;
|
|
154272
154857
|
}
|
|
154273
|
-
const
|
|
154274
|
-
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);
|
|
154275
154860
|
return rows.map(toTagEntry);
|
|
154276
154861
|
}
|
|
154277
154862
|
function getMaxDroppedTagNumber(db, sessionId) {
|
|
@@ -154424,6 +155009,7 @@ var init_storage = __esm(async () => {
|
|
|
154424
155009
|
init_storage_source();
|
|
154425
155010
|
init_storage_tags();
|
|
154426
155011
|
init_storage_v22_backfill_failures();
|
|
155012
|
+
init_workspaces();
|
|
154427
155013
|
await __promiseAll([
|
|
154428
155014
|
init_message_index(),
|
|
154429
155015
|
init_migrations(),
|
|
@@ -163875,7 +164461,7 @@ function isEmbeddingRow(row) {
|
|
|
163875
164461
|
if (row === null || typeof row !== "object")
|
|
163876
164462
|
return false;
|
|
163877
164463
|
const candidate = row;
|
|
163878
|
-
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding);
|
|
164464
|
+
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding) && (candidate.modelId === null || typeof candidate.modelId === "string");
|
|
163879
164465
|
}
|
|
163880
164466
|
function toFloat32Array(blob) {
|
|
163881
164467
|
if (blob instanceof Uint8Array) {
|
|
@@ -163895,7 +164481,7 @@ function getSaveEmbeddingStatement(db) {
|
|
|
163895
164481
|
function getLoadAllEmbeddingsStatement(db) {
|
|
163896
164482
|
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
163897
164483
|
if (!stmt) {
|
|
163898
|
-
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");
|
|
163899
164485
|
loadAllEmbeddingsStatements.set(db, stmt);
|
|
163900
164486
|
}
|
|
163901
164487
|
return stmt;
|
|
@@ -163924,7 +164510,10 @@ function loadAllEmbeddings(db, projectPath) {
|
|
|
163924
164510
|
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath).filter(isEmbeddingRow);
|
|
163925
164511
|
const embeddings = new Map;
|
|
163926
164512
|
for (const row of rows) {
|
|
163927
|
-
embeddings.set(row.memoryId,
|
|
164513
|
+
embeddings.set(row.memoryId, {
|
|
164514
|
+
embedding: toFloat32Array(row.embedding),
|
|
164515
|
+
modelId: row.modelId
|
|
164516
|
+
});
|
|
163928
164517
|
}
|
|
163929
164518
|
return embeddings;
|
|
163930
164519
|
}
|
|
@@ -163987,13 +164576,13 @@ var init_embedding_cache = __esm(() => {
|
|
|
163987
164576
|
});
|
|
163988
164577
|
|
|
163989
164578
|
// src/features/magic-context/memory/normalize-hash.ts
|
|
163990
|
-
import { createHash as
|
|
164579
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
163991
164580
|
function normalizeMemoryContent(content) {
|
|
163992
164581
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
163993
164582
|
}
|
|
163994
164583
|
function computeNormalizedHash(content) {
|
|
163995
164584
|
const normalized = normalizeMemoryContent(content);
|
|
163996
|
-
return
|
|
164585
|
+
return createHash7("md5").update(normalized).digest("hex");
|
|
163997
164586
|
}
|
|
163998
164587
|
var init_normalize_hash = () => {};
|
|
163999
164588
|
|
|
@@ -164107,8 +164696,8 @@ function getMemoriesByProjectStatement(db, statuses) {
|
|
|
164107
164696
|
}
|
|
164108
164697
|
let stmt = statements.get(db);
|
|
164109
164698
|
if (!stmt) {
|
|
164110
|
-
const
|
|
164111
|
-
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`);
|
|
164112
164701
|
statements.set(db, stmt);
|
|
164113
164702
|
}
|
|
164114
164703
|
return stmt;
|
|
@@ -164229,6 +164818,97 @@ function getMemoriesByProject(db, projectPath, statuses = ["active", "permanent"
|
|
|
164229
164818
|
const rows = getMemoriesByProjectStatement(db, statuses).all(projectPath, ...statuses, expiryCutoff).filter(isMemoryRow);
|
|
164230
164819
|
return rows.map(toMemory);
|
|
164231
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
|
+
}
|
|
164232
164912
|
function getAllActiveMemoriesForMigration(db, projectPath) {
|
|
164233
164913
|
const rows = getActiveMemoriesNoExpiryStatement(db).all(projectPath).filter(isMemoryRow);
|
|
164234
164914
|
return rows.map(toMemory);
|
|
@@ -164326,6 +165006,7 @@ function getMemoryCountsByStatus(db, projectPath) {
|
|
|
164326
165006
|
}
|
|
164327
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;
|
|
164328
165008
|
var init_storage_memory = __esm(() => {
|
|
165009
|
+
init_constants();
|
|
164329
165010
|
init_embedding_cache();
|
|
164330
165011
|
init_normalize_hash();
|
|
164331
165012
|
COLUMN_MAP = {
|
|
@@ -164431,8 +165112,8 @@ function getUserMemoryCandidates(db) {
|
|
|
164431
165112
|
function deleteUserMemoryCandidates(db, ids) {
|
|
164432
165113
|
if (ids.length === 0)
|
|
164433
165114
|
return;
|
|
164434
|
-
const
|
|
164435
|
-
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);
|
|
164436
165117
|
}
|
|
164437
165118
|
function insertUserMemory(db, content, sourceCandidateIds) {
|
|
164438
165119
|
const now = Date.now();
|
|
@@ -164465,6 +165146,444 @@ function parseUserMemoryRow(row) {
|
|
|
164465
165146
|
};
|
|
164466
165147
|
}
|
|
164467
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
|
+
|
|
164468
165587
|
// src/features/magic-context/memory/cosine-similarity.ts
|
|
164469
165588
|
function cosineSimilarity(a, b) {
|
|
164470
165589
|
if (a.length !== b.length) {
|
|
@@ -164622,19 +165741,19 @@ function isArrayLikeNumber(value) {
|
|
|
164622
165741
|
}
|
|
164623
165742
|
return arr.length === 0 || typeof arr[0] === "number";
|
|
164624
165743
|
}
|
|
164625
|
-
function
|
|
165744
|
+
function toFloat32Array3(values) {
|
|
164626
165745
|
return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
|
|
164627
165746
|
}
|
|
164628
165747
|
function extractBatchEmbeddings(result, expectedCount) {
|
|
164629
165748
|
const { data } = result;
|
|
164630
165749
|
if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
|
|
164631
|
-
return data.map((entry) =>
|
|
165750
|
+
return data.map((entry) => toFloat32Array3(entry));
|
|
164632
165751
|
}
|
|
164633
165752
|
if (!isArrayLikeNumber(data)) {
|
|
164634
165753
|
log("[magic-context] embedding batch returned unexpected data shape");
|
|
164635
165754
|
return Array.from({ length: expectedCount }, () => null);
|
|
164636
165755
|
}
|
|
164637
|
-
const flatData =
|
|
165756
|
+
const flatData = toFloat32Array3(data);
|
|
164638
165757
|
const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
|
|
164639
165758
|
if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
|
|
164640
165759
|
log("[magic-context] embedding batch returned invalid dimensions");
|
|
@@ -164649,6 +165768,7 @@ function extractBatchEmbeddings(result, expectedCount) {
|
|
|
164649
165768
|
|
|
164650
165769
|
class LocalEmbeddingProvider {
|
|
164651
165770
|
modelId;
|
|
165771
|
+
maxInputTokens;
|
|
164652
165772
|
model;
|
|
164653
165773
|
pipeline = null;
|
|
164654
165774
|
initPromise = null;
|
|
@@ -164656,8 +165776,9 @@ class LocalEmbeddingProvider {
|
|
|
164656
165776
|
disposing = false;
|
|
164657
165777
|
disposePromise = null;
|
|
164658
165778
|
inFlightWaiters = [];
|
|
164659
|
-
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
165779
|
+
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
|
|
164660
165780
|
this.model = model;
|
|
165781
|
+
this.maxInputTokens = maxInputTokens;
|
|
164661
165782
|
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
164662
165783
|
}
|
|
164663
165784
|
async initialize() {
|
|
@@ -164917,6 +166038,7 @@ function normalizeEndpoint3(endpoint) {
|
|
|
164917
166038
|
|
|
164918
166039
|
class OpenAICompatibleEmbeddingProvider {
|
|
164919
166040
|
modelId;
|
|
166041
|
+
maxInputTokens;
|
|
164920
166042
|
endpoint;
|
|
164921
166043
|
model;
|
|
164922
166044
|
apiKey;
|
|
@@ -164933,11 +166055,13 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164933
166055
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
164934
166056
|
this.inputType = options.inputType?.trim() ?? "";
|
|
164935
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;
|
|
164936
166059
|
this.modelId = getEmbeddingProviderIdentity({
|
|
164937
166060
|
provider: "openai-compatible",
|
|
164938
166061
|
endpoint: this.endpoint,
|
|
164939
166062
|
model: this.model,
|
|
164940
|
-
...this.apiKey ? { api_key: this.apiKey } : {}
|
|
166063
|
+
...this.apiKey ? { api_key: this.apiKey } : {},
|
|
166064
|
+
...this.inputType ? { input_type: this.inputType } : {}
|
|
164941
166065
|
});
|
|
164942
166066
|
}
|
|
164943
166067
|
async initialize() {
|
|
@@ -165181,12 +166305,12 @@ function getCountEmbeddedStatement(db) {
|
|
|
165181
166305
|
}
|
|
165182
166306
|
return stmt;
|
|
165183
166307
|
}
|
|
165184
|
-
function
|
|
165185
|
-
let stmt =
|
|
166308
|
+
function getClearProjectStatement2(db) {
|
|
166309
|
+
let stmt = clearProjectStatements2.get(db);
|
|
165186
166310
|
if (!stmt) {
|
|
165187
166311
|
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
165188
166312
|
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
165189
|
-
|
|
166313
|
+
clearProjectStatements2.set(db, stmt);
|
|
165190
166314
|
}
|
|
165191
166315
|
return stmt;
|
|
165192
166316
|
}
|
|
@@ -165222,19 +166346,19 @@ function countEmbeddedCommits(db, projectPath) {
|
|
|
165222
166346
|
return row?.count ?? 0;
|
|
165223
166347
|
}
|
|
165224
166348
|
function clearProjectCommitEmbeddings(db, projectPath) {
|
|
165225
|
-
return
|
|
166349
|
+
return getClearProjectStatement2(db).run(projectPath).changes;
|
|
165226
166350
|
}
|
|
165227
166351
|
function getDistinctCommitEmbeddingModelIds(db, projectPath) {
|
|
165228
166352
|
const rows = getDistinctModelIdStatement(db).all(projectPath);
|
|
165229
166353
|
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
165230
166354
|
}
|
|
165231
|
-
var saveStatements, loadProjectStatements, loadUnembeddedStatements, countEmbeddedStatements,
|
|
166355
|
+
var saveStatements, loadProjectStatements, loadUnembeddedStatements, countEmbeddedStatements, clearProjectStatements2, distinctModelIdStatements;
|
|
165232
166356
|
var init_storage_git_commit_embeddings = __esm(() => {
|
|
165233
166357
|
saveStatements = new WeakMap;
|
|
165234
166358
|
loadProjectStatements = new WeakMap;
|
|
165235
166359
|
loadUnembeddedStatements = new WeakMap;
|
|
165236
166360
|
countEmbeddedStatements = new WeakMap;
|
|
165237
|
-
|
|
166361
|
+
clearProjectStatements2 = new WeakMap;
|
|
165238
166362
|
distinctModelIdStatements = new WeakMap;
|
|
165239
166363
|
});
|
|
165240
166364
|
|
|
@@ -165360,13 +166484,90 @@ var init_sweep_coordinator = __esm(() => {
|
|
|
165360
166484
|
GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
|
|
165361
166485
|
});
|
|
165362
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
|
+
|
|
165363
166561
|
// src/features/magic-context/project-embedding-registry.ts
|
|
165364
|
-
import { createHash as
|
|
166562
|
+
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
165365
166563
|
function resolveEmbeddingConfig(config2) {
|
|
165366
166564
|
if (!config2 || config2.provider === "local") {
|
|
165367
166565
|
return {
|
|
165368
166566
|
provider: "local",
|
|
165369
|
-
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
|
+
} : {}
|
|
165370
166571
|
};
|
|
165371
166572
|
}
|
|
165372
166573
|
if (config2.provider === "openai-compatible") {
|
|
@@ -165379,7 +166580,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
165379
166580
|
endpoint: config2.endpoint.trim(),
|
|
165380
166581
|
...apiKey ? { api_key: apiKey } : {},
|
|
165381
166582
|
...inputType ? { input_type: inputType } : {},
|
|
165382
|
-
...truncate ? { truncate } : {}
|
|
166583
|
+
...truncate ? { truncate } : {},
|
|
166584
|
+
...config2.max_input_tokens ? {
|
|
166585
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
166586
|
+
} : {}
|
|
165383
166587
|
};
|
|
165384
166588
|
}
|
|
165385
166589
|
return { provider: "off" };
|
|
@@ -165397,10 +166601,11 @@ function createProvider(config2) {
|
|
|
165397
166601
|
model: config2.model,
|
|
165398
166602
|
apiKey: config2.api_key,
|
|
165399
166603
|
inputType: config2.input_type,
|
|
165400
|
-
truncate: config2.truncate
|
|
166604
|
+
truncate: config2.truncate,
|
|
166605
|
+
maxInputTokens: config2.max_input_tokens
|
|
165401
166606
|
});
|
|
165402
166607
|
}
|
|
165403
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
166608
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
165404
166609
|
}
|
|
165405
166610
|
function stableStringify2(value) {
|
|
165406
166611
|
if (Array.isArray(value)) {
|
|
@@ -165413,7 +166618,7 @@ function stableStringify2(value) {
|
|
|
165413
166618
|
return JSON.stringify(value);
|
|
165414
166619
|
}
|
|
165415
166620
|
function sha256Prefix(value, length = 16) {
|
|
165416
|
-
return
|
|
166621
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, length);
|
|
165417
166622
|
}
|
|
165418
166623
|
function getRuntimeFingerprint(config2) {
|
|
165419
166624
|
if (config2.provider === "off") {
|
|
@@ -165421,6 +166626,18 @@ function getRuntimeFingerprint(config2) {
|
|
|
165421
166626
|
}
|
|
165422
166627
|
return `${getEmbeddingProviderIdentity(config2)}:${sha256Prefix(stableStringify2(config2))}`;
|
|
165423
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
|
+
}
|
|
165424
166641
|
function sameFeatures(a, b) {
|
|
165425
166642
|
return a.memoryEnabled === b.memoryEnabled && a.gitCommitEnabled === b.gitCommitEnabled;
|
|
165426
166643
|
}
|
|
@@ -165437,7 +166654,8 @@ function snapshotFor(registration) {
|
|
|
165437
166654
|
features: { ...registration.features },
|
|
165438
166655
|
enabled,
|
|
165439
166656
|
gitCommitEnabled,
|
|
165440
|
-
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId
|
|
166657
|
+
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
|
|
166658
|
+
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId
|
|
165441
166659
|
};
|
|
165442
166660
|
}
|
|
165443
166661
|
function disposeProvider(provider) {
|
|
@@ -165457,7 +166675,7 @@ function anyStoredModelIdIsStale(storedIds, currentId) {
|
|
|
165457
166675
|
}
|
|
165458
166676
|
return false;
|
|
165459
166677
|
}
|
|
165460
|
-
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, features) {
|
|
166678
|
+
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, currentChunkIdentity, features) {
|
|
165461
166679
|
if (currentProviderIdentity === OFF_PROVIDER_IDENTITY) {
|
|
165462
166680
|
return false;
|
|
165463
166681
|
}
|
|
@@ -165478,6 +166696,14 @@ function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity,
|
|
|
165478
166696
|
wiped = true;
|
|
165479
166697
|
}
|
|
165480
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
|
+
}
|
|
165481
166707
|
})();
|
|
165482
166708
|
return wiped;
|
|
165483
166709
|
}
|
|
@@ -165485,10 +166711,11 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
165485
166711
|
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
165486
166712
|
const providerIdentity = getEmbeddingProviderIdentity(resolvedConfig);
|
|
165487
166713
|
const runtimeFingerprint = getRuntimeFingerprint(resolvedConfig);
|
|
166714
|
+
const chunkModelId = getChunkEmbeddingModelId(resolvedConfig, providerIdentity);
|
|
165488
166715
|
const prior = projectRegistrations.get(projectIdentity);
|
|
165489
166716
|
const canReuseProvider = prior !== undefined && !prior.observationMode && prior.runtimeFingerprint === runtimeFingerprint && prior.providerIdentity === providerIdentity;
|
|
165490
|
-
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, features);
|
|
165491
|
-
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;
|
|
165492
166719
|
const generation = generationChanged ? ++globalRegistrationGeneration : prior.generation;
|
|
165493
166720
|
const registration = {
|
|
165494
166721
|
projectIdentity,
|
|
@@ -165500,6 +166727,7 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
165500
166727
|
generation,
|
|
165501
166728
|
features: { ...features },
|
|
165502
166729
|
modelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : providerIdentity,
|
|
166730
|
+
chunkModelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : chunkModelId,
|
|
165503
166731
|
observationMode: false
|
|
165504
166732
|
};
|
|
165505
166733
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -165522,6 +166750,7 @@ function registerProjectInObservationMode(db, projectIdentity, sourceDirectory,
|
|
|
165522
166750
|
generation,
|
|
165523
166751
|
features: { memoryEnabled: false, gitCommitEnabled: false },
|
|
165524
166752
|
modelId: "off",
|
|
166753
|
+
chunkModelId: "off",
|
|
165525
166754
|
observationMode: true
|
|
165526
166755
|
};
|
|
165527
166756
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -165532,6 +166761,15 @@ function getProjectEmbeddingSnapshot(projectIdentity) {
|
|
|
165532
166761
|
const registration = projectRegistrations.get(projectIdentity);
|
|
165533
166762
|
return registration ? snapshotFor(registration) : null;
|
|
165534
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
|
+
}
|
|
165535
166773
|
function getOrCreateProjectProvider(registration) {
|
|
165536
166774
|
if (registration.providerIdentity === OFF_PROVIDER_IDENTITY || registration.observationMode) {
|
|
165537
166775
|
return null;
|
|
@@ -165626,10 +166864,136 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
165626
166864
|
return 0;
|
|
165627
166865
|
}
|
|
165628
166866
|
}
|
|
165629
|
-
|
|
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;
|
|
165630
166993
|
var init_project_embedding_registry = __esm(() => {
|
|
165631
166994
|
init_magic_context();
|
|
165632
166995
|
init_logger();
|
|
166996
|
+
init_compartment_chunk_embedding();
|
|
165633
166997
|
init_storage_git_commit_embeddings();
|
|
165634
166998
|
init_sweep_coordinator();
|
|
165635
166999
|
init_embedding_cache();
|
|
@@ -165637,7 +167001,9 @@ var init_project_embedding_registry = __esm(() => {
|
|
|
165637
167001
|
init_embedding_local();
|
|
165638
167002
|
init_embedding_openai();
|
|
165639
167003
|
init_storage_memory_embeddings();
|
|
167004
|
+
init_session_project_storage();
|
|
165640
167005
|
SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
167006
|
+
SESSION_EMBED_LEASE_RENEWAL_MS = 60 * 1000;
|
|
165641
167007
|
projectRegistrations = new Map;
|
|
165642
167008
|
loadUnembeddedMemoriesStatements = new WeakMap;
|
|
165643
167009
|
});
|
|
@@ -165653,10 +167019,11 @@ function createProvider2(config2) {
|
|
|
165653
167019
|
model: config2.model,
|
|
165654
167020
|
apiKey: config2.api_key,
|
|
165655
167021
|
inputType: config2.input_type,
|
|
165656
|
-
truncate: config2.truncate
|
|
167022
|
+
truncate: config2.truncate,
|
|
167023
|
+
maxInputTokens: config2.max_input_tokens
|
|
165657
167024
|
});
|
|
165658
167025
|
}
|
|
165659
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
167026
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
165660
167027
|
}
|
|
165661
167028
|
function getOrCreateProvider() {
|
|
165662
167029
|
if (provider) {
|
|
@@ -165682,6 +167049,7 @@ var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMe
|
|
|
165682
167049
|
var init_embedding = __esm(() => {
|
|
165683
167050
|
init_magic_context();
|
|
165684
167051
|
init_logger();
|
|
167052
|
+
init_compartment_chunk_embedding();
|
|
165685
167053
|
init_embedding_identity();
|
|
165686
167054
|
init_embedding_local();
|
|
165687
167055
|
init_embedding_openai();
|
|
@@ -165705,6 +167073,23 @@ function getSearchStatement(db) {
|
|
|
165705
167073
|
}
|
|
165706
167074
|
return stmt;
|
|
165707
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
|
+
}
|
|
165708
167093
|
function sanitizeFtsQuery(query) {
|
|
165709
167094
|
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
165710
167095
|
if (tokens.length === 0)
|
|
@@ -165723,10 +167108,33 @@ function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT)
|
|
|
165723
167108
|
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
165724
167109
|
return rows.map(toMemory);
|
|
165725
167110
|
}
|
|
165726
|
-
|
|
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;
|
|
165727
167134
|
var init_storage_memory_fts = __esm(() => {
|
|
165728
167135
|
init_storage_memory();
|
|
165729
167136
|
searchStatements = new WeakMap;
|
|
167137
|
+
unionSearchStatements = new Map;
|
|
165730
167138
|
});
|
|
165731
167139
|
|
|
165732
167140
|
// src/shared/models-dev-cache.ts
|
|
@@ -165920,26 +167328,54 @@ var init_rpc_notifications = __esm(() => {
|
|
|
165920
167328
|
});
|
|
165921
167329
|
|
|
165922
167330
|
// src/features/magic-context/compartment-embedding.ts
|
|
165923
|
-
async function
|
|
167331
|
+
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
165924
167332
|
if (compartments.length === 0)
|
|
165925
167333
|
return;
|
|
165926
|
-
const
|
|
165927
|
-
for (const
|
|
165928
|
-
if (!c.p1 || c.p1.length === 0)
|
|
165929
|
-
continue;
|
|
167334
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
167335
|
+
for (const compartment of compartments) {
|
|
165930
167336
|
try {
|
|
165931
|
-
const
|
|
165932
|
-
|
|
165933
|
-
|
|
165934
|
-
|
|
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);
|
|
165935
167370
|
}
|
|
165936
167371
|
} catch (error51) {
|
|
165937
|
-
sessionLog(sessionId, `compartment embedding failed for compartment ${
|
|
167372
|
+
sessionLog(sessionId, `compartment chunk embedding failed for compartment ${compartment.id}:`, error51);
|
|
165938
167373
|
}
|
|
165939
167374
|
}
|
|
165940
167375
|
}
|
|
165941
167376
|
var init_compartment_embedding = __esm(() => {
|
|
165942
167377
|
init_logger();
|
|
167378
|
+
init_compartment_chunk_embedding();
|
|
165943
167379
|
init_project_embedding_registry();
|
|
165944
167380
|
});
|
|
165945
167381
|
|
|
@@ -167053,55 +168489,6 @@ var init_historian_state_file = __esm(() => {
|
|
|
167053
168489
|
init_data_path();
|
|
167054
168490
|
});
|
|
167055
168491
|
|
|
167056
|
-
// src/features/magic-context/memory/constants.ts
|
|
167057
|
-
var V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
167058
|
-
var init_constants = __esm(() => {
|
|
167059
|
-
V2_MEMORY_CATEGORIES = [
|
|
167060
|
-
"PROJECT_RULES",
|
|
167061
|
-
"ARCHITECTURE",
|
|
167062
|
-
"CONSTRAINTS",
|
|
167063
|
-
"CONFIG_VALUES",
|
|
167064
|
-
"NAMING"
|
|
167065
|
-
];
|
|
167066
|
-
PROMOTABLE_CATEGORIES = [
|
|
167067
|
-
"PROJECT_RULES",
|
|
167068
|
-
"ARCHITECTURE",
|
|
167069
|
-
"CONSTRAINTS",
|
|
167070
|
-
"CONFIG_VALUES",
|
|
167071
|
-
"NAMING",
|
|
167072
|
-
"ARCHITECTURE_DECISIONS",
|
|
167073
|
-
"CONFIG_DEFAULTS",
|
|
167074
|
-
"USER_PREFERENCES",
|
|
167075
|
-
"USER_DIRECTIVES",
|
|
167076
|
-
"ENVIRONMENT",
|
|
167077
|
-
"WORKFLOW_RULES",
|
|
167078
|
-
"KNOWN_ISSUES"
|
|
167079
|
-
];
|
|
167080
|
-
CATEGORY_PRIORITY = [
|
|
167081
|
-
"PROJECT_RULES",
|
|
167082
|
-
"ARCHITECTURE",
|
|
167083
|
-
"CONSTRAINTS",
|
|
167084
|
-
"CONFIG_VALUES",
|
|
167085
|
-
"NAMING",
|
|
167086
|
-
"USER_DIRECTIVES",
|
|
167087
|
-
"USER_PREFERENCES",
|
|
167088
|
-
"CONFIG_DEFAULTS",
|
|
167089
|
-
"ARCHITECTURE_DECISIONS",
|
|
167090
|
-
"ENVIRONMENT",
|
|
167091
|
-
"WORKFLOW_RULES",
|
|
167092
|
-
"KNOWN_ISSUES"
|
|
167093
|
-
];
|
|
167094
|
-
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
167095
|
-
acc[category] = index;
|
|
167096
|
-
return acc;
|
|
167097
|
-
}, {});
|
|
167098
|
-
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
167099
|
-
CATEGORY_DEFAULT_TTL = {
|
|
167100
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
167101
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
167102
|
-
};
|
|
167103
|
-
});
|
|
167104
|
-
|
|
167105
168492
|
// src/features/magic-context/memory/embedding-backfill.ts
|
|
167106
168493
|
async function ensureMemoryEmbeddings(args) {
|
|
167107
168494
|
const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -167125,7 +168512,7 @@ async function ensureMemoryEmbeddings(args) {
|
|
|
167125
168512
|
continue;
|
|
167126
168513
|
}
|
|
167127
168514
|
saveEmbedding(args.db, memory.id, embedding, result.modelId);
|
|
167128
|
-
staged.set(memory.id, embedding);
|
|
168515
|
+
staged.set(memory.id, { embedding, modelId: result.modelId });
|
|
167129
168516
|
}
|
|
167130
168517
|
})();
|
|
167131
168518
|
const currentSnapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -167922,6 +169309,71 @@ function lastCompartmentBoundaryId(compartments) {
|
|
|
167922
169309
|
const last = compartments.at(-1);
|
|
167923
169310
|
return last?.endMessageId && last.endMessageId.length > 0 ? last.endMessageId : null;
|
|
167924
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
|
+
}
|
|
167925
169377
|
function cachedStatement(cache, db, sql) {
|
|
167926
169378
|
let stmt = cache.get(db);
|
|
167927
169379
|
if (!stmt) {
|
|
@@ -167964,13 +169416,19 @@ function getGlobalUserProfileVersion(db) {
|
|
|
167964
169416
|
function readCurrentM0SnapshotMarkers(args) {
|
|
167965
169417
|
const projectDirectory = args.projectDirectory ?? args.projectPath ?? "";
|
|
167966
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
|
+
});
|
|
167967
169424
|
return {
|
|
167968
169425
|
projectMemoryEpoch: getProjectMemoryEpoch(args.db, args.projectPath),
|
|
169426
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(args.db, workspace.identities) : null,
|
|
167969
169427
|
projectUserProfileVersion: getGlobalUserProfileVersion(args.db),
|
|
167970
169428
|
maxCompartmentSeq: getMaxCompartmentSeq(args.db, args.sessionId),
|
|
167971
|
-
maxMemoryId: getMaxMemoryId(args.db, args.projectPath),
|
|
169429
|
+
maxMemoryId: workspace.isWorkspaced ? getMaxMemoryIdForProjects(args.db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryId(args.db, args.projectPath),
|
|
167972
169430
|
maxMutationId: getMaxM0MutationId(args.db, args.sessionId) ?? 0,
|
|
167973
|
-
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,
|
|
167974
169432
|
projectDocsHash: projectDirectory ? computeProjectDocsHash(projectDirectory) : "",
|
|
167975
169433
|
materializedAt: Date.now(),
|
|
167976
169434
|
sessionFactsVersion: getSessionFactsVersion(args.db, args.sessionId),
|
|
@@ -167998,6 +169456,7 @@ function snapshotMarkersFromCachedM0(state) {
|
|
|
167998
169456
|
return null;
|
|
167999
169457
|
return {
|
|
168000
169458
|
projectMemoryEpoch: state.cachedM0ProjectMemoryEpoch,
|
|
169459
|
+
workspaceFingerprint: state.cachedM0WorkspaceFingerprint,
|
|
168001
169460
|
projectUserProfileVersion: state.cachedM0ProjectUserProfileVersion,
|
|
168002
169461
|
maxCompartmentSeq: state.cachedM0MaxCompartmentSeq,
|
|
168003
169462
|
maxMemoryId: state.cachedM0MaxMemoryId,
|
|
@@ -168027,35 +169486,27 @@ function mustMaterialize(args) {
|
|
|
168027
169486
|
if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (args.state.cachedM0MaterializedAt ?? 0)) {
|
|
168028
169487
|
return { value: true, reason: "ttl_idle" };
|
|
168029
169488
|
}
|
|
168030
|
-
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) {
|
|
168031
169494
|
return { value: true, reason: "project_memory_epoch" };
|
|
168032
169495
|
}
|
|
168033
169496
|
if (args.state.cachedM0MaxMutationId !== current.maxMutationId) {
|
|
168034
169497
|
return { value: true, reason: "max_mutation_id" };
|
|
168035
169498
|
}
|
|
168036
|
-
if ((args.state.cachedM0ProjectDocsHash ?? "") !== current.projectDocsHash) {
|
|
168037
|
-
return { value: true, reason: "project_docs_hash" };
|
|
168038
|
-
}
|
|
168039
169499
|
if ((args.state.cachedM0UpgradeState ?? null) !== current.upgradeState) {
|
|
168040
169500
|
return { value: true, reason: "upgrade_state" };
|
|
168041
169501
|
}
|
|
168042
169502
|
return { value: false, reason: null };
|
|
168043
169503
|
}
|
|
168044
|
-
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
168045
|
-
const selectionOrder = [...memories].sort(
|
|
168046
|
-
if (a.status === "permanent" && b.status !== "permanent")
|
|
168047
|
-
return -1;
|
|
168048
|
-
if (b.status === "permanent" && a.status !== "permanent")
|
|
168049
|
-
return 1;
|
|
168050
|
-
const importanceDiff = (b.importance ?? 50) - (a.importance ?? 50);
|
|
168051
|
-
if (importanceDiff !== 0)
|
|
168052
|
-
return importanceDiff;
|
|
168053
|
-
return a.id - b.id;
|
|
168054
|
-
});
|
|
169504
|
+
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions = {}) {
|
|
169505
|
+
const selectionOrder = [...memories].sort(memorySelectionOrder);
|
|
168055
169506
|
const selected = [];
|
|
168056
169507
|
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
168057
169508
|
for (const memory of selectionOrder) {
|
|
168058
|
-
const memoryTokens = estimateTokens(renderMemoryLineV2(memory));
|
|
169509
|
+
const memoryTokens = estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
168059
169510
|
if (usedTokens + memoryTokens > budgetTokens)
|
|
168060
169511
|
continue;
|
|
168061
169512
|
selected.push(memory);
|
|
@@ -168064,16 +169515,70 @@ function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
|
168064
169515
|
if (selected.length < memories.length) {
|
|
168065
169516
|
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
168066
169517
|
}
|
|
168067
|
-
const renderOrder = [...selected].sort(
|
|
168068
|
-
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[a.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
168069
|
-
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[b.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
168070
|
-
const categoryDiff = aPriority - bPriority;
|
|
168071
|
-
if (categoryDiff !== 0)
|
|
168072
|
-
return categoryDiff;
|
|
168073
|
-
return a.id - b.id;
|
|
168074
|
-
});
|
|
169518
|
+
const renderOrder = [...selected].sort(memoryRenderOrder);
|
|
168075
169519
|
return { selected, renderOrder };
|
|
168076
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
|
+
}
|
|
168077
169582
|
function safeGetActiveUserMemories(db) {
|
|
168078
169583
|
try {
|
|
168079
169584
|
return getActiveUserMemories(db);
|
|
@@ -168149,15 +169654,16 @@ function readNewMemoriesForM1(db, projectPath, afterId, expiryCutoff) {
|
|
|
168149
169654
|
ORDER BY ${MEMORY_CATEGORY_ORDER_SQL}, id ASC`).all(projectPath, afterId, expiryCutoff).filter(isMemoryRow);
|
|
168150
169655
|
return rows.map((row) => ({ ...row }));
|
|
168151
169656
|
}
|
|
168152
|
-
function renderMemoryLineV2(memory) {
|
|
168153
|
-
|
|
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>`;
|
|
168154
169660
|
}
|
|
168155
|
-
function renderMemoryBlockV2(memories, wrapper = "project-memory") {
|
|
169661
|
+
function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions = {}) {
|
|
168156
169662
|
if (memories.length === 0)
|
|
168157
169663
|
return "";
|
|
168158
169664
|
const lines = [`<${wrapper}>`];
|
|
168159
169665
|
for (const memory of memories) {
|
|
168160
|
-
lines.push(renderMemoryLineV2(memory));
|
|
169666
|
+
lines.push(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
168161
169667
|
}
|
|
168162
169668
|
lines.push(`</${wrapper}>`);
|
|
168163
169669
|
return lines.join(`
|
|
@@ -168196,7 +169702,7 @@ function renderM0(args) {
|
|
|
168196
169702
|
sections.push(sessionHistory.length > 0 ? `<session-history>
|
|
168197
169703
|
${sessionHistory}
|
|
168198
169704
|
</session-history>` : M0_EMPTY_BODY);
|
|
168199
|
-
const memoriesBlock = renderMemoryBlockV2(args.memories);
|
|
169705
|
+
const memoriesBlock = renderMemoryBlockV2(args.memories, "project-memory", args.memoryRenderOptions);
|
|
168200
169706
|
if (memoriesBlock)
|
|
168201
169707
|
sections.push(memoriesBlock);
|
|
168202
169708
|
return sections.join(`
|
|
@@ -168208,6 +169714,7 @@ function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
|
|
|
168208
169714
|
if (m1Bytes)
|
|
168209
169715
|
state.cachedM1Bytes = m1Bytes;
|
|
168210
169716
|
state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
|
|
169717
|
+
state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
|
|
168211
169718
|
state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
|
|
168212
169719
|
state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
|
|
168213
169720
|
state.cachedM0MaxMemoryId = markers.maxMemoryId;
|
|
@@ -168233,24 +169740,38 @@ function materializeM0(options) {
|
|
|
168233
169740
|
let facts = [];
|
|
168234
169741
|
let memories = [];
|
|
168235
169742
|
let userMemories = [];
|
|
169743
|
+
let workspace = resolveWorkspaceRenderContext({
|
|
169744
|
+
db: options.db,
|
|
169745
|
+
projectPath,
|
|
169746
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169747
|
+
});
|
|
168236
169748
|
let docs = {
|
|
168237
169749
|
renderedBlock: "",
|
|
168238
169750
|
canonicalHash: ""
|
|
168239
169751
|
};
|
|
168240
169752
|
options.db.exec("BEGIN");
|
|
168241
169753
|
try {
|
|
169754
|
+
workspace = resolveWorkspaceRenderContext({
|
|
169755
|
+
db: options.db,
|
|
169756
|
+
projectPath,
|
|
169757
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169758
|
+
});
|
|
168242
169759
|
snapshotMarkers = readCurrentM0SnapshotMarkers({
|
|
168243
169760
|
db: options.db,
|
|
168244
169761
|
sessionId: options.sessionId,
|
|
168245
169762
|
projectPath,
|
|
168246
169763
|
projectDirectory,
|
|
168247
|
-
hardSignals: options.hardSignals
|
|
169764
|
+
hardSignals: options.hardSignals,
|
|
169765
|
+
workspaceIdentitySet: {
|
|
169766
|
+
identities: workspace.identities,
|
|
169767
|
+
namesByIdentity: workspace.namesByIdentity
|
|
169768
|
+
}
|
|
168248
169769
|
});
|
|
168249
169770
|
docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
|
|
168250
169771
|
snapshotMarkers.projectDocsHash = docs.canonicalHash;
|
|
168251
169772
|
compartments = readM0Compartments(options.db, options.sessionId);
|
|
168252
169773
|
facts = [];
|
|
168253
|
-
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"]) : [];
|
|
168254
169775
|
userMemories = safeGetActiveUserMemories(options.db);
|
|
168255
169776
|
options.db.exec("COMMIT");
|
|
168256
169777
|
} catch (error51) {
|
|
@@ -168260,7 +169781,14 @@ function materializeM0(options) {
|
|
|
168260
169781
|
throw error51;
|
|
168261
169782
|
}
|
|
168262
169783
|
const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
168263
|
-
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);
|
|
168264
169792
|
let decayPressureMultiplier = 1;
|
|
168265
169793
|
let m0Text = renderM0({
|
|
168266
169794
|
projectDocs: docs.renderedBlock,
|
|
@@ -168268,6 +169796,7 @@ function materializeM0(options) {
|
|
|
168268
169796
|
compartments,
|
|
168269
169797
|
memories: trimmed.renderOrder,
|
|
168270
169798
|
facts,
|
|
169799
|
+
memoryRenderOptions,
|
|
168271
169800
|
historyBudgetTokens: options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS,
|
|
168272
169801
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168273
169802
|
decayPressureMultiplier
|
|
@@ -168282,6 +169811,7 @@ function materializeM0(options) {
|
|
|
168282
169811
|
compartments,
|
|
168283
169812
|
memories: trimmed.renderOrder,
|
|
168284
169813
|
facts,
|
|
169814
|
+
memoryRenderOptions,
|
|
168285
169815
|
historyBudgetTokens: budget,
|
|
168286
169816
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168287
169817
|
decayPressureMultiplier
|
|
@@ -168300,13 +169830,19 @@ function materializeM0(options) {
|
|
|
168300
169830
|
let m1Bytes = Buffer4.from(m1Text, "utf8");
|
|
168301
169831
|
options.db.exec("BEGIN IMMEDIATE");
|
|
168302
169832
|
try {
|
|
169833
|
+
const currentWorkspace = resolveWorkspaceRenderContext({
|
|
169834
|
+
db: options.db,
|
|
169835
|
+
projectPath,
|
|
169836
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169837
|
+
});
|
|
168303
169838
|
const current = {
|
|
168304
169839
|
projectMemoryEpoch: getProjectMemoryEpoch(options.db, projectPath),
|
|
169840
|
+
workspaceFingerprint: currentWorkspace.isWorkspaced ? computeWorkspaceEpochFingerprint(options.db, currentWorkspace.identities) : null,
|
|
168305
169841
|
projectUserProfileVersion: getGlobalUserProfileVersion(options.db),
|
|
168306
169842
|
maxCompartmentSeq: getMaxCompartmentSeq(options.db, options.sessionId),
|
|
168307
|
-
maxMemoryId: getMaxMemoryId(options.db, projectPath),
|
|
169843
|
+
maxMemoryId: currentWorkspace.isWorkspaced ? getMaxMemoryIdForProjects(options.db, currentWorkspace.expandedIdentities, currentWorkspace.ownIdentities, currentWorkspace.shareCategories) : getMaxMemoryId(options.db, projectPath),
|
|
168308
169844
|
maxMutationId: getMaxM0MutationId(options.db, options.sessionId) ?? 0,
|
|
168309
|
-
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,
|
|
168310
169846
|
projectDocsHash: phase3ProjectDocsHash,
|
|
168311
169847
|
materializedAt: Date.now(),
|
|
168312
169848
|
sessionFactsVersion: getSessionFactsVersion(options.db, options.sessionId),
|
|
@@ -168314,17 +169850,26 @@ function materializeM0(options) {
|
|
|
168314
169850
|
systemHash: snapshotMarkers.systemHash,
|
|
168315
169851
|
modelKey: snapshotMarkers.modelKey
|
|
168316
169852
|
};
|
|
168317
|
-
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;
|
|
168318
169855
|
if (stale) {
|
|
168319
169856
|
options.db.exec("ROLLBACK");
|
|
168320
169857
|
throw new MaterializeContentionError({ reason: "snapshot changed before Phase 3" });
|
|
168321
169858
|
}
|
|
168322
|
-
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);
|
|
168323
169867
|
m1Text = m1Render.text;
|
|
168324
169868
|
m1Bytes = Buffer4.from(m1Text, "utf8");
|
|
168325
169869
|
persistCachedM0(options.db, options.sessionId, {
|
|
168326
169870
|
m0Bytes,
|
|
168327
169871
|
projectMemoryEpoch: snapshotMarkers.projectMemoryEpoch,
|
|
169872
|
+
workspaceFingerprint: snapshotMarkers.workspaceFingerprint,
|
|
168328
169873
|
projectUserProfileVersion: snapshotMarkers.projectUserProfileVersion,
|
|
168329
169874
|
maxCompartmentSeq: snapshotMarkers.maxCompartmentSeq,
|
|
168330
169875
|
maxMemoryId: snapshotMarkers.maxMemoryId,
|
|
@@ -168387,7 +169932,7 @@ function renderMemoryUpdatesBlock(args) {
|
|
|
168387
169932
|
return { block: "", count: 0 };
|
|
168388
169933
|
}
|
|
168389
169934
|
const renderedIds = new Set(args.renderedMemoryIds);
|
|
168390
|
-
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);
|
|
168391
169936
|
if (mutations.length === 0)
|
|
168392
169937
|
return { block: "", count: 0 };
|
|
168393
169938
|
const lines = ["These memories changed since the snapshot below — trust these:"];
|
|
@@ -168419,12 +169964,18 @@ function renderM1WithMetadata(options, markers, renderedMemoryIds) {
|
|
|
168419
169964
|
throw new RenderM1InvalidMarkersError(options.sessionId);
|
|
168420
169965
|
}
|
|
168421
169966
|
const blocks = [];
|
|
169967
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
169968
|
+
db: options.db,
|
|
169969
|
+
projectPath: options.projectPath,
|
|
169970
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169971
|
+
});
|
|
168422
169972
|
const keyFiles = renderedKeyFilesBlock(options);
|
|
168423
169973
|
if (keyFiles)
|
|
168424
169974
|
blocks.push(keyFiles);
|
|
168425
169975
|
const memoryUpdates = renderMemoryUpdatesBlock({
|
|
168426
169976
|
db: options.db,
|
|
168427
169977
|
projectPath: options.projectPath,
|
|
169978
|
+
workspace,
|
|
168428
169979
|
afterId: markers.maxMemoryMutationId,
|
|
168429
169980
|
renderedMemoryIds
|
|
168430
169981
|
});
|
|
@@ -168438,9 +169989,16 @@ ${newCompartments.map((compartment) => renderCompartmentAtTier(compartment, 1)).
|
|
|
168438
169989
|
`)}
|
|
168439
169990
|
</new-compartments>`);
|
|
168440
169991
|
}
|
|
168441
|
-
const newMemories = readNewMemoriesForM1(options.db, options.projectPath, markers.maxMemoryId, markers.materializedAt);
|
|
168442
|
-
const
|
|
168443
|
-
|
|
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);
|
|
168444
170002
|
if (newMemoriesBlock)
|
|
168445
170003
|
blocks.push(newMemoriesBlock);
|
|
168446
170004
|
const currentUserProfileVersion = getGlobalUserProfileVersion(options.db);
|
|
@@ -168488,6 +170046,7 @@ function parseMemoryBlockIds(raw) {
|
|
|
168488
170046
|
function readCachedM0M1Row(db, sessionId) {
|
|
168489
170047
|
return db.prepare(`SELECT cached_m0_bytes, cached_m1_bytes,
|
|
168490
170048
|
cached_m0_project_memory_epoch,
|
|
170049
|
+
cached_m0_workspace_fingerprint,
|
|
168491
170050
|
cached_m0_project_user_profile_version,
|
|
168492
170051
|
cached_m0_max_compartment_seq,
|
|
168493
170052
|
cached_m0_max_memory_id,
|
|
@@ -168522,6 +170081,7 @@ function markersFromCachedRow(row) {
|
|
|
168522
170081
|
return null;
|
|
168523
170082
|
return {
|
|
168524
170083
|
projectMemoryEpoch: row.cached_m0_project_memory_epoch,
|
|
170084
|
+
workspaceFingerprint: row.cached_m0_workspace_fingerprint,
|
|
168525
170085
|
projectUserProfileVersion: row.cached_m0_project_user_profile_version,
|
|
168526
170086
|
maxCompartmentSeq: row.cached_m0_max_compartment_seq,
|
|
168527
170087
|
maxMemoryId: row.cached_m0_max_memory_id,
|
|
@@ -168536,7 +170096,7 @@ function markersFromCachedRow(row) {
|
|
|
168536
170096
|
};
|
|
168537
170097
|
}
|
|
168538
170098
|
function cachedRowMatchesState(row, state) {
|
|
168539
|
-
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 ?? "");
|
|
168540
170100
|
}
|
|
168541
170101
|
function applyCachedRowToState(state, row) {
|
|
168542
170102
|
const markers = markersFromCachedRow(row);
|
|
@@ -168546,6 +170106,7 @@ function applyCachedRowToState(state, row) {
|
|
|
168546
170106
|
state.cachedM0Bytes = toBuffer(row.cached_m0_bytes);
|
|
168547
170107
|
state.cachedM1Bytes = toBuffer(row.cached_m1_bytes);
|
|
168548
170108
|
state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
|
|
170109
|
+
state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
|
|
168549
170110
|
state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
|
|
168550
170111
|
state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
|
|
168551
170112
|
state.cachedM0MaxMemoryId = markers.maxMemoryId;
|
|
@@ -168609,20 +170170,36 @@ function prependM0M1Messages(sessionId, messages, m0Text, m1Text) {
|
|
|
168609
170170
|
function renderFreshM0NonPersisted(options) {
|
|
168610
170171
|
const projectPath = options.projectPath;
|
|
168611
170172
|
const projectDirectory = options.projectDirectory;
|
|
170173
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
170174
|
+
db: options.db,
|
|
170175
|
+
projectPath,
|
|
170176
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
170177
|
+
});
|
|
168612
170178
|
const snapshotMarkers = readCurrentM0SnapshotMarkers({
|
|
168613
170179
|
db: options.db,
|
|
168614
170180
|
sessionId: options.sessionId,
|
|
168615
170181
|
projectPath,
|
|
168616
|
-
projectDirectory
|
|
170182
|
+
projectDirectory,
|
|
170183
|
+
workspaceIdentitySet: {
|
|
170184
|
+
identities: workspace.identities,
|
|
170185
|
+
namesByIdentity: workspace.namesByIdentity
|
|
170186
|
+
}
|
|
168617
170187
|
});
|
|
168618
170188
|
const docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
|
|
168619
170189
|
snapshotMarkers.projectDocsHash = docs.canonicalHash;
|
|
168620
170190
|
snapshotMarkers.materializedAt = options.state.cachedM0MaterializedAt ?? 0;
|
|
168621
170191
|
const compartments = readM0Compartments(options.db, options.sessionId);
|
|
168622
|
-
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) : [];
|
|
168623
170193
|
const userMemories = safeGetActiveUserMemories(options.db);
|
|
168624
170194
|
const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
168625
|
-
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);
|
|
168626
170203
|
const budget = options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
168627
170204
|
let decayPressureMultiplier = 1;
|
|
168628
170205
|
let m0Text = renderM0({
|
|
@@ -168631,6 +170208,7 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168631
170208
|
compartments,
|
|
168632
170209
|
memories: trimmed.renderOrder,
|
|
168633
170210
|
facts: [],
|
|
170211
|
+
memoryRenderOptions,
|
|
168634
170212
|
historyBudgetTokens: budget,
|
|
168635
170213
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168636
170214
|
decayPressureMultiplier
|
|
@@ -168644,6 +170222,7 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168644
170222
|
compartments,
|
|
168645
170223
|
memories: trimmed.renderOrder,
|
|
168646
170224
|
facts: [],
|
|
170225
|
+
memoryRenderOptions,
|
|
168647
170226
|
historyBudgetTokens: budget,
|
|
168648
170227
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168649
170228
|
decayPressureMultiplier
|
|
@@ -168659,6 +170238,12 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168659
170238
|
};
|
|
168660
170239
|
}
|
|
168661
170240
|
function injectM0M1(options) {
|
|
170241
|
+
if (!options.workspaceIdentitySet && options.projectPath) {
|
|
170242
|
+
options = {
|
|
170243
|
+
...options,
|
|
170244
|
+
workspaceIdentitySet: resolveWorkspaceIdentitySet(options.db, options.projectPath)
|
|
170245
|
+
};
|
|
170246
|
+
}
|
|
168662
170247
|
const skipped = {
|
|
168663
170248
|
injected: false,
|
|
168664
170249
|
m0RematerializedThisPass: false,
|
|
@@ -168675,7 +170260,8 @@ function injectM0M1(options) {
|
|
|
168675
170260
|
state: options.state,
|
|
168676
170261
|
projectPath: options.projectPath,
|
|
168677
170262
|
projectDirectory: options.projectDirectory,
|
|
168678
|
-
hardSignals: options.hardSignals
|
|
170263
|
+
hardSignals: options.hardSignals,
|
|
170264
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
168679
170265
|
});
|
|
168680
170266
|
let rematerialized = false;
|
|
168681
170267
|
let contentionExhausted = false;
|
|
@@ -168769,6 +170355,7 @@ var init_inject_compartments = __esm(async () => {
|
|
|
168769
170355
|
init_compartment_storage();
|
|
168770
170356
|
init_constants();
|
|
168771
170357
|
init_storage_memory();
|
|
170358
|
+
init_workspaces();
|
|
168772
170359
|
init_logger();
|
|
168773
170360
|
init_decay_render();
|
|
168774
170361
|
init_key_files_block();
|
|
@@ -171908,18 +173495,38 @@ async function runCompartmentAgent(deps) {
|
|
|
171908
173495
|
return;
|
|
171909
173496
|
}
|
|
171910
173497
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
171911
|
-
|
|
173498
|
+
let boundarySnapshot = deps.boundarySnapshot ?? null;
|
|
171912
173499
|
if (!boundarySnapshot) {
|
|
171913
173500
|
telemetry.failureReason = "missing protected-tail boundary snapshot";
|
|
171914
173501
|
sessionLog(sessionId, "historian no-op: missing protected-tail boundary snapshot from trigger decision");
|
|
171915
173502
|
rollbackDrainReservation();
|
|
171916
173503
|
return;
|
|
171917
173504
|
}
|
|
171918
|
-
|
|
173505
|
+
let validation = boundarySnapshot.rawRangeFingerprint.length > 0 ? validateBoundarySnapshot({
|
|
171919
173506
|
db,
|
|
171920
173507
|
snapshot: boundarySnapshot,
|
|
171921
173508
|
currentContextLimit: deps.currentContextLimit ?? boundarySnapshot.contextLimit
|
|
171922
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
|
+
}
|
|
171923
173530
|
if (!validation.ok) {
|
|
171924
173531
|
sessionLog(sessionId, `historian no-op: stale protected-tail snapshot (${validation.detail ?? validation.reason ?? "unknown"})`);
|
|
171925
173532
|
telemetry.status = "noop";
|
|
@@ -171988,6 +173595,7 @@ async function runCompartmentAgent(deps) {
|
|
|
171988
173595
|
rollbackDrainReservation();
|
|
171989
173596
|
return;
|
|
171990
173597
|
}
|
|
173598
|
+
deps.onHistorianRunStarted?.();
|
|
171991
173599
|
const projectPath = resolveProjectIdentity(directory ?? process.cwd());
|
|
171992
173600
|
const memories = getMemoriesByProject(db, projectPath, ["active", "permanent"]);
|
|
171993
173601
|
const projectMemory = renderMemoryBlock(memories) ?? "";
|
|
@@ -172120,8 +173728,13 @@ ${chunkText}`,
|
|
|
172120
173728
|
}
|
|
172121
173729
|
if (embeddingActive) {
|
|
172122
173730
|
const projectIdentity = resolveProjectIdentity(promotionDirectory);
|
|
172123
|
-
const
|
|
172124
|
-
|
|
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);
|
|
172125
173738
|
}
|
|
172126
173739
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
172127
173740
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
@@ -172352,8 +173965,12 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
172352
173965
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172353
173966
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
172354
173967
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172355
|
-
const
|
|
172356
|
-
|
|
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);
|
|
172357
173974
|
}
|
|
172358
173975
|
const lastCompartmentEnd2 = promoted2.compartments[promoted2.compartments.length - 1]?.endMessage ?? 0;
|
|
172359
173976
|
if (lastCompartmentEnd2 > 0) {
|
|
@@ -172566,8 +174183,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
172566
174183
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172567
174184
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
172568
174185
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172569
|
-
const
|
|
172570
|
-
|
|
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);
|
|
172571
174192
|
}
|
|
172572
174193
|
if (lastCompartmentEnd > 0) {
|
|
172573
174194
|
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
@@ -172748,8 +174369,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
172748
174369
|
if (deps.memoryEnabled !== false) {
|
|
172749
174370
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172750
174371
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172751
|
-
const
|
|
172752
|
-
|
|
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));
|
|
172753
174378
|
}
|
|
172754
174379
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
172755
174380
|
if (lastEnd > 0) {
|
|
@@ -174971,7 +176596,14 @@ function startCompartmentAgent(deps) {
|
|
|
174971
176596
|
return;
|
|
174972
176597
|
}
|
|
174973
176598
|
const renewal = startLeaseRenewal(deps, holderId);
|
|
174974
|
-
|
|
176599
|
+
let realRunStarted = false;
|
|
176600
|
+
const runnerDeps = withPublishedCallback({
|
|
176601
|
+
...deps,
|
|
176602
|
+
compartmentLeaseHolderId: holderId,
|
|
176603
|
+
onHistorianRunStarted: () => {
|
|
176604
|
+
realRunStarted = true;
|
|
176605
|
+
}
|
|
176606
|
+
});
|
|
174975
176607
|
const promise2 = runCompartmentAgent(runnerDeps).catch((err) => {
|
|
174976
176608
|
sessionLog(deps.sessionId, "compartment agent: unhandled rejection:", err);
|
|
174977
176609
|
try {
|
|
@@ -174985,6 +176617,9 @@ function startCompartmentAgent(deps) {
|
|
|
174985
176617
|
}
|
|
174986
176618
|
});
|
|
174987
176619
|
activeRuns.set(deps.sessionId, { promise: promise2, published: false });
|
|
176620
|
+
if (!realRunStarted && activeRuns.get(deps.sessionId)?.promise === promise2) {
|
|
176621
|
+
activeRuns.delete(deps.sessionId);
|
|
176622
|
+
}
|
|
174988
176623
|
}
|
|
174989
176624
|
async function executeContextRecompWithResult(deps, options = {}) {
|
|
174990
176625
|
const { sessionId } = deps;
|
|
@@ -175119,7 +176754,7 @@ function applyMemoryMigration(db, projectPath, result) {
|
|
|
175119
176754
|
inserted++;
|
|
175120
176755
|
}
|
|
175121
176756
|
if (removed > 0 || inserted > 0) {
|
|
175122
|
-
|
|
176757
|
+
bumpEpochsForWorkspaceMembers(db, projectPath);
|
|
175123
176758
|
}
|
|
175124
176759
|
})();
|
|
175125
176760
|
return { removed, inserted };
|
|
@@ -175577,15 +177212,15 @@ function shouldShowAnnouncement() {
|
|
|
175577
177212
|
}
|
|
175578
177213
|
return state.version !== ANNOUNCEMENT_VERSION;
|
|
175579
177214
|
}
|
|
175580
|
-
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";
|
|
175581
177216
|
var init_announcement = __esm(() => {
|
|
175582
177217
|
init_data_path();
|
|
175583
177218
|
ANNOUNCEMENT_FEATURES = [
|
|
175584
|
-
"
|
|
175585
|
-
"
|
|
175586
|
-
"
|
|
175587
|
-
"
|
|
175588
|
-
"
|
|
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)."
|
|
175589
177224
|
];
|
|
175590
177225
|
});
|
|
175591
177226
|
// src/agents/permissions.ts
|
|
@@ -176313,6 +177948,10 @@ function getMagicContextBuiltinCommands() {
|
|
|
176313
177948
|
"ctx-dream": {
|
|
176314
177949
|
template: "ctx-dream",
|
|
176315
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"
|
|
176316
177955
|
}
|
|
176317
177956
|
};
|
|
176318
177957
|
}
|
|
@@ -176806,7 +178445,7 @@ await init_storage_db();
|
|
|
176806
178445
|
// src/features/magic-context/v22-deferred-backfill.ts
|
|
176807
178446
|
init_logger();
|
|
176808
178447
|
init_project_identity();
|
|
176809
|
-
import { createHash as
|
|
178448
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
176810
178449
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
176811
178450
|
import path5 from "node:path";
|
|
176812
178451
|
var BATCH_SIZE = 25;
|
|
@@ -176860,7 +178499,7 @@ function computeLegacyRustDirIdentity(rawProjectPath) {
|
|
|
176860
178499
|
} catch {
|
|
176861
178500
|
canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
|
|
176862
178501
|
}
|
|
176863
|
-
return `dir:${
|
|
178502
|
+
return `dir:${createHash6("sha256").update(canonical, "utf8").digest("hex")}`;
|
|
176864
178503
|
}
|
|
176865
178504
|
function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
|
|
176866
178505
|
db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
|
|
@@ -179401,7 +181040,7 @@ init_project_identity();
|
|
|
179401
181040
|
// src/plugin/embedding-bootstrap-helpers.ts
|
|
179402
181041
|
init_embedding();
|
|
179403
181042
|
init_logger();
|
|
179404
|
-
import { createHash as
|
|
181043
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
179405
181044
|
var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
179406
181045
|
"embedding.api_key",
|
|
179407
181046
|
"embedding.endpoint",
|
|
@@ -179422,7 +181061,7 @@ var EMBEDDING_WARNING_TERMS = [
|
|
|
179422
181061
|
];
|
|
179423
181062
|
var loggedFailureSignatures = new Map;
|
|
179424
181063
|
function sha256Prefix2(value, length = 16) {
|
|
179425
|
-
return
|
|
181064
|
+
return createHash10("sha256").update(value).digest("hex").slice(0, length);
|
|
179426
181065
|
}
|
|
179427
181066
|
function warningLooksEmbeddingRelated(message) {
|
|
179428
181067
|
const lower = message.toLowerCase();
|
|
@@ -180058,6 +181697,7 @@ function createTagger() {
|
|
|
180058
181697
|
// src/hooks/magic-context/hook.ts
|
|
180059
181698
|
init_magic_context();
|
|
180060
181699
|
init_project_identity();
|
|
181700
|
+
init_project_embedding_registry();
|
|
180061
181701
|
await init_storage();
|
|
180062
181702
|
init_logger();
|
|
180063
181703
|
init_resolve_fallbacks();
|
|
@@ -180651,6 +182291,7 @@ function createMagicContextCommandHandler(deps) {
|
|
|
180651
182291
|
const isAugCommand = (command) => command === "ctx-aug";
|
|
180652
182292
|
const isDreamCommand = (command) => command === "ctx-dream";
|
|
180653
182293
|
const isSessionUpgradeCommand = (command) => command === "ctx-session-upgrade";
|
|
182294
|
+
const isEmbedHistoryCommand = (command) => command === "ctx-embed-history";
|
|
180654
182295
|
return {
|
|
180655
182296
|
"command.execute.before": async (input, _output, _params) => {
|
|
180656
182297
|
const isStatus = isStatusCommand(input.command);
|
|
@@ -180659,7 +182300,8 @@ function createMagicContextCommandHandler(deps) {
|
|
|
180659
182300
|
const isAug = isAugCommand(input.command);
|
|
180660
182301
|
const isDream = isDreamCommand(input.command);
|
|
180661
182302
|
const isSessionUpgrade = isSessionUpgradeCommand(input.command);
|
|
180662
|
-
|
|
182303
|
+
const isEmbedHistory = isEmbedHistoryCommand(input.command);
|
|
182304
|
+
if (!isStatus && !isFlush && !isRecomp && !isAug && !isDream && !isSessionUpgrade && !isEmbedHistory) {
|
|
180663
182305
|
return;
|
|
180664
182306
|
}
|
|
180665
182307
|
const sessionId = input.sessionID;
|
|
@@ -180672,6 +182314,11 @@ function createMagicContextCommandHandler(deps) {
|
|
|
180672
182314
|
await executeDreaming(deps, sessionId);
|
|
180673
182315
|
return;
|
|
180674
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
|
+
}
|
|
180675
182322
|
if (isFlush) {
|
|
180676
182323
|
result = executeFlush(deps.db, sessionId);
|
|
180677
182324
|
clearCachedM0M1(deps.db, sessionId);
|
|
@@ -181412,6 +183059,7 @@ await init_read_session_chunk();
|
|
|
181412
183059
|
// src/hooks/magic-context/transform.ts
|
|
181413
183060
|
init_project_identity();
|
|
181414
183061
|
import * as crypto2 from "node:crypto";
|
|
183062
|
+
init_session_project_storage();
|
|
181415
183063
|
init_storage_meta_persisted();
|
|
181416
183064
|
init_logger();
|
|
181417
183065
|
await init_storage();
|
|
@@ -182012,6 +183660,7 @@ await __promiseAll([
|
|
|
182012
183660
|
init_read_session_chunk(),
|
|
182013
183661
|
init_read_session_db()
|
|
182014
183662
|
]);
|
|
183663
|
+
|
|
182015
183664
|
// src/hooks/magic-context/sentinel.ts
|
|
182016
183665
|
var WHOLE_MESSAGE_PLACEHOLDER_TEXT = "[dropped]";
|
|
182017
183666
|
function modelAcceptsEmptyContent(providerID) {
|
|
@@ -182069,7 +183718,6 @@ function replaySentinelByMessageIds(messages, ids, providerID) {
|
|
|
182069
183718
|
missingIds.push(id);
|
|
182070
183719
|
return { replayed, missingIds };
|
|
182071
183720
|
}
|
|
182072
|
-
|
|
182073
183721
|
// src/hooks/magic-context/strip-content.ts
|
|
182074
183722
|
var DROPPED_PLACEHOLDER_PATTERN = /^\[dropped §\d+§\]$/;
|
|
182075
183723
|
var TAG_PREFIX_PATTERN = /^§\d+§\s*/;
|
|
@@ -182422,8 +184070,10 @@ function stripReasoningFromMergedAssistants(messages, providerID) {
|
|
|
182422
184070
|
}
|
|
182423
184071
|
return stripped;
|
|
182424
184072
|
}
|
|
182425
|
-
function stripProcessedImages(messages,
|
|
184073
|
+
function stripProcessedImages(messages, frozenIds, options) {
|
|
184074
|
+
const { detect, watermark, messageTagNumbers } = options;
|
|
182426
184075
|
let stripped = 0;
|
|
184076
|
+
const newlyStrippedIds = [];
|
|
182427
184077
|
let hasAssistantResponse = false;
|
|
182428
184078
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
182429
184079
|
const msg = messages[i];
|
|
@@ -182431,13 +184081,17 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
182431
184081
|
hasAssistantResponse = true;
|
|
182432
184082
|
continue;
|
|
182433
184083
|
}
|
|
182434
|
-
if (msg.info.role !== "user"
|
|
184084
|
+
if (msg.info.role !== "user") {
|
|
182435
184085
|
continue;
|
|
182436
184086
|
}
|
|
184087
|
+
const id = typeof msg.info.id === "string" ? msg.info.id : undefined;
|
|
184088
|
+
const inFrozen = id !== undefined && frozenIds.has(id);
|
|
182437
184089
|
const maxTag = messageTagNumbers.get(msg) ?? 0;
|
|
182438
|
-
|
|
184090
|
+
const isNewDetection = !inFrozen && detect && hasAssistantResponse && id !== undefined && maxTag <= watermark;
|
|
184091
|
+
if (!inFrozen && !isNewDetection) {
|
|
182439
184092
|
continue;
|
|
182440
184093
|
}
|
|
184094
|
+
let touchedThisMsg = false;
|
|
182441
184095
|
for (let j = 0;j < msg.parts.length; j++) {
|
|
182442
184096
|
const part = msg.parts[j];
|
|
182443
184097
|
if (!isRecord(part) || part.type !== "file") {
|
|
@@ -182449,10 +184103,14 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
182449
184103
|
if (typeof part.url === "string" && part.url.startsWith("data:") && part.url.length > 200) {
|
|
182450
184104
|
msg.parts[j] = makeSentinel(part);
|
|
182451
184105
|
stripped++;
|
|
184106
|
+
touchedThisMsg = true;
|
|
182452
184107
|
}
|
|
182453
184108
|
}
|
|
184109
|
+
if (touchedThisMsg && isNewDetection && id !== undefined) {
|
|
184110
|
+
newlyStrippedIds.push(id);
|
|
184111
|
+
}
|
|
182454
184112
|
}
|
|
182455
|
-
return stripped;
|
|
184113
|
+
return { stripped, newlyStrippedIds };
|
|
182456
184114
|
}
|
|
182457
184115
|
|
|
182458
184116
|
// src/hooks/magic-context/transform.ts
|
|
@@ -183395,6 +185053,7 @@ init_embedding();
|
|
|
183395
185053
|
|
|
183396
185054
|
// src/features/magic-context/search.ts
|
|
183397
185055
|
init_logger();
|
|
185056
|
+
init_compartment_chunk_embedding();
|
|
183398
185057
|
|
|
183399
185058
|
// src/features/magic-context/literal-probes.ts
|
|
183400
185059
|
var MAX_PROBES = 5;
|
|
@@ -183456,6 +185115,7 @@ function containsProbeVerbatim(text, probes) {
|
|
|
183456
185115
|
init_memory();
|
|
183457
185116
|
init_embedding();
|
|
183458
185117
|
init_storage_memory_fts();
|
|
185118
|
+
init_workspaces();
|
|
183459
185119
|
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
183460
185120
|
var FTS_SEMANTIC_CANDIDATE_LIMIT = 50;
|
|
183461
185121
|
var SEMANTIC_WEIGHT = 0.7;
|
|
@@ -183485,6 +185145,37 @@ function previewText(text) {
|
|
|
183485
185145
|
}
|
|
183486
185146
|
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}…`;
|
|
183487
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
|
+
}
|
|
183488
185179
|
function getMessageSearchStatement(db) {
|
|
183489
185180
|
let stmt = messageSearchStatements.get(db);
|
|
183490
185181
|
if (!stmt) {
|
|
@@ -183493,6 +185184,30 @@ function getMessageSearchStatement(db) {
|
|
|
183493
185184
|
}
|
|
183494
185185
|
return stmt;
|
|
183495
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
|
+
}
|
|
183496
185211
|
function getMessageOrdinal(value) {
|
|
183497
185212
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
183498
185213
|
return value;
|
|
@@ -183508,25 +185223,63 @@ async function getSemanticScores(args) {
|
|
|
183508
185223
|
if (!args.queryEmbedding || args.memories.length === 0) {
|
|
183509
185224
|
return semanticScores;
|
|
183510
185225
|
}
|
|
183511
|
-
|
|
183512
|
-
|
|
183513
|
-
|
|
183514
|
-
|
|
183515
|
-
|
|
183516
|
-
|
|
183517
|
-
|
|
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;
|
|
183518
185248
|
for (const memory of args.memories) {
|
|
183519
|
-
const
|
|
183520
|
-
if (!
|
|
185249
|
+
const identity = memoryWorkspaceIdentity(memory, workspace);
|
|
185250
|
+
if (!identity)
|
|
183521
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)));
|
|
183522
185276
|
}
|
|
183523
|
-
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
|
|
183524
185277
|
}
|
|
183525
185278
|
return semanticScores;
|
|
183526
185279
|
}
|
|
183527
185280
|
function getFtsMatches(args) {
|
|
183528
185281
|
try {
|
|
183529
|
-
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);
|
|
183530
185283
|
} catch (error51) {
|
|
183531
185284
|
log(`[search] FTS query failed for "${args.query}": ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
183532
185285
|
return [];
|
|
@@ -183540,8 +185293,11 @@ function selectSemanticCandidates(args) {
|
|
|
183540
185293
|
return args.memories;
|
|
183541
185294
|
}
|
|
183542
185295
|
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
183543
|
-
const
|
|
183544
|
-
|
|
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;
|
|
183545
185301
|
for (const memoryId of cachedEmbeddings.keys()) {
|
|
183546
185302
|
candidateIds.add(memoryId);
|
|
183547
185303
|
}
|
|
@@ -183583,7 +185339,8 @@ function mergeMemoryResults(args) {
|
|
|
183583
185339
|
score,
|
|
183584
185340
|
memoryId: memory.id,
|
|
183585
185341
|
category: memory.category,
|
|
183586
|
-
matchType
|
|
185342
|
+
matchType,
|
|
185343
|
+
sourceName: args.sourceNameByMemoryId?.get(memory.id)
|
|
183587
185344
|
});
|
|
183588
185345
|
}
|
|
183589
185346
|
return results.sort((left, right) => {
|
|
@@ -183597,7 +185354,7 @@ async function searchMemories(args) {
|
|
|
183597
185354
|
if (!args.memoryEnabled) {
|
|
183598
185355
|
return [];
|
|
183599
185356
|
}
|
|
183600
|
-
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);
|
|
183601
185358
|
if (memories.length === 0) {
|
|
183602
185359
|
return [];
|
|
183603
185360
|
}
|
|
@@ -183605,26 +185362,43 @@ async function searchMemories(args) {
|
|
|
183605
185362
|
db: args.db,
|
|
183606
185363
|
projectPath: args.projectPath,
|
|
183607
185364
|
query: args.query,
|
|
183608
|
-
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
185365
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT,
|
|
185366
|
+
workspace: args.workspace
|
|
183609
185367
|
});
|
|
183610
185368
|
const ftsScores = getFtsScores(ftsMatches);
|
|
183611
185369
|
const semanticCandidates = selectSemanticCandidates({
|
|
183612
185370
|
memories,
|
|
183613
185371
|
projectPath: args.projectPath,
|
|
183614
|
-
ftsMatches
|
|
185372
|
+
ftsMatches,
|
|
185373
|
+
workspace: args.workspace
|
|
183615
185374
|
});
|
|
183616
185375
|
const semanticScores = await getSemanticScores({
|
|
183617
185376
|
db: args.db,
|
|
183618
185377
|
projectPath: args.projectPath,
|
|
183619
185378
|
memories: semanticCandidates,
|
|
183620
|
-
queryEmbedding: args.queryEmbedding
|
|
185379
|
+
queryEmbedding: args.queryEmbedding,
|
|
185380
|
+
queryModelId: args.queryModelId,
|
|
185381
|
+
workspace: args.workspace
|
|
183621
185382
|
});
|
|
183622
185383
|
return mergeMemoryResults({
|
|
183623
185384
|
memories,
|
|
183624
185385
|
semanticScores,
|
|
183625
185386
|
ftsScores,
|
|
183626
185387
|
limit: args.limit,
|
|
183627
|
-
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
|
+
})
|
|
183628
185402
|
});
|
|
183629
185403
|
}
|
|
183630
185404
|
function linearDecayScore(rank, total) {
|
|
@@ -183655,7 +185429,13 @@ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
|
|
|
183655
185429
|
return result;
|
|
183656
185430
|
}
|
|
183657
185431
|
var RRF_K = 60;
|
|
183658
|
-
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
|
+
}
|
|
183659
185439
|
function searchMessages(args) {
|
|
183660
185440
|
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
183661
185441
|
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
@@ -183672,20 +185452,31 @@ function searchMessages(args) {
|
|
|
183672
185452
|
role: row.role
|
|
183673
185453
|
}));
|
|
183674
185454
|
}
|
|
185455
|
+
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId);
|
|
183675
185456
|
const queryLists = [];
|
|
183676
185457
|
if (baseQuery.length > 0) {
|
|
183677
|
-
queryLists.push(
|
|
185458
|
+
queryLists.push({
|
|
185459
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff),
|
|
185460
|
+
weight: 1
|
|
185461
|
+
});
|
|
183678
185462
|
}
|
|
185463
|
+
const probeWeights = new Map;
|
|
183679
185464
|
for (const probe of probes) {
|
|
183680
185465
|
const probeQuery = sanitizeFtsQuery(probe);
|
|
183681
185466
|
if (probeQuery.length === 0)
|
|
183682
185467
|
continue;
|
|
183683
|
-
|
|
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
|
+
});
|
|
183684
185475
|
}
|
|
183685
185476
|
const fused = new Map;
|
|
183686
185477
|
for (const list of queryLists) {
|
|
183687
|
-
list.forEach((row, rank) => {
|
|
183688
|
-
const rrf =
|
|
185478
|
+
list.rows.forEach((row, rank) => {
|
|
185479
|
+
const rrf = list.weight / (RRF_K + rank);
|
|
183689
185480
|
const existing = fused.get(row.messageId);
|
|
183690
185481
|
if (existing) {
|
|
183691
185482
|
existing.score += rrf;
|
|
@@ -183695,26 +185486,107 @@ function searchMessages(args) {
|
|
|
183695
185486
|
});
|
|
183696
185487
|
}
|
|
183697
185488
|
for (const entry of fused.values()) {
|
|
183698
|
-
|
|
183699
|
-
|
|
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;
|
|
183700
185498
|
}
|
|
183701
185499
|
}
|
|
183702
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);
|
|
183703
|
-
|
|
183704
|
-
return ranked.map((entry) => ({
|
|
185501
|
+
return ranked.map((entry, rank) => ({
|
|
183705
185502
|
source: "message",
|
|
183706
185503
|
content: previewText(entry.row.content),
|
|
183707
|
-
score:
|
|
185504
|
+
score: linearDecayScore(rank, ranked.length),
|
|
183708
185505
|
messageOrdinal: entry.row.messageOrdinal,
|
|
183709
185506
|
messageId: entry.row.messageId,
|
|
183710
185507
|
role: entry.row.role
|
|
183711
185508
|
}));
|
|
183712
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
|
+
}
|
|
183713
185584
|
function getSourceBoost(result) {
|
|
183714
185585
|
switch (result.source) {
|
|
183715
185586
|
case "memory":
|
|
183716
185587
|
return MEMORY_SOURCE_BOOST;
|
|
183717
185588
|
case "message":
|
|
185589
|
+
case "compartment":
|
|
183718
185590
|
return MESSAGE_SOURCE_BOOST;
|
|
183719
185591
|
case "git_commit":
|
|
183720
185592
|
return GIT_COMMIT_SOURCE_BOOST;
|
|
@@ -183732,6 +185604,9 @@ function compareUnifiedResults(left, right) {
|
|
|
183732
185604
|
if (left.source === "message" && right.source === "message") {
|
|
183733
185605
|
return left.messageOrdinal - right.messageOrdinal;
|
|
183734
185606
|
}
|
|
185607
|
+
if (left.source === "compartment" && right.source === "compartment") {
|
|
185608
|
+
return left.startOrdinal - right.startOrdinal;
|
|
185609
|
+
}
|
|
183735
185610
|
if (left.source === "git_commit" && right.source === "git_commit") {
|
|
183736
185611
|
return right.committedAtMs - left.committedAtMs;
|
|
183737
185612
|
}
|
|
@@ -183782,10 +185657,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183782
185657
|
const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
|
|
183783
185658
|
const gitCommitsEnabled = options.gitCommitsEnabled ?? false;
|
|
183784
185659
|
const activeSources = resolveSources(options.sources);
|
|
183785
|
-
const
|
|
185660
|
+
const memoryFeatureEnabled = options.memoryEnabled ?? true;
|
|
185661
|
+
const runMemory = activeSources.has("memory") && memoryFeatureEnabled;
|
|
183786
185662
|
const runMessages = activeSources.has("message");
|
|
183787
185663
|
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
183788
|
-
const
|
|
185664
|
+
const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
|
|
185665
|
+
const needsEmbedding = (runMemory || runGitCommits || runCompartmentChunks) && embeddingEnabled && isEmbeddingRuntimeEnabled();
|
|
183789
185666
|
const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error51) => {
|
|
183790
185667
|
log(`[search] query embedding failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
183791
185668
|
return null;
|
|
@@ -183801,6 +185678,24 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183801
185678
|
probes: messageProbes
|
|
183802
185679
|
}) : [];
|
|
183803
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
|
+
});
|
|
183804
185699
|
const [memoryResults, gitCommitResults] = await Promise.all([
|
|
183805
185700
|
runMemory ? searchMemories({
|
|
183806
185701
|
db,
|
|
@@ -183809,6 +185704,8 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183809
185704
|
limit: tierLimit,
|
|
183810
185705
|
memoryEnabled: true,
|
|
183811
185706
|
queryEmbedding,
|
|
185707
|
+
queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null,
|
|
185708
|
+
workspace,
|
|
183812
185709
|
visibleMemoryIds: options.visibleMemoryIds
|
|
183813
185710
|
}) : Promise.resolve([]),
|
|
183814
185711
|
runGitCommits ? Promise.resolve(searchGitCommits({
|
|
@@ -183819,7 +185716,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183819
185716
|
queryEmbedding
|
|
183820
185717
|
})) : Promise.resolve([])
|
|
183821
185718
|
]);
|
|
183822
|
-
const results = [...memoryResults, ...
|
|
185719
|
+
const results = [...memoryResults, ...messageLikeResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
|
|
183823
185720
|
const countRetrievals = options.countRetrievals ?? true;
|
|
183824
185721
|
if (countRetrievals) {
|
|
183825
185722
|
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
@@ -183883,6 +185780,11 @@ function renderFragment(result, charCap) {
|
|
|
183883
185780
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
183884
185781
|
return truncate(compressed, charCap);
|
|
183885
185782
|
}
|
|
185783
|
+
case "compartment": {
|
|
185784
|
+
const source = result.snippet ?? result.title;
|
|
185785
|
+
const compressed = cavemanCompress(source, "ultra");
|
|
185786
|
+
return truncate(compressed, charCap);
|
|
185787
|
+
}
|
|
183886
185788
|
}
|
|
183887
185789
|
}
|
|
183888
185790
|
function buildAutoSearchHint(results, options = {}) {
|
|
@@ -184523,7 +186425,7 @@ function isVisibleNoteReadPart(part) {
|
|
|
184523
186425
|
}
|
|
184524
186426
|
|
|
184525
186427
|
// src/hooks/magic-context/todo-view.ts
|
|
184526
|
-
import { createHash as
|
|
186428
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
184527
186429
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
184528
186430
|
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
184529
186431
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
@@ -184568,7 +186470,7 @@ function buildSyntheticTodoPart(stateJson) {
|
|
|
184568
186470
|
};
|
|
184569
186471
|
}
|
|
184570
186472
|
function computeSyntheticCallId(stateJson) {
|
|
184571
|
-
const hash2 =
|
|
186473
|
+
const hash2 = createHash11("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
184572
186474
|
return `${SYNTHETIC_CALL_ID_PREFIX}${hash2}`;
|
|
184573
186475
|
}
|
|
184574
186476
|
function parseTodoState(stateJson) {
|
|
@@ -184619,15 +186521,25 @@ async function runPostTransformPhase(args) {
|
|
|
184619
186521
|
const emergencyBypassCompartmentGate = forceMaterialization;
|
|
184620
186522
|
const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
184621
186523
|
const materializationRequested = isExplicitFlush || deferredMaterialize;
|
|
184622
|
-
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;
|
|
184623
186534
|
const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
|
|
184624
186535
|
const hasPendingUserOps = pendingOps.length > 0;
|
|
184625
|
-
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization) && (!compartmentRunning || emergencyBypassCompartmentGate);
|
|
184626
|
-
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));
|
|
184627
186538
|
const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
|
|
186539
|
+
const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
|
|
184628
186540
|
if (shouldRunHeuristics) {
|
|
184629
186541
|
const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
|
|
184630
|
-
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})`;
|
|
184631
186543
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
|
|
184632
186544
|
}
|
|
184633
186545
|
if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
|
|
@@ -184670,7 +186582,9 @@ async function runPostTransformPhase(args) {
|
|
|
184670
186582
|
logTransformTiming(args.sessionId, "applyHeuristicCleanup", t5, `droppedTools=${cleanup.droppedTools} deduplicatedTools=${cleanup.deduplicatedTools} droppedInjections=${cleanup.droppedInjections} compressedTextTags=${cleanup.compressedTextTags}`);
|
|
184671
186583
|
const t7 = performance.now();
|
|
184672
186584
|
const clearedReasoning = clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge);
|
|
184673
|
-
|
|
186585
|
+
if (canUseEmptySentinels) {
|
|
186586
|
+
stripClearedReasoning(args.messages);
|
|
186587
|
+
}
|
|
184674
186588
|
const strippedInline = stripInlineThinking(args.messages, args.messageTagNumbers, args.clearReasoningAge);
|
|
184675
186589
|
if (clearedReasoning > 0 || strippedInline > 0) {
|
|
184676
186590
|
let maxTag = 0;
|
|
@@ -184716,7 +186630,6 @@ async function runPostTransformPhase(args) {
|
|
|
184716
186630
|
if (args.watermark > 0) {
|
|
184717
186631
|
const tWatermarkCleanup = performance.now();
|
|
184718
186632
|
truncateErroredTools(args.messages, args.watermark, args.messageTagNumbers);
|
|
184719
|
-
stripProcessedImages(args.messages, args.watermark, args.messageTagNumbers);
|
|
184720
186633
|
logTransformTiming(args.sessionId, "watermarkCleanup", tWatermarkCleanup);
|
|
184721
186634
|
}
|
|
184722
186635
|
if (shouldApplyPendingOps) {
|
|
@@ -184726,21 +186639,40 @@ async function runPostTransformPhase(args) {
|
|
|
184726
186639
|
sessionLog(args.sessionId, "transform failed applying pending operations:", error51);
|
|
184727
186640
|
updateSessionMeta(args.db, args.sessionId, { lastTransformError: getErrorMessage(error51) });
|
|
184728
186641
|
}
|
|
184729
|
-
|
|
184730
|
-
|
|
184731
|
-
|
|
184732
|
-
|
|
184733
|
-
|
|
184734
|
-
|
|
184735
|
-
|
|
184736
|
-
|
|
184737
|
-
|
|
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);
|
|
186656
|
+
}
|
|
186657
|
+
}
|
|
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);
|
|
184738
186673
|
}
|
|
184739
|
-
logTransformTiming(args.sessionId, "dropStaleReduceCalls", t8);
|
|
184740
|
-
} catch (error51) {
|
|
184741
|
-
sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error51);
|
|
184742
186674
|
}
|
|
184743
|
-
const m0M1Enabled =
|
|
186675
|
+
const m0M1Enabled = m0M1EnabledForFold;
|
|
184744
186676
|
if (m0M1Enabled && args.m0M1) {
|
|
184745
186677
|
const tInjectM0M1 = performance.now();
|
|
184746
186678
|
try {
|
|
@@ -184787,7 +186719,7 @@ async function runPostTransformPhase(args) {
|
|
|
184787
186719
|
const tPlaceholder = performance.now();
|
|
184788
186720
|
const persistedIds = getStrippedPlaceholderIds(args.db, args.sessionId);
|
|
184789
186721
|
if (persistedIds.size > 0) {
|
|
184790
|
-
const { replayed, missingIds } = replaySentinelByMessageIds(args.messages, persistedIds, args.
|
|
186722
|
+
const { replayed, missingIds } = replaySentinelByMessageIds(args.messages, persistedIds, args.resolvedProviderID);
|
|
184791
186723
|
if (replayed > 0) {
|
|
184792
186724
|
sessionLog(args.sessionId, `sentinel replay: neutralized ${replayed} previously-stripped messages`);
|
|
184793
186725
|
}
|
|
@@ -184798,9 +186730,9 @@ async function runPostTransformPhase(args) {
|
|
|
184798
186730
|
}
|
|
184799
186731
|
}
|
|
184800
186732
|
if (isCacheBustingPass) {
|
|
184801
|
-
const droppedResult = stripDroppedPlaceholderMessages(args.messages, args.
|
|
186733
|
+
const droppedResult = stripDroppedPlaceholderMessages(args.messages, args.resolvedProviderID);
|
|
184802
186734
|
const protectedTailStart = Math.max(0, args.messages.length - args.protectedTags * 2);
|
|
184803
|
-
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart, args.
|
|
186735
|
+
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart, args.resolvedProviderID);
|
|
184804
186736
|
const newlyNeutralized = droppedResult.sentineledIds.length + systemInjectedResult.sentineledIds.length;
|
|
184805
186737
|
if (newlyNeutralized > 0) {
|
|
184806
186738
|
const addedIds = [
|
|
@@ -185000,6 +186932,7 @@ function clearMessageTokensCache(sessionId, messageId) {
|
|
|
185000
186932
|
if (cache)
|
|
185001
186933
|
cache.delete(messageId);
|
|
185002
186934
|
}
|
|
186935
|
+
var recordedSessionProjectIdentity = new BoundedSessionMap(MESSAGE_TOKENS_CACHE_MAX);
|
|
185003
186936
|
function findLastAssistantModel2(messages) {
|
|
185004
186937
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
185005
186938
|
const info = messages[i].info;
|
|
@@ -185047,9 +186980,11 @@ function createTransform(deps) {
|
|
|
185047
186980
|
const fullFeatureMode = !reducedMode;
|
|
185048
186981
|
const ctxReduceEnabledEffective = deps.ctxReduceEnabled !== false && resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
|
|
185049
186982
|
let sessionDirectory = deps.directory ?? "";
|
|
186983
|
+
let sessionDirectoryResolvedFromHost = false;
|
|
185050
186984
|
const cachedDirectory = deps.sessionDirectoryBySession?.get(sessionId);
|
|
185051
186985
|
if (cachedDirectory && cachedDirectory.length > 0) {
|
|
185052
186986
|
sessionDirectory = cachedDirectory;
|
|
186987
|
+
sessionDirectoryResolvedFromHost = true;
|
|
185053
186988
|
} else if (deps.client !== undefined) {
|
|
185054
186989
|
try {
|
|
185055
186990
|
const sessionResponse = await deps.client.session.get({ path: { id: sessionId } }).catch(() => null);
|
|
@@ -185057,6 +186992,7 @@ function createTransform(deps) {
|
|
|
185057
186992
|
if (sessionInfo && typeof sessionInfo.directory === "string" && sessionInfo.directory.length > 0) {
|
|
185058
186993
|
sessionDirectory = sessionInfo.directory;
|
|
185059
186994
|
deps.sessionDirectoryBySession?.set(sessionId, sessionDirectory);
|
|
186995
|
+
sessionDirectoryResolvedFromHost = true;
|
|
185060
186996
|
}
|
|
185061
186997
|
} catch {}
|
|
185062
186998
|
}
|
|
@@ -185151,6 +187087,8 @@ function createTransform(deps) {
|
|
|
185151
187087
|
deps.liveModelBySession?.set(sessionId, recovered);
|
|
185152
187088
|
}
|
|
185153
187089
|
}
|
|
187090
|
+
const resolvedProviderID = modelForBudget?.providerID;
|
|
187091
|
+
const canUseEmptySentinels = modelAcceptsEmptyContent(resolvedProviderID);
|
|
185154
187092
|
const resolvedContextLimit = modelForBudget ? resolveTrustedContextLimit(modelForBudget.providerID, modelForBudget.modelID, {
|
|
185155
187093
|
db,
|
|
185156
187094
|
sessionID: sessionId
|
|
@@ -185315,6 +187253,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185315
187253
|
logTransformTiming(sessionId, "emergencyRecoveryBlock", tFirstPass);
|
|
185316
187254
|
const projectIdentity = deps.memoryConfig?.enabled ? resolveProjectIdentity(compartmentDirectory || process.cwd()) : undefined;
|
|
185317
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
|
+
}
|
|
185318
187260
|
let triggerBoundarySnapshot;
|
|
185319
187261
|
if (fullFeatureMode && historianRunnable && !sessionMeta.compartmentInProgress) {
|
|
185320
187262
|
const tTrigger = performance.now();
|
|
@@ -185409,7 +187351,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185409
187351
|
}
|
|
185410
187352
|
}
|
|
185411
187353
|
const t3 = performance.now();
|
|
185412
|
-
const strippedStructuralNoise = stripStructuralNoise(messages);
|
|
187354
|
+
const strippedStructuralNoise = canUseEmptySentinels ? stripStructuralNoise(messages) : 0;
|
|
185413
187355
|
logTransformTiming(sessionId, "stripStructuralNoise", t3, `strippedParts=${strippedStructuralNoise}`);
|
|
185414
187356
|
const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
|
|
185415
187357
|
if (persistedReasoningWatermark > 0) {
|
|
@@ -185430,18 +187372,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185430
187372
|
logTransformTiming(sessionId, "replayCavemanCompression", tCavemanReplay);
|
|
185431
187373
|
}
|
|
185432
187374
|
const t4 = performance.now();
|
|
185433
|
-
const strippedClearedReasoning = stripClearedReasoning(messages);
|
|
187375
|
+
const strippedClearedReasoning = canUseEmptySentinels ? stripClearedReasoning(messages) : 0;
|
|
185434
187376
|
logTransformTiming(sessionId, "stripClearedReasoning", t4, `strippedParts=${strippedClearedReasoning}`);
|
|
185435
187377
|
const tMergeStrip = performance.now();
|
|
185436
|
-
|
|
185437
|
-
if (liveProviderID === undefined) {
|
|
185438
|
-
const recovered = findLastAssistantModelFromOpenCodeDb(sessionId);
|
|
185439
|
-
if (recovered) {
|
|
185440
|
-
liveProviderID = recovered.providerID;
|
|
185441
|
-
deps.liveModelBySession?.set(sessionId, recovered);
|
|
185442
|
-
}
|
|
185443
|
-
}
|
|
185444
|
-
const strippedMergedReasoning = stripReasoningFromMergedAssistants(messages, liveProviderID);
|
|
187378
|
+
const strippedMergedReasoning = stripReasoningFromMergedAssistants(messages, resolvedProviderID);
|
|
185445
187379
|
if (strippedMergedReasoning > 0) {
|
|
185446
187380
|
sessionLog(sessionId, `stripped ${strippedMergedReasoning} reasoning parts from merged assistants (anthropic groupIntoBlocks workaround)`);
|
|
185447
187381
|
}
|
|
@@ -185560,7 +187494,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185560
187494
|
sessionDirectory,
|
|
185561
187495
|
autoSearch: deps.autoSearch,
|
|
185562
187496
|
cavemanTextCompression: deps.ctxReduceEnabled === false && !reducedMode ? deps.cavemanTextCompression : undefined,
|
|
185563
|
-
|
|
187497
|
+
resolvedProviderID,
|
|
185564
187498
|
historyRefreshSessions: deps.historyRefreshSessions,
|
|
185565
187499
|
m0M1: {
|
|
185566
187500
|
projectPath: projectIdentity,
|
|
@@ -186413,7 +188347,7 @@ function createToolExecuteAfterHook(args) {
|
|
|
186413
188347
|
init_send_session_notification();
|
|
186414
188348
|
|
|
186415
188349
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
186416
|
-
import { createHash as
|
|
188350
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
186417
188351
|
|
|
186418
188352
|
// src/agents/magic-context-prompt.ts
|
|
186419
188353
|
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
@@ -186613,7 +188547,7 @@ function createSystemPromptHashHandler(deps) {
|
|
|
186613
188547
|
`);
|
|
186614
188548
|
if (systemContent.length === 0)
|
|
186615
188549
|
return;
|
|
186616
|
-
const currentHash =
|
|
188550
|
+
const currentHash = createHash12("md5").update(systemContent).digest("hex");
|
|
186617
188551
|
if (!sessionMetaEarly) {
|
|
186618
188552
|
return;
|
|
186619
188553
|
}
|
|
@@ -186874,6 +188808,46 @@ function createMagicContextHook(deps) {
|
|
|
186874
188808
|
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
186875
188809
|
getNotificationParams: (sid) => getLiveNotificationParams(sid, liveModelBySession, variantBySession, agentBySession)
|
|
186876
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
|
+
};
|
|
186877
188851
|
const sidekickRunnable = isSidekickRunnable(deps.config);
|
|
186878
188852
|
const sidekickConfig = sidekickRunnable ? deps.config.sidekick : undefined;
|
|
186879
188853
|
const transform2 = createTransform({
|
|
@@ -187028,6 +189002,7 @@ function createMagicContextHook(deps) {
|
|
|
187028
189002
|
},
|
|
187029
189003
|
executeRecomp: historianRunnable ? async (sessionId, options) => runManagedRecomp(buildManagedRecompCtx(sessionId), sessionId, options) : undefined,
|
|
187030
189004
|
runUpgrade: historianRunnable ? async (sessionId) => runManagedUpgrade(buildManagedRecompCtx(sessionId), sessionId) : undefined,
|
|
189005
|
+
executeEmbedHistory,
|
|
187031
189006
|
sendNotification: async (sessionId, text, params) => {
|
|
187032
189007
|
await sendIgnoredMessage(deps.client, sessionId, text, {
|
|
187033
189008
|
...getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
|
|
@@ -188166,6 +190141,7 @@ init_memory();
|
|
|
188166
190141
|
init_embedding();
|
|
188167
190142
|
init_embedding_cache();
|
|
188168
190143
|
init_normalize_hash();
|
|
190144
|
+
init_workspaces();
|
|
188169
190145
|
init_logger();
|
|
188170
190146
|
await init_storage();
|
|
188171
190147
|
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
@@ -188325,6 +190301,23 @@ function createCtxMemoryTool(deps) {
|
|
|
188325
190301
|
}
|
|
188326
190302
|
const projectPath = deps.resolveProjectPath(toolContext.directory);
|
|
188327
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
|
+
};
|
|
188328
190321
|
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
188329
190322
|
if (embeddingSnapshot ? !embeddingSnapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
188330
190323
|
return getDisabledMessage();
|
|
@@ -188381,18 +190374,18 @@ function createCtxMemoryTool(deps) {
|
|
|
188381
190374
|
}
|
|
188382
190375
|
const rawProjectPath = projectPathForMemoryId(deps.db, updateId);
|
|
188383
190376
|
const memory = getMemoryById(deps.db, updateId);
|
|
188384
|
-
if (!memory || !rawProjectPath || !
|
|
190377
|
+
if (!memory || !rawProjectPath || !memoryVisibleToTool(memory)) {
|
|
188385
190378
|
return `Error: Memory with ID ${updateId} was not found.`;
|
|
188386
190379
|
}
|
|
188387
190380
|
if (toolContext.agent !== DREAMER_AGENT && !isPrimaryMutableMemory(memory)) {
|
|
188388
190381
|
return inactiveMemoryError(updateId, "updating");
|
|
188389
190382
|
}
|
|
188390
190383
|
const normalizedHash = computeNormalizedHash(content);
|
|
188391
|
-
const duplicate = getMemoryByHash(deps.db,
|
|
190384
|
+
const duplicate = getMemoryByHash(deps.db, targetIdentityForStoredPath(rawProjectPath), memory.category, normalizedHash);
|
|
188392
190385
|
if (duplicate && duplicate.id !== memory.id) {
|
|
188393
190386
|
return `Error: Memory content already exists as ID ${duplicate.id}; merge or archive duplicates instead.`;
|
|
188394
190387
|
}
|
|
188395
|
-
const projectIdentity =
|
|
190388
|
+
const projectIdentity = targetIdentityForStoredPath(rawProjectPath);
|
|
188396
190389
|
deps.db.transaction(() => {
|
|
188397
190390
|
updateMemoryContentInCurrentTransaction(deps.db, memory, content, normalizedHash);
|
|
188398
190391
|
queueMemoryMutation(deps.db, {
|
|
@@ -188406,7 +190399,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188406
190399
|
queueMemoryEmbedding({
|
|
188407
190400
|
deps,
|
|
188408
190401
|
sessionId: toolContext.sessionID,
|
|
188409
|
-
projectPath,
|
|
190402
|
+
projectPath: projectIdentity,
|
|
188410
190403
|
memoryId: memory.id,
|
|
188411
190404
|
content
|
|
188412
190405
|
});
|
|
@@ -188429,7 +190422,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188429
190422
|
return "Error: One or more source memories were not found.";
|
|
188430
190423
|
}
|
|
188431
190424
|
if (toolContext.agent !== DREAMER_AGENT) {
|
|
188432
|
-
const foreign = sourceMemories.find((memory) => !
|
|
190425
|
+
const foreign = sourceMemories.find((memory) => !memoryVisibleToTool(memory));
|
|
188433
190426
|
if (foreign) {
|
|
188434
190427
|
return `Error: Memory with ID ${foreign.id} was not found.`;
|
|
188435
190428
|
}
|
|
@@ -188513,15 +190506,16 @@ function createCtxMemoryTool(deps) {
|
|
|
188513
190506
|
return `Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`;
|
|
188514
190507
|
}
|
|
188515
190508
|
if (args.action === "archive") {
|
|
188516
|
-
const
|
|
188517
|
-
if (!
|
|
190509
|
+
const rawArchiveIds = args.ids;
|
|
190510
|
+
if (!rawArchiveIds || rawArchiveIds.length === 0 || !rawArchiveIds.every(Number.isInteger)) {
|
|
188518
190511
|
return "Error: 'ids' must contain at least one integer memory ID when action is 'archive'.";
|
|
188519
190512
|
}
|
|
190513
|
+
const archiveIds = [...new Set(rawArchiveIds)];
|
|
188520
190514
|
const targets = [];
|
|
188521
190515
|
for (const memoryId of archiveIds) {
|
|
188522
190516
|
const rawProjectPath = projectPathForMemoryId(deps.db, memoryId);
|
|
188523
190517
|
const memory = getMemoryById(deps.db, memoryId);
|
|
188524
|
-
if (!memory || !rawProjectPath || !
|
|
190518
|
+
if (!memory || !rawProjectPath || !memoryVisibleToTool(memory)) {
|
|
188525
190519
|
return `Error: Memory with ID ${memoryId} was not found.`;
|
|
188526
190520
|
}
|
|
188527
190521
|
if (toolContext.agent !== DREAMER_AGENT && !isPrimaryMutableMemory(memory)) {
|
|
@@ -188529,7 +190523,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188529
190523
|
}
|
|
188530
190524
|
targets.push({
|
|
188531
190525
|
memoryId,
|
|
188532
|
-
projectIdentity:
|
|
190526
|
+
projectIdentity: targetIdentityForStoredPath(rawProjectPath)
|
|
188533
190527
|
});
|
|
188534
190528
|
}
|
|
188535
190529
|
deps.db.transaction(() => {
|
|
@@ -189003,8 +190997,9 @@ function formatAge2(committedAtMs) {
|
|
|
189003
190997
|
}
|
|
189004
190998
|
function formatResult(result, index) {
|
|
189005
190999
|
if (result.source === "memory") {
|
|
191000
|
+
const source = result.sourceName ? ` source=${result.sourceName}` : "";
|
|
189006
191001
|
return [
|
|
189007
|
-
`[${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}`,
|
|
189008
191003
|
result.content
|
|
189009
191004
|
].join(`
|
|
189010
191005
|
`);
|
|
@@ -189014,6 +191009,13 @@ function formatResult(result, index) {
|
|
|
189014
191009
|
`[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge2(result.committedAtMs)} match=${result.matchType}`,
|
|
189015
191010
|
result.content
|
|
189016
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(`
|
|
189017
191019
|
`);
|
|
189018
191020
|
}
|
|
189019
191021
|
const expandStart = Math.max(1, result.messageOrdinal - 3);
|
|
@@ -189029,7 +191031,7 @@ function formatSearchResults(query, results) {
|
|
|
189029
191031
|
return `No results found for "${query}" across memories, git commits, or message history.`;
|
|
189030
191032
|
}
|
|
189031
191033
|
const bodyParts = results.map((result, index) => formatResult(result, index + 1));
|
|
189032
|
-
if (results.some((result) => result.source === "message")) {
|
|
191034
|
+
if (results.some((result) => result.source === "message" || result.source === "compartment")) {
|
|
189033
191035
|
bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
|
|
189034
191036
|
}
|
|
189035
191037
|
const body = bodyParts.join(`
|
|
@@ -189187,11 +191189,11 @@ import { createServer } from "node:http";
|
|
|
189187
191189
|
import { dirname as dirname5 } from "node:path";
|
|
189188
191190
|
|
|
189189
191191
|
// src/shared/rpc-utils.ts
|
|
189190
|
-
import { createHash as
|
|
191192
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
189191
191193
|
import { join as join20 } from "node:path";
|
|
189192
191194
|
function projectHash(directory) {
|
|
189193
191195
|
const normalized = directory.replace(/\/+$/, "");
|
|
189194
|
-
return
|
|
191196
|
+
return createHash13("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
189195
191197
|
}
|
|
189196
191198
|
function rpcPortDir(storageDir, directory) {
|
|
189197
191199
|
return join20(storageDir, "rpc", projectHash(directory));
|