@cortexkit/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/README.md +6 -0
- 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" };
|
|
@@ -15841,7 +15844,7 @@ function isSessionMetaRow(row) {
|
|
|
15841
15844
|
if (row === null || typeof row !== "object")
|
|
15842
15845
|
return false;
|
|
15843
15846
|
const r = row;
|
|
15844
|
-
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);
|
|
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) && 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);
|
|
15845
15848
|
}
|
|
15846
15849
|
function getDefaultSessionMeta(sessionId) {
|
|
15847
15850
|
return {
|
|
@@ -15868,6 +15871,7 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
15868
15871
|
cachedM0Bytes: null,
|
|
15869
15872
|
cachedM1Bytes: null,
|
|
15870
15873
|
cachedM0ProjectMemoryEpoch: null,
|
|
15874
|
+
cachedM0WorkspaceFingerprint: null,
|
|
15871
15875
|
cachedM0ProjectUserProfileVersion: null,
|
|
15872
15876
|
cachedM0MaxCompartmentSeq: null,
|
|
15873
15877
|
cachedM0MaxMemoryId: null,
|
|
@@ -15930,6 +15934,7 @@ function toSessionMeta(row) {
|
|
|
15930
15934
|
cachedM0Bytes: toBufferOrNull(row.cached_m0_bytes),
|
|
15931
15935
|
cachedM1Bytes: toBufferOrNull(row.cached_m1_bytes),
|
|
15932
15936
|
cachedM0ProjectMemoryEpoch: numOrNull(row.cached_m0_project_memory_epoch),
|
|
15937
|
+
cachedM0WorkspaceFingerprint: stringOrNull(row.cached_m0_workspace_fingerprint),
|
|
15933
15938
|
cachedM0ProjectUserProfileVersion: numOrNull(row.cached_m0_project_user_profile_version),
|
|
15934
15939
|
cachedM0MaxCompartmentSeq: numOrNull(row.cached_m0_max_compartment_seq),
|
|
15935
15940
|
cachedM0MaxMemoryId: numOrNull(row.cached_m0_max_memory_id),
|
|
@@ -15960,6 +15965,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
15960
15965
|
db.prepare(`UPDATE session_meta SET
|
|
15961
15966
|
cached_m0_bytes = ?,
|
|
15962
15967
|
cached_m0_project_memory_epoch = ?,
|
|
15968
|
+
cached_m0_workspace_fingerprint = ?,
|
|
15963
15969
|
cached_m0_project_user_profile_version = ?,
|
|
15964
15970
|
cached_m0_max_compartment_seq = ?,
|
|
15965
15971
|
cached_m0_max_memory_id = ?,
|
|
@@ -15972,7 +15978,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
15972
15978
|
cached_m0_upgrade_state = ?,
|
|
15973
15979
|
cached_m0_system_hash = ?,
|
|
15974
15980
|
cached_m0_model_key = ?
|
|
15975
|
-
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);
|
|
15981
|
+
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);
|
|
15976
15982
|
}
|
|
15977
15983
|
function clearCachedM0M1(db, sessionId) {
|
|
15978
15984
|
ensureSessionMetaRow(db, sessionId);
|
|
@@ -15981,6 +15987,7 @@ function clearCachedM0M1(db, sessionId) {
|
|
|
15981
15987
|
["cached_m0_bytes", null],
|
|
15982
15988
|
["cached_m1_bytes", null],
|
|
15983
15989
|
["cached_m0_project_memory_epoch", null],
|
|
15990
|
+
["cached_m0_workspace_fingerprint", null],
|
|
15984
15991
|
["cached_m0_project_user_profile_version", null],
|
|
15985
15992
|
["cached_m0_max_compartment_seq", null],
|
|
15986
15993
|
["cached_m0_max_memory_id", null],
|
|
@@ -16036,6 +16043,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16036
16043
|
"cached_m0_bytes",
|
|
16037
16044
|
"cached_m1_bytes",
|
|
16038
16045
|
"cached_m0_project_memory_epoch",
|
|
16046
|
+
"cached_m0_workspace_fingerprint",
|
|
16039
16047
|
"cached_m0_project_user_profile_version",
|
|
16040
16048
|
"cached_m0_max_compartment_seq",
|
|
16041
16049
|
"cached_m0_max_memory_id",
|
|
@@ -16083,6 +16091,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16083
16091
|
cachedM0Bytes: "cached_m0_bytes",
|
|
16084
16092
|
cachedM1Bytes: "cached_m1_bytes",
|
|
16085
16093
|
cachedM0ProjectMemoryEpoch: "cached_m0_project_memory_epoch",
|
|
16094
|
+
cachedM0WorkspaceFingerprint: "cached_m0_workspace_fingerprint",
|
|
16086
16095
|
cachedM0ProjectUserProfileVersion: "cached_m0_project_user_profile_version",
|
|
16087
16096
|
cachedM0MaxCompartmentSeq: "cached_m0_max_compartment_seq",
|
|
16088
16097
|
cachedM0MaxMemoryId: "cached_m0_max_memory_id",
|
|
@@ -16112,6 +16121,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16112
16121
|
"cachedM0Bytes",
|
|
16113
16122
|
"cachedM1Bytes",
|
|
16114
16123
|
"cachedM0ProjectMemoryEpoch",
|
|
16124
|
+
"cachedM0WorkspaceFingerprint",
|
|
16115
16125
|
"cachedM0ProjectUserProfileVersion",
|
|
16116
16126
|
"cachedM0MaxCompartmentSeq",
|
|
16117
16127
|
"cachedM0MaxMemoryId",
|
|
@@ -150823,6 +150833,35 @@ function initializeDatabase(db) {
|
|
|
150823
150833
|
);
|
|
150824
150834
|
CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
|
|
150825
150835
|
|
|
150836
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
150837
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
150838
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
150839
|
+
session_id TEXT NOT NULL,
|
|
150840
|
+
project_path TEXT NOT NULL,
|
|
150841
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
150842
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
150843
|
+
start_ordinal INTEGER NOT NULL,
|
|
150844
|
+
end_ordinal INTEGER NOT NULL,
|
|
150845
|
+
chunk_hash TEXT NOT NULL,
|
|
150846
|
+
model_id TEXT NOT NULL,
|
|
150847
|
+
dims INTEGER NOT NULL,
|
|
150848
|
+
vector BLOB NOT NULL,
|
|
150849
|
+
created_at INTEGER NOT NULL,
|
|
150850
|
+
UNIQUE(compartment_id, window_index)
|
|
150851
|
+
);
|
|
150852
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session ON compartment_chunk_embeddings(session_id);
|
|
150853
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model ON compartment_chunk_embeddings(project_path, model_id);
|
|
150854
|
+
|
|
150855
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
150856
|
+
session_id TEXT NOT NULL,
|
|
150857
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
150858
|
+
project_path TEXT NOT NULL,
|
|
150859
|
+
updated_at INTEGER NOT NULL,
|
|
150860
|
+
PRIMARY KEY(session_id, harness)
|
|
150861
|
+
);
|
|
150862
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
150863
|
+
ON session_projects(project_path);
|
|
150864
|
+
|
|
150826
150865
|
CREATE TABLE IF NOT EXISTS compartment_events (
|
|
150827
150866
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
150828
150867
|
session_id TEXT NOT NULL,
|
|
@@ -151008,6 +151047,25 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151008
151047
|
rekeyed_at INTEGER NOT NULL
|
|
151009
151048
|
);
|
|
151010
151049
|
|
|
151050
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
151051
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151052
|
+
name TEXT NOT NULL UNIQUE,
|
|
151053
|
+
created_at INTEGER NOT NULL,
|
|
151054
|
+
updated_at INTEGER NOT NULL,
|
|
151055
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
151056
|
+
);
|
|
151057
|
+
|
|
151058
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
151059
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
151060
|
+
project_path TEXT NOT NULL,
|
|
151061
|
+
display_name TEXT NOT NULL,
|
|
151062
|
+
display_path TEXT NOT NULL,
|
|
151063
|
+
added_at INTEGER NOT NULL,
|
|
151064
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
151065
|
+
);
|
|
151066
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
151067
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
151068
|
+
|
|
151011
151069
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
151012
151070
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151013
151071
|
table_name TEXT NOT NULL,
|
|
@@ -151119,6 +151177,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151119
151177
|
deferred_execute_state TEXT,
|
|
151120
151178
|
cached_m0_bytes BLOB,
|
|
151121
151179
|
cached_m0_project_memory_epoch INTEGER,
|
|
151180
|
+
cached_m0_workspace_fingerprint TEXT,
|
|
151122
151181
|
cached_m0_project_user_profile_version INTEGER,
|
|
151123
151182
|
cached_m0_max_compartment_seq INTEGER,
|
|
151124
151183
|
cached_m0_max_memory_id INTEGER,
|
|
@@ -151277,6 +151336,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151277
151336
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
151278
151337
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
151279
151338
|
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
151339
|
+
ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
|
|
151280
151340
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
151281
151341
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
151282
151342
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -151330,6 +151390,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151330
151390
|
ensureColumn(db, "memories", "importance", "INTEGER");
|
|
151331
151391
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
151332
151392
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
151393
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
151333
151394
|
ensureColumn(db, "session_meta", "cached_m0_project_user_profile_version", "INTEGER");
|
|
151334
151395
|
ensureColumn(db, "session_meta", "cached_m0_max_compartment_seq", "INTEGER");
|
|
151335
151396
|
ensureColumn(db, "session_meta", "cached_m0_max_memory_id", "INTEGER");
|
|
@@ -151361,6 +151422,15 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151361
151422
|
project_user_profile_version INTEGER NOT NULL DEFAULT 0,
|
|
151362
151423
|
updated_at INTEGER NOT NULL DEFAULT 0
|
|
151363
151424
|
);
|
|
151425
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
151426
|
+
session_id TEXT NOT NULL,
|
|
151427
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
151428
|
+
project_path TEXT NOT NULL,
|
|
151429
|
+
updated_at INTEGER NOT NULL,
|
|
151430
|
+
PRIMARY KEY(session_id, harness)
|
|
151431
|
+
);
|
|
151432
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
151433
|
+
ON session_projects(project_path);
|
|
151364
151434
|
CREATE TABLE IF NOT EXISTS m0_mutation_log (
|
|
151365
151435
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151366
151436
|
session_id TEXT NOT NULL,
|
|
@@ -151388,6 +151458,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151388
151458
|
new_project_path TEXT NOT NULL,
|
|
151389
151459
|
rekeyed_at INTEGER NOT NULL
|
|
151390
151460
|
);
|
|
151461
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
151462
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151463
|
+
name TEXT NOT NULL UNIQUE,
|
|
151464
|
+
created_at INTEGER NOT NULL,
|
|
151465
|
+
updated_at INTEGER NOT NULL,
|
|
151466
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
151467
|
+
);
|
|
151468
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
151469
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
151470
|
+
project_path TEXT NOT NULL,
|
|
151471
|
+
display_name TEXT NOT NULL,
|
|
151472
|
+
display_path TEXT NOT NULL,
|
|
151473
|
+
added_at INTEGER NOT NULL,
|
|
151474
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
151475
|
+
);
|
|
151476
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
151477
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
151391
151478
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
151392
151479
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151393
151480
|
table_name TEXT NOT NULL,
|
|
@@ -151409,6 +151496,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151409
151496
|
ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151410
151497
|
ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151411
151498
|
ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151499
|
+
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
151412
151500
|
}
|
|
151413
151501
|
function healAllNullColumns(db) {
|
|
151414
151502
|
healNullTextColumns(db);
|
|
@@ -151446,6 +151534,7 @@ function healNullTextColumns(db) {
|
|
|
151446
151534
|
["system_prompt_hash", ""],
|
|
151447
151535
|
["stripped_placeholder_ids", ""],
|
|
151448
151536
|
["stale_reduce_stripped_ids", ""],
|
|
151537
|
+
["processed_image_stripped_ids", ""],
|
|
151449
151538
|
["memory_block_cache", ""],
|
|
151450
151539
|
["memory_block_ids", ""],
|
|
151451
151540
|
["compaction_marker_state", ""],
|
|
@@ -151490,7 +151579,7 @@ function healNullIntegerColumns(db) {
|
|
|
151490
151579
|
}
|
|
151491
151580
|
}
|
|
151492
151581
|
function ensureColumn(db, table, column, definition) {
|
|
151493
|
-
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_'(),[\]\s]+$/i.test(definition)) {
|
|
151582
|
+
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_"'(),[\]\s]+$/i.test(definition)) {
|
|
151494
151583
|
throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
|
|
151495
151584
|
}
|
|
151496
151585
|
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
@@ -151576,7 +151665,7 @@ function getDatabasePersistenceError(db) {
|
|
|
151576
151665
|
return null;
|
|
151577
151666
|
return persistenceErrorByDatabase.get(db) ?? null;
|
|
151578
151667
|
}
|
|
151579
|
-
var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION =
|
|
151668
|
+
var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 36, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
|
|
151580
151669
|
var init_storage_db = __esm(async () => {
|
|
151581
151670
|
init_data_path();
|
|
151582
151671
|
init_logger();
|
|
@@ -151596,10 +151685,302 @@ var init_storage_db = __esm(async () => {
|
|
|
151596
151685
|
};
|
|
151597
151686
|
});
|
|
151598
151687
|
|
|
151688
|
+
// src/features/magic-context/memory/constants.ts
|
|
151689
|
+
var V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
151690
|
+
var init_constants = __esm(() => {
|
|
151691
|
+
V2_MEMORY_CATEGORIES = [
|
|
151692
|
+
"PROJECT_RULES",
|
|
151693
|
+
"ARCHITECTURE",
|
|
151694
|
+
"CONSTRAINTS",
|
|
151695
|
+
"CONFIG_VALUES",
|
|
151696
|
+
"NAMING"
|
|
151697
|
+
];
|
|
151698
|
+
PROMOTABLE_CATEGORIES = [
|
|
151699
|
+
"PROJECT_RULES",
|
|
151700
|
+
"ARCHITECTURE",
|
|
151701
|
+
"CONSTRAINTS",
|
|
151702
|
+
"CONFIG_VALUES",
|
|
151703
|
+
"NAMING",
|
|
151704
|
+
"ARCHITECTURE_DECISIONS",
|
|
151705
|
+
"CONFIG_DEFAULTS",
|
|
151706
|
+
"USER_PREFERENCES",
|
|
151707
|
+
"USER_DIRECTIVES",
|
|
151708
|
+
"ENVIRONMENT",
|
|
151709
|
+
"WORKFLOW_RULES",
|
|
151710
|
+
"KNOWN_ISSUES"
|
|
151711
|
+
];
|
|
151712
|
+
CATEGORY_PRIORITY = [
|
|
151713
|
+
"PROJECT_RULES",
|
|
151714
|
+
"ARCHITECTURE",
|
|
151715
|
+
"CONSTRAINTS",
|
|
151716
|
+
"CONFIG_VALUES",
|
|
151717
|
+
"NAMING",
|
|
151718
|
+
"USER_DIRECTIVES",
|
|
151719
|
+
"USER_PREFERENCES",
|
|
151720
|
+
"CONFIG_DEFAULTS",
|
|
151721
|
+
"ARCHITECTURE_DECISIONS",
|
|
151722
|
+
"ENVIRONMENT",
|
|
151723
|
+
"WORKFLOW_RULES",
|
|
151724
|
+
"KNOWN_ISSUES"
|
|
151725
|
+
];
|
|
151726
|
+
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
151727
|
+
acc[category] = index;
|
|
151728
|
+
return acc;
|
|
151729
|
+
}, {});
|
|
151730
|
+
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
151731
|
+
CATEGORY_DEFAULT_TTL = {
|
|
151732
|
+
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
151733
|
+
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
151734
|
+
};
|
|
151735
|
+
});
|
|
151736
|
+
|
|
151737
|
+
// src/features/magic-context/project-identity.ts
|
|
151738
|
+
var init_project_identity2 = __esm(() => {
|
|
151739
|
+
init_project_identity();
|
|
151740
|
+
});
|
|
151741
|
+
|
|
151742
|
+
// src/features/magic-context/workspaces.ts
|
|
151743
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
151744
|
+
function tableExists(db, tableName) {
|
|
151745
|
+
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ? LIMIT 1").get(tableName);
|
|
151746
|
+
return Boolean(row);
|
|
151747
|
+
}
|
|
151748
|
+
function columnExists(db, tableName, columnName) {
|
|
151749
|
+
const rows = db.prepare(`PRAGMA table_info(${tableName})`).all();
|
|
151750
|
+
return rows.some((row) => row.name === columnName);
|
|
151751
|
+
}
|
|
151752
|
+
function uniqueSorted(values) {
|
|
151753
|
+
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
151754
|
+
}
|
|
151755
|
+
function placeholders(values) {
|
|
151756
|
+
return values.map(() => "?").join(", ");
|
|
151757
|
+
}
|
|
151758
|
+
function normalizeShareCategories(raw) {
|
|
151759
|
+
if (raw === null || raw === undefined)
|
|
151760
|
+
return null;
|
|
151761
|
+
if (typeof raw !== "string")
|
|
151762
|
+
return null;
|
|
151763
|
+
let parsed;
|
|
151764
|
+
try {
|
|
151765
|
+
parsed = JSON.parse(raw);
|
|
151766
|
+
} catch {
|
|
151767
|
+
return null;
|
|
151768
|
+
}
|
|
151769
|
+
if (!Array.isArray(parsed))
|
|
151770
|
+
return null;
|
|
151771
|
+
const categories = [];
|
|
151772
|
+
for (const value of parsed) {
|
|
151773
|
+
if (typeof value !== "string" || !VALID_SHARE_CATEGORIES.has(value)) {
|
|
151774
|
+
return null;
|
|
151775
|
+
}
|
|
151776
|
+
if (!categories.includes(value))
|
|
151777
|
+
categories.push(value);
|
|
151778
|
+
}
|
|
151779
|
+
return categories.sort((left, right) => left.localeCompare(right));
|
|
151780
|
+
}
|
|
151781
|
+
function selectWorkspaceShareCategories(db, identities) {
|
|
151782
|
+
const candidates = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
151783
|
+
if (candidates.length === 0 || !tableExists(db, "workspace_members") || !tableExists(db, "workspaces") || !columnExists(db, "workspaces", "share_categories")) {
|
|
151784
|
+
return null;
|
|
151785
|
+
}
|
|
151786
|
+
const row = db.prepare(`SELECT workspace.share_categories AS shareCategories
|
|
151787
|
+
FROM workspace_members AS member
|
|
151788
|
+
JOIN workspaces AS workspace ON workspace.id = member.workspace_id
|
|
151789
|
+
WHERE member.project_path IN (${placeholders(candidates)})
|
|
151790
|
+
ORDER BY workspace.id ASC
|
|
151791
|
+
LIMIT 1`).get(...candidates);
|
|
151792
|
+
return normalizeShareCategories(row?.shareCategories ?? null);
|
|
151793
|
+
}
|
|
151794
|
+
function resolveWorkspaceShareCategories(db, projectIdentity) {
|
|
151795
|
+
return selectWorkspaceShareCategories(db, [projectIdentity]);
|
|
151796
|
+
}
|
|
151797
|
+
function resolveWorkspaceIdentitySet(db, projectIdentity) {
|
|
151798
|
+
if (!tableExists(db, "workspace_members")) {
|
|
151799
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
151800
|
+
}
|
|
151801
|
+
const rows = db.prepare(`SELECT member.project_path AS identity, member.display_name AS displayName
|
|
151802
|
+
FROM workspace_members AS anchor
|
|
151803
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
151804
|
+
WHERE anchor.project_path = ?
|
|
151805
|
+
ORDER BY member.display_name ASC, member.project_path ASC`).all(projectIdentity);
|
|
151806
|
+
if (rows.length === 0) {
|
|
151807
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
151808
|
+
}
|
|
151809
|
+
const namesByIdentity = new Map;
|
|
151810
|
+
const identities = [];
|
|
151811
|
+
for (const row of rows) {
|
|
151812
|
+
if (typeof row.identity !== "string" || row.identity.length === 0)
|
|
151813
|
+
continue;
|
|
151814
|
+
if (identities.includes(row.identity))
|
|
151815
|
+
continue;
|
|
151816
|
+
identities.push(row.identity);
|
|
151817
|
+
if (typeof row.displayName === "string" && row.displayName.length > 0) {
|
|
151818
|
+
namesByIdentity.set(row.identity, row.displayName);
|
|
151819
|
+
}
|
|
151820
|
+
}
|
|
151821
|
+
return identities.length > 0 ? { identities, namesByIdentity } : { identities: [projectIdentity], namesByIdentity: new Map };
|
|
151822
|
+
}
|
|
151823
|
+
function expandWorkspaceIdentitySetWithAliases(db, identities) {
|
|
151824
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
151825
|
+
const expanded = new Set(canonical);
|
|
151826
|
+
const canonicalIdentityByStoredPath = new Map;
|
|
151827
|
+
for (const identity of canonical) {
|
|
151828
|
+
canonicalIdentityByStoredPath.set(identity, identity);
|
|
151829
|
+
}
|
|
151830
|
+
if (canonical.length === 0 || !tableExists(db, "v22_identity_rekey_map")) {
|
|
151831
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
151832
|
+
}
|
|
151833
|
+
const rows = db.prepare(`SELECT old_project_path AS oldProjectPath, new_project_path AS newProjectPath
|
|
151834
|
+
FROM v22_identity_rekey_map
|
|
151835
|
+
WHERE new_project_path IN (${placeholders(canonical)})
|
|
151836
|
+
ORDER BY old_project_path ASC`).all(...canonical);
|
|
151837
|
+
for (const row of rows) {
|
|
151838
|
+
if (typeof row.oldProjectPath !== "string" || typeof row.newProjectPath !== "string") {
|
|
151839
|
+
continue;
|
|
151840
|
+
}
|
|
151841
|
+
if (!canonicalIdentityByStoredPath.has(row.newProjectPath))
|
|
151842
|
+
continue;
|
|
151843
|
+
expanded.add(row.oldProjectPath);
|
|
151844
|
+
canonicalIdentityByStoredPath.set(row.oldProjectPath, row.newProjectPath);
|
|
151845
|
+
}
|
|
151846
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
151847
|
+
}
|
|
151848
|
+
function resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) {
|
|
151849
|
+
const direct = canonicalIdentityByStoredPath.get(storedProjectPath);
|
|
151850
|
+
if (direct)
|
|
151851
|
+
return direct;
|
|
151852
|
+
const normalized = normalizeStoredProjectPath(storedProjectPath);
|
|
151853
|
+
const normalizedDirect = canonicalIdentityByStoredPath.get(normalized);
|
|
151854
|
+
if (normalizedDirect)
|
|
151855
|
+
return normalizedDirect;
|
|
151856
|
+
if (memberIdentities.includes(normalized))
|
|
151857
|
+
return normalized;
|
|
151858
|
+
for (const identity of memberIdentities) {
|
|
151859
|
+
if (storedPathBelongsToIdentity(storedProjectPath, identity)) {
|
|
151860
|
+
return identity;
|
|
151861
|
+
}
|
|
151862
|
+
}
|
|
151863
|
+
return null;
|
|
151864
|
+
}
|
|
151865
|
+
function storedPathBelongsToWorkspace(storedProjectPath, memberIdentities, expandedIdentities, canonicalIdentityByStoredPath) {
|
|
151866
|
+
if (expandedIdentities.includes(storedProjectPath))
|
|
151867
|
+
return true;
|
|
151868
|
+
return resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) !== null;
|
|
151869
|
+
}
|
|
151870
|
+
function sourceNameForMemory(storedProjectPath, ownIdentity, memberIdentities, namesByIdentity, canonicalIdentityByStoredPath) {
|
|
151871
|
+
const canonicalIdentity = resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath);
|
|
151872
|
+
if (!canonicalIdentity || canonicalIdentity === ownIdentity)
|
|
151873
|
+
return;
|
|
151874
|
+
return namesByIdentity.get(canonicalIdentity);
|
|
151875
|
+
}
|
|
151876
|
+
function getEpochMap(db, identities) {
|
|
151877
|
+
if (identities.length === 0)
|
|
151878
|
+
return new Map;
|
|
151879
|
+
const rows = db.prepare(`SELECT project_path AS projectPath, project_memory_epoch AS epoch
|
|
151880
|
+
FROM project_state
|
|
151881
|
+
WHERE project_path IN (${placeholders(identities)})`).all(...identities);
|
|
151882
|
+
const epochs = new Map;
|
|
151883
|
+
for (const row of rows) {
|
|
151884
|
+
if (typeof row.projectPath !== "string" || typeof row.epoch !== "number")
|
|
151885
|
+
continue;
|
|
151886
|
+
epochs.set(row.projectPath, row.epoch);
|
|
151887
|
+
}
|
|
151888
|
+
return epochs;
|
|
151889
|
+
}
|
|
151890
|
+
function computeWorkspaceEpochFingerprint(db, identities) {
|
|
151891
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
151892
|
+
const epochs = getEpochMap(db, canonical);
|
|
151893
|
+
const shareCategories = selectWorkspaceShareCategories(db, canonical);
|
|
151894
|
+
const hash2 = createHash4("sha256");
|
|
151895
|
+
hash2.update("share_categories", "utf8");
|
|
151896
|
+
hash2.update("\x00");
|
|
151897
|
+
hash2.update(shareCategories === null ? "ALL" : JSON.stringify(shareCategories), "utf8");
|
|
151898
|
+
hash2.update(`
|
|
151899
|
+
`);
|
|
151900
|
+
for (const identity of canonical) {
|
|
151901
|
+
hash2.update(identity, "utf8");
|
|
151902
|
+
hash2.update("\x00");
|
|
151903
|
+
hash2.update(String(epochs.get(identity) ?? 0), "utf8");
|
|
151904
|
+
hash2.update(`
|
|
151905
|
+
`);
|
|
151906
|
+
}
|
|
151907
|
+
return hash2.digest("hex");
|
|
151908
|
+
}
|
|
151909
|
+
function isInTransaction(db) {
|
|
151910
|
+
const candidate = db;
|
|
151911
|
+
return candidate.inTransaction === true || candidate.isTransaction === true;
|
|
151912
|
+
}
|
|
151913
|
+
function workspaceMembersForIdentity(db, identity) {
|
|
151914
|
+
if (!tableExists(db, "workspace_members"))
|
|
151915
|
+
return [identity];
|
|
151916
|
+
const rows = db.prepare(`SELECT member.project_path AS identity
|
|
151917
|
+
FROM workspace_members AS anchor
|
|
151918
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
151919
|
+
WHERE anchor.project_path = ?
|
|
151920
|
+
ORDER BY member.project_path ASC`).all(identity);
|
|
151921
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((value) => value.length > 0);
|
|
151922
|
+
return identities.length > 0 ? uniqueSorted(identities) : [identity];
|
|
151923
|
+
}
|
|
151924
|
+
function bumpEpochRows(db, identities, now) {
|
|
151925
|
+
const stmt = db.prepare(`INSERT INTO project_state
|
|
151926
|
+
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
151927
|
+
VALUES (?, 1, 0, ?)
|
|
151928
|
+
ON CONFLICT(project_path) DO UPDATE SET
|
|
151929
|
+
project_memory_epoch = project_memory_epoch + 1,
|
|
151930
|
+
updated_at = excluded.updated_at`);
|
|
151931
|
+
for (const identity of uniqueSorted(identities)) {
|
|
151932
|
+
stmt.run(identity, now);
|
|
151933
|
+
}
|
|
151934
|
+
}
|
|
151935
|
+
function bumpEpochsForWorkspaceMembers(db, identity, now = Date.now()) {
|
|
151936
|
+
const run = () => bumpEpochRows(db, workspaceMembersForIdentity(db, identity), now);
|
|
151937
|
+
if (isInTransaction(db)) {
|
|
151938
|
+
run();
|
|
151939
|
+
return;
|
|
151940
|
+
}
|
|
151941
|
+
db.exec("BEGIN IMMEDIATE");
|
|
151942
|
+
try {
|
|
151943
|
+
run();
|
|
151944
|
+
db.exec("COMMIT");
|
|
151945
|
+
} catch (error51) {
|
|
151946
|
+
try {
|
|
151947
|
+
db.exec("ROLLBACK");
|
|
151948
|
+
} catch {}
|
|
151949
|
+
throw error51;
|
|
151950
|
+
}
|
|
151951
|
+
}
|
|
151952
|
+
function bumpEpochsForWorkspaceMemberSet(db, identities, now = Date.now()) {
|
|
151953
|
+
const run = () => bumpEpochRows(db, identities, now);
|
|
151954
|
+
if (isInTransaction(db)) {
|
|
151955
|
+
run();
|
|
151956
|
+
return;
|
|
151957
|
+
}
|
|
151958
|
+
db.exec("BEGIN IMMEDIATE");
|
|
151959
|
+
try {
|
|
151960
|
+
run();
|
|
151961
|
+
db.exec("COMMIT");
|
|
151962
|
+
} catch (error51) {
|
|
151963
|
+
try {
|
|
151964
|
+
db.exec("ROLLBACK");
|
|
151965
|
+
} catch {}
|
|
151966
|
+
throw error51;
|
|
151967
|
+
}
|
|
151968
|
+
}
|
|
151969
|
+
var VALID_SHARE_CATEGORIES;
|
|
151970
|
+
var init_workspaces = __esm(() => {
|
|
151971
|
+
init_constants();
|
|
151972
|
+
init_project_identity2();
|
|
151973
|
+
VALID_SHARE_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
151974
|
+
});
|
|
151975
|
+
|
|
151599
151976
|
// src/features/magic-context/migrations.ts
|
|
151600
|
-
function
|
|
151977
|
+
function tableExists2(db, name2) {
|
|
151601
151978
|
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name2));
|
|
151602
151979
|
}
|
|
151980
|
+
function columnExists2(db, table, column) {
|
|
151981
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
151982
|
+
return rows.some((row) => row.name === column);
|
|
151983
|
+
}
|
|
151603
151984
|
function ensureMigrationsTable(db) {
|
|
151604
151985
|
db.exec(`
|
|
151605
151986
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
@@ -151668,6 +152049,7 @@ function runMigrations(db) {
|
|
|
151668
152049
|
var MIGRATIONS, LATEST_MIGRATION_VERSION;
|
|
151669
152050
|
var init_migrations = __esm(async () => {
|
|
151670
152051
|
init_logger();
|
|
152052
|
+
init_workspaces();
|
|
151671
152053
|
await init_storage_db();
|
|
151672
152054
|
MIGRATIONS = [
|
|
151673
152055
|
{
|
|
@@ -152127,9 +152509,9 @@ var init_migrations = __esm(async () => {
|
|
|
152127
152509
|
version: 22,
|
|
152128
152510
|
description: "v2.0 cache architecture schema foundation",
|
|
152129
152511
|
up: (db) => {
|
|
152130
|
-
const hasSessionMetaTable =
|
|
152131
|
-
const hasCompartmentsTable =
|
|
152132
|
-
const hasMemoriesTable =
|
|
152512
|
+
const hasSessionMetaTable = tableExists2(db, "session_meta");
|
|
152513
|
+
const hasCompartmentsTable = tableExists2(db, "compartments");
|
|
152514
|
+
const hasMemoriesTable = tableExists2(db, "memories");
|
|
152133
152515
|
if (hasSessionMetaTable) {
|
|
152134
152516
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
152135
152517
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
@@ -152154,7 +152536,7 @@ var init_migrations = __esm(async () => {
|
|
|
152154
152536
|
ensureColumn(db, "compartments", "p1_embedding_model_id", "TEXT");
|
|
152155
152537
|
ensureColumn(db, "compartments", "legacy", "INTEGER NOT NULL DEFAULT 0");
|
|
152156
152538
|
}
|
|
152157
|
-
const hasRecompCompartmentsTable =
|
|
152539
|
+
const hasRecompCompartmentsTable = tableExists2(db, "recomp_compartments");
|
|
152158
152540
|
if (hasRecompCompartmentsTable) {
|
|
152159
152541
|
ensureColumn(db, "recomp_compartments", "p1", "TEXT");
|
|
152160
152542
|
ensureColumn(db, "recomp_compartments", "p2", "TEXT");
|
|
@@ -152465,13 +152847,163 @@ var init_migrations = __esm(async () => {
|
|
|
152465
152847
|
db.prepare("UPDATE session_meta SET force_emergency_bypass_used = 0 WHERE force_emergency_bypass_used IS NULL").run();
|
|
152466
152848
|
db.prepare("UPDATE session_meta SET last_usage_context_limit = 0 WHERE last_usage_context_limit IS NULL").run();
|
|
152467
152849
|
}
|
|
152850
|
+
},
|
|
152851
|
+
{
|
|
152852
|
+
version: 33,
|
|
152853
|
+
description: "Compartment chunk embeddings for semantic message-history search",
|
|
152854
|
+
up: (db) => {
|
|
152855
|
+
db.exec(`
|
|
152856
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
152857
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152858
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
152859
|
+
session_id TEXT NOT NULL,
|
|
152860
|
+
project_path TEXT NOT NULL,
|
|
152861
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
152862
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
152863
|
+
start_ordinal INTEGER NOT NULL,
|
|
152864
|
+
end_ordinal INTEGER NOT NULL,
|
|
152865
|
+
chunk_hash TEXT NOT NULL,
|
|
152866
|
+
model_id TEXT NOT NULL,
|
|
152867
|
+
dims INTEGER NOT NULL,
|
|
152868
|
+
vector BLOB NOT NULL,
|
|
152869
|
+
created_at INTEGER NOT NULL,
|
|
152870
|
+
UNIQUE(compartment_id, window_index)
|
|
152871
|
+
);
|
|
152872
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session
|
|
152873
|
+
ON compartment_chunk_embeddings(session_id);
|
|
152874
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model
|
|
152875
|
+
ON compartment_chunk_embeddings(project_path, model_id);
|
|
152876
|
+
`);
|
|
152877
|
+
}
|
|
152878
|
+
},
|
|
152879
|
+
{
|
|
152880
|
+
version: 34,
|
|
152881
|
+
description: "workspace tables and m[0] workspace fingerprint cache reset",
|
|
152882
|
+
up: (db) => {
|
|
152883
|
+
db.exec(`
|
|
152884
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
152885
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152886
|
+
name TEXT NOT NULL UNIQUE,
|
|
152887
|
+
created_at INTEGER NOT NULL,
|
|
152888
|
+
updated_at INTEGER NOT NULL
|
|
152889
|
+
);
|
|
152890
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
152891
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
152892
|
+
project_path TEXT NOT NULL,
|
|
152893
|
+
display_name TEXT NOT NULL,
|
|
152894
|
+
display_path TEXT NOT NULL,
|
|
152895
|
+
added_at INTEGER NOT NULL,
|
|
152896
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
152897
|
+
);
|
|
152898
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique
|
|
152899
|
+
ON workspace_members(project_path);
|
|
152900
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name
|
|
152901
|
+
ON workspace_members(workspace_id, display_name);
|
|
152902
|
+
`);
|
|
152903
|
+
const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
|
|
152904
|
+
if (!hasSessionMeta)
|
|
152905
|
+
return;
|
|
152906
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
152907
|
+
const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
|
|
152908
|
+
const clears = [
|
|
152909
|
+
["cached_m0_bytes", null],
|
|
152910
|
+
["cached_m1_bytes", null],
|
|
152911
|
+
["cached_m0_project_memory_epoch", null],
|
|
152912
|
+
["cached_m0_workspace_fingerprint", null],
|
|
152913
|
+
["cached_m0_project_user_profile_version", null],
|
|
152914
|
+
["cached_m0_max_compartment_seq", null],
|
|
152915
|
+
["cached_m0_max_memory_id", null],
|
|
152916
|
+
["cached_m0_max_mutation_id", null],
|
|
152917
|
+
["cached_m0_max_memory_mutation_id", null],
|
|
152918
|
+
["cached_m0_project_docs_hash", null],
|
|
152919
|
+
["cached_m0_materialized_at", null],
|
|
152920
|
+
["cached_m0_session_facts_version", null],
|
|
152921
|
+
["cached_m0_upgrade_state", null],
|
|
152922
|
+
["cached_m0_system_hash", null],
|
|
152923
|
+
["cached_m0_tool_set_hash", null],
|
|
152924
|
+
["cached_m0_model_key", null],
|
|
152925
|
+
["cached_m0_last_baseline_end_message_id", null],
|
|
152926
|
+
["memory_block_cache", ""],
|
|
152927
|
+
["memory_block_ids", ""],
|
|
152928
|
+
["memory_block_count", 0]
|
|
152929
|
+
];
|
|
152930
|
+
const setClauses = [];
|
|
152931
|
+
const values = [];
|
|
152932
|
+
for (const [column, value] of clears) {
|
|
152933
|
+
if (!columns.has(column))
|
|
152934
|
+
continue;
|
|
152935
|
+
setClauses.push(`${column} = ?`);
|
|
152936
|
+
values.push(value);
|
|
152937
|
+
}
|
|
152938
|
+
if (setClauses.length > 0) {
|
|
152939
|
+
db.prepare(`UPDATE session_meta SET ${setClauses.join(", ")}`).run(...values);
|
|
152940
|
+
}
|
|
152941
|
+
}
|
|
152942
|
+
},
|
|
152943
|
+
{
|
|
152944
|
+
version: 35,
|
|
152945
|
+
description: "workspace per-category share defaults and epoch refresh",
|
|
152946
|
+
up: (db) => {
|
|
152947
|
+
db.exec(`
|
|
152948
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
152949
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152950
|
+
name TEXT NOT NULL UNIQUE,
|
|
152951
|
+
created_at INTEGER NOT NULL,
|
|
152952
|
+
updated_at INTEGER NOT NULL,
|
|
152953
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
152954
|
+
);
|
|
152955
|
+
`);
|
|
152956
|
+
if (!columnExists2(db, "workspaces", "share_categories")) {
|
|
152957
|
+
db.exec(`ALTER TABLE workspaces ADD COLUMN share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
152958
|
+
}
|
|
152959
|
+
db.prepare(`UPDATE workspaces
|
|
152960
|
+
SET share_categories = '["CONSTRAINTS"]'
|
|
152961
|
+
WHERE share_categories IS NULL OR share_categories = ''`).run();
|
|
152962
|
+
if (!tableExists2(db, "workspace_members"))
|
|
152963
|
+
return;
|
|
152964
|
+
const rows = db.prepare(`SELECT DISTINCT project_path AS identity
|
|
152965
|
+
FROM workspace_members
|
|
152966
|
+
WHERE project_path IS NOT NULL AND project_path <> ''
|
|
152967
|
+
ORDER BY project_path ASC`).all();
|
|
152968
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((identity) => identity.length > 0);
|
|
152969
|
+
if (identities.length > 0) {
|
|
152970
|
+
bumpEpochsForWorkspaceMemberSet(db, identities, Date.now());
|
|
152971
|
+
}
|
|
152972
|
+
}
|
|
152973
|
+
},
|
|
152974
|
+
{
|
|
152975
|
+
version: 36,
|
|
152976
|
+
description: "session project ownership map for compartment chunk backfill scoping",
|
|
152977
|
+
up: (db) => {
|
|
152978
|
+
db.exec(`
|
|
152979
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
152980
|
+
session_id TEXT NOT NULL,
|
|
152981
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
152982
|
+
project_path TEXT NOT NULL,
|
|
152983
|
+
updated_at INTEGER NOT NULL,
|
|
152984
|
+
PRIMARY KEY(session_id, harness)
|
|
152985
|
+
);
|
|
152986
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
152987
|
+
ON session_projects(project_path);
|
|
152988
|
+
`);
|
|
152989
|
+
const hasChunkTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='compartment_chunk_embeddings'").get();
|
|
152990
|
+
if (hasChunkTable) {
|
|
152991
|
+
db.exec(`
|
|
152992
|
+
INSERT OR IGNORE INTO session_projects (session_id, harness, project_path, updated_at)
|
|
152993
|
+
SELECT session_id, harness, MIN(project_path), 0
|
|
152994
|
+
FROM compartment_chunk_embeddings
|
|
152995
|
+
GROUP BY session_id, harness
|
|
152996
|
+
HAVING COUNT(DISTINCT project_path) = 1;
|
|
152997
|
+
`);
|
|
152998
|
+
}
|
|
152999
|
+
}
|
|
152468
153000
|
}
|
|
152469
153001
|
];
|
|
152470
153002
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
152471
153003
|
});
|
|
152472
153004
|
|
|
152473
153005
|
// src/features/magic-context/project-docs-hash.ts
|
|
152474
|
-
import { createHash as
|
|
153006
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
152475
153007
|
import { lstatSync, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
|
|
152476
153008
|
import path4 from "node:path";
|
|
152477
153009
|
function canonicalizeDocContent(raw) {
|
|
@@ -152561,7 +153093,7 @@ function hashCanonicalPieces(hashPieces) {
|
|
|
152561
153093
|
if (hashPieces.length === 0) {
|
|
152562
153094
|
return "";
|
|
152563
153095
|
}
|
|
152564
|
-
return
|
|
153096
|
+
return createHash5("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
|
|
152565
153097
|
}
|
|
152566
153098
|
function readProjectDocsCanonical(projectDirectory) {
|
|
152567
153099
|
const canonicalDirectory = path4.resolve(projectDirectory);
|
|
@@ -152599,11 +153131,6 @@ var init_project_docs_hash = __esm(() => {
|
|
|
152599
153131
|
MAX_PROJECT_DOC_BYTES = 256 * 1024;
|
|
152600
153132
|
docsCache = new Map;
|
|
152601
153133
|
});
|
|
152602
|
-
|
|
152603
|
-
// src/features/magic-context/project-identity.ts
|
|
152604
|
-
var init_project_identity2 = __esm(() => {
|
|
152605
|
-
init_project_identity();
|
|
152606
|
-
});
|
|
152607
153134
|
// src/features/magic-context/storage-m0-mutation-log.ts
|
|
152608
153135
|
function assertMutationType(mutationType) {
|
|
152609
153136
|
if (!M0_MUTATION_TYPES.has(mutationType)) {
|
|
@@ -152688,18 +153215,13 @@ function getMemoryMutation(db, id) {
|
|
|
152688
153215
|
WHERE id = ?`).get(id);
|
|
152689
153216
|
return row ? toMemoryMutation(row) : null;
|
|
152690
153217
|
}
|
|
152691
|
-
function
|
|
152692
|
-
|
|
152693
|
-
|
|
152694
|
-
|
|
152695
|
-
|
|
152696
|
-
|
|
152697
|
-
|
|
152698
|
-
FROM memory_mutation_log
|
|
152699
|
-
WHERE project_path = ?
|
|
152700
|
-
AND id > ?
|
|
152701
|
-
AND target_memory_id IN (${placeholders})
|
|
152702
|
-
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
153218
|
+
function uniqueProjectPaths(projectPaths) {
|
|
153219
|
+
return [...new Set(projectPaths.filter((path5) => path5.length > 0))];
|
|
153220
|
+
}
|
|
153221
|
+
function placeholders2(values) {
|
|
153222
|
+
return values.map(() => "?").join(", ");
|
|
153223
|
+
}
|
|
153224
|
+
function coalesceMutations(rows) {
|
|
152703
153225
|
const chosenByTarget = new Map;
|
|
152704
153226
|
for (const dbRow of rows) {
|
|
152705
153227
|
const candidate = toMemoryMutation(dbRow);
|
|
@@ -152720,10 +153242,54 @@ function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds
|
|
|
152720
153242
|
}
|
|
152721
153243
|
return [...chosenByTarget.values()].sort((left, right) => left.id - right.id);
|
|
152722
153244
|
}
|
|
153245
|
+
function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds) {
|
|
153246
|
+
if (renderedMemoryIds.length === 0)
|
|
153247
|
+
return [];
|
|
153248
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
153249
|
+
const placeholders3 = uniqueIds.map(() => "?").join(", ");
|
|
153250
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
153251
|
+
superseded_by_id, category, new_content, queued_at
|
|
153252
|
+
FROM memory_mutation_log
|
|
153253
|
+
WHERE project_path = ?
|
|
153254
|
+
AND id > ?
|
|
153255
|
+
AND target_memory_id IN (${placeholders3})
|
|
153256
|
+
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
153257
|
+
return coalesceMutations(rows);
|
|
153258
|
+
}
|
|
153259
|
+
function getMemoryMutationsForRenderByProjects(db, projectPaths, afterId, renderedMemoryIds) {
|
|
153260
|
+
if (renderedMemoryIds.length === 0)
|
|
153261
|
+
return [];
|
|
153262
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
153263
|
+
if (identities.length === 0)
|
|
153264
|
+
return [];
|
|
153265
|
+
if (identities.length === 1) {
|
|
153266
|
+
return getMemoryMutationsForRender(db, identities[0], afterId, renderedMemoryIds);
|
|
153267
|
+
}
|
|
153268
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
153269
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
153270
|
+
superseded_by_id, category, new_content, queued_at
|
|
153271
|
+
FROM memory_mutation_log
|
|
153272
|
+
WHERE project_path IN (${placeholders2(identities)})
|
|
153273
|
+
AND id > ?
|
|
153274
|
+
AND target_memory_id IN (${placeholders2(uniqueIds)})
|
|
153275
|
+
ORDER BY id ASC`).all(...identities, afterId ?? 0, ...uniqueIds);
|
|
153276
|
+
return coalesceMutations(rows);
|
|
153277
|
+
}
|
|
152723
153278
|
function getMaxMemoryMutationId(db, projectPath) {
|
|
152724
153279
|
const row = db.prepare("SELECT MAX(id) AS max_id FROM memory_mutation_log WHERE project_path = ?").get(projectPath);
|
|
152725
153280
|
return row?.max_id ?? null;
|
|
152726
153281
|
}
|
|
153282
|
+
function getMaxMemoryMutationIdForProjects(db, projectPaths) {
|
|
153283
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
153284
|
+
if (identities.length === 0)
|
|
153285
|
+
return null;
|
|
153286
|
+
if (identities.length === 1)
|
|
153287
|
+
return getMaxMemoryMutationId(db, identities[0]);
|
|
153288
|
+
const row = db.prepare(`SELECT MAX(id) AS max_id
|
|
153289
|
+
FROM memory_mutation_log
|
|
153290
|
+
WHERE project_path IN (${placeholders2(identities)})`).get(...identities);
|
|
153291
|
+
return row?.max_id ?? null;
|
|
153292
|
+
}
|
|
152727
153293
|
var MEMORY_MUTATION_TYPES, TERMINAL_MUTATION_TYPES;
|
|
152728
153294
|
var init_storage_memory_mutation_log = __esm(() => {
|
|
152729
153295
|
MEMORY_MUTATION_TYPES = new Set(["archive", "delete", "update", "superseded"]);
|
|
@@ -153416,6 +153982,36 @@ function addStaleReduceStrippedIds(db, sessionId, ids) {
|
|
|
153416
153982
|
sessionLog(sessionId, `stale_reduce_stripped_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
153417
153983
|
return false;
|
|
153418
153984
|
}
|
|
153985
|
+
function getProcessedImageStrippedIds(db, sessionId) {
|
|
153986
|
+
const row = db.prepare("SELECT processed_image_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
153987
|
+
return new Set(parseStrippedBlob(row?.processed_image_stripped_ids));
|
|
153988
|
+
}
|
|
153989
|
+
function addProcessedImageStrippedIds(db, sessionId, ids) {
|
|
153990
|
+
const add = [...ids];
|
|
153991
|
+
if (add.length === 0)
|
|
153992
|
+
return true;
|
|
153993
|
+
ensureSessionMetaRow(db, sessionId);
|
|
153994
|
+
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
153995
|
+
const row = db.prepare("SELECT processed_image_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
153996
|
+
const rawStored = row ? row.processed_image_stripped_ids ?? null : null;
|
|
153997
|
+
const current = new Set(parseStrippedBlob(rawStored));
|
|
153998
|
+
let changed = false;
|
|
153999
|
+
for (const id of add) {
|
|
154000
|
+
if (!current.has(id)) {
|
|
154001
|
+
current.add(id);
|
|
154002
|
+
changed = true;
|
|
154003
|
+
}
|
|
154004
|
+
}
|
|
154005
|
+
if (!changed)
|
|
154006
|
+
return true;
|
|
154007
|
+
const nextBlob = JSON.stringify([...current]);
|
|
154008
|
+
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);
|
|
154009
|
+
if (result.changes > 0)
|
|
154010
|
+
return true;
|
|
154011
|
+
}
|
|
154012
|
+
sessionLog(sessionId, `processed_image_stripped_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
154013
|
+
return false;
|
|
154014
|
+
}
|
|
153419
154015
|
function isPendingCompactionMarker(value) {
|
|
153420
154016
|
return typeof value === "object" && value !== null && typeof value.ordinal === "number" && typeof value.endMessageId === "string" && typeof value.publishedAt === "number";
|
|
153421
154017
|
}
|
|
@@ -153594,6 +154190,8 @@ function clearSession(db, sessionId) {
|
|
|
153594
154190
|
db.prepare("DELETE FROM source_contents WHERE session_id = ?").run(sessionId);
|
|
153595
154191
|
db.prepare("DELETE FROM tags WHERE session_id = ?").run(sessionId);
|
|
153596
154192
|
db.prepare("DELETE FROM session_meta WHERE session_id = ?").run(sessionId);
|
|
154193
|
+
db.prepare("DELETE FROM session_projects WHERE session_id = ?").run(sessionId);
|
|
154194
|
+
db.prepare("DELETE FROM compartment_chunk_embeddings WHERE session_id = ?").run(sessionId);
|
|
153597
154195
|
db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
|
|
153598
154196
|
clearCompressionDepth(db, sessionId);
|
|
153599
154197
|
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
@@ -153700,9 +154298,9 @@ function buildStatusClause(status) {
|
|
|
153700
154298
|
if (statuses.length === 0) {
|
|
153701
154299
|
return null;
|
|
153702
154300
|
}
|
|
153703
|
-
const
|
|
154301
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
153704
154302
|
return {
|
|
153705
|
-
sql: `status IN (${
|
|
154303
|
+
sql: `status IN (${placeholders3})`,
|
|
153706
154304
|
params: statuses
|
|
153707
154305
|
};
|
|
153708
154306
|
}
|
|
@@ -153908,19 +154506,6 @@ function getProjectState(db, projectPath) {
|
|
|
153908
154506
|
WHERE project_path = ?`).get(projectPath);
|
|
153909
154507
|
return row ? toProjectState(row) : null;
|
|
153910
154508
|
}
|
|
153911
|
-
function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
|
|
153912
|
-
db.prepare(`INSERT INTO project_state
|
|
153913
|
-
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
153914
|
-
VALUES (?, 1, 0, ?)
|
|
153915
|
-
ON CONFLICT(project_path) DO UPDATE SET
|
|
153916
|
-
project_memory_epoch = project_memory_epoch + 1,
|
|
153917
|
-
updated_at = excluded.updated_at`).run(projectPath, now);
|
|
153918
|
-
const state = getProjectState(db, projectPath);
|
|
153919
|
-
if (!state) {
|
|
153920
|
-
throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
|
|
153921
|
-
}
|
|
153922
|
-
return state;
|
|
153923
|
-
}
|
|
153924
154509
|
function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PROJECT_PATH, now = Date.now()) {
|
|
153925
154510
|
db.prepare(`INSERT INTO project_state
|
|
153926
154511
|
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
@@ -153956,8 +154541,8 @@ function getSourceContents(db, sessionId, tagIds) {
|
|
|
153956
154541
|
if (tagIds.length === 0) {
|
|
153957
154542
|
return new Map;
|
|
153958
154543
|
}
|
|
153959
|
-
const
|
|
153960
|
-
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${
|
|
154544
|
+
const placeholders3 = tagIds.map(() => "?").join(", ");
|
|
154545
|
+
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${placeholders3})`).all(sessionId, ...tagIds).filter(isSourceContentRow);
|
|
153961
154546
|
const sources = new Map;
|
|
153962
154547
|
for (const row of rows) {
|
|
153963
154548
|
sources.set(row.tag_id, row.content);
|
|
@@ -154267,8 +154852,8 @@ function getTagsByNumbers(db, sessionId, tagNumbers) {
|
|
|
154267
154852
|
}
|
|
154268
154853
|
return all;
|
|
154269
154854
|
}
|
|
154270
|
-
const
|
|
154271
|
-
const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${
|
|
154855
|
+
const placeholders3 = tagNumbers.map(() => "?").join(",");
|
|
154856
|
+
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);
|
|
154272
154857
|
return rows.map(toTagEntry);
|
|
154273
154858
|
}
|
|
154274
154859
|
function getMaxDroppedTagNumber(db, sessionId) {
|
|
@@ -154421,6 +155006,7 @@ var init_storage = __esm(async () => {
|
|
|
154421
155006
|
init_storage_source();
|
|
154422
155007
|
init_storage_tags();
|
|
154423
155008
|
init_storage_v22_backfill_failures();
|
|
155009
|
+
init_workspaces();
|
|
154424
155010
|
await __promiseAll([
|
|
154425
155011
|
init_message_index(),
|
|
154426
155012
|
init_migrations(),
|
|
@@ -163872,7 +164458,7 @@ function isEmbeddingRow(row) {
|
|
|
163872
164458
|
if (row === null || typeof row !== "object")
|
|
163873
164459
|
return false;
|
|
163874
164460
|
const candidate = row;
|
|
163875
|
-
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding);
|
|
164461
|
+
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding) && (candidate.modelId === null || typeof candidate.modelId === "string");
|
|
163876
164462
|
}
|
|
163877
164463
|
function toFloat32Array(blob) {
|
|
163878
164464
|
if (blob instanceof Uint8Array) {
|
|
@@ -163892,7 +164478,7 @@ function getSaveEmbeddingStatement(db) {
|
|
|
163892
164478
|
function getLoadAllEmbeddingsStatement(db) {
|
|
163893
164479
|
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
163894
164480
|
if (!stmt) {
|
|
163895
|
-
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");
|
|
164481
|
+
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");
|
|
163896
164482
|
loadAllEmbeddingsStatements.set(db, stmt);
|
|
163897
164483
|
}
|
|
163898
164484
|
return stmt;
|
|
@@ -163921,7 +164507,10 @@ function loadAllEmbeddings(db, projectPath) {
|
|
|
163921
164507
|
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath).filter(isEmbeddingRow);
|
|
163922
164508
|
const embeddings = new Map;
|
|
163923
164509
|
for (const row of rows) {
|
|
163924
|
-
embeddings.set(row.memoryId,
|
|
164510
|
+
embeddings.set(row.memoryId, {
|
|
164511
|
+
embedding: toFloat32Array(row.embedding),
|
|
164512
|
+
modelId: row.modelId
|
|
164513
|
+
});
|
|
163925
164514
|
}
|
|
163926
164515
|
return embeddings;
|
|
163927
164516
|
}
|
|
@@ -163984,13 +164573,13 @@ var init_embedding_cache = __esm(() => {
|
|
|
163984
164573
|
});
|
|
163985
164574
|
|
|
163986
164575
|
// src/features/magic-context/memory/normalize-hash.ts
|
|
163987
|
-
import { createHash as
|
|
164576
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
163988
164577
|
function normalizeMemoryContent(content) {
|
|
163989
164578
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
163990
164579
|
}
|
|
163991
164580
|
function computeNormalizedHash(content) {
|
|
163992
164581
|
const normalized = normalizeMemoryContent(content);
|
|
163993
|
-
return
|
|
164582
|
+
return createHash7("md5").update(normalized).digest("hex");
|
|
163994
164583
|
}
|
|
163995
164584
|
var init_normalize_hash = () => {};
|
|
163996
164585
|
|
|
@@ -164104,8 +164693,8 @@ function getMemoriesByProjectStatement(db, statuses) {
|
|
|
164104
164693
|
}
|
|
164105
164694
|
let stmt = statements.get(db);
|
|
164106
164695
|
if (!stmt) {
|
|
164107
|
-
const
|
|
164108
|
-
stmt = db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories WHERE project_path = ? AND status IN (${
|
|
164696
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
164697
|
+
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`);
|
|
164109
164698
|
statements.set(db, stmt);
|
|
164110
164699
|
}
|
|
164111
164700
|
return stmt;
|
|
@@ -164226,6 +164815,97 @@ function getMemoriesByProject(db, projectPath, statuses = ["active", "permanent"
|
|
|
164226
164815
|
const rows = getMemoriesByProjectStatement(db, statuses).all(projectPath, ...statuses, expiryCutoff).filter(isMemoryRow);
|
|
164227
164816
|
return rows.map(toMemory);
|
|
164228
164817
|
}
|
|
164818
|
+
function sqlPlaceholders(values) {
|
|
164819
|
+
return values.map(() => "?").join(", ");
|
|
164820
|
+
}
|
|
164821
|
+
function uniqueValues(values) {
|
|
164822
|
+
return [...new Set(values.filter((value) => value.length > 0))];
|
|
164823
|
+
}
|
|
164824
|
+
function buildWorkspaceMemorySqlFilter(args) {
|
|
164825
|
+
if (args.shareCategories === null || args.shareCategories === undefined) {
|
|
164826
|
+
return { clause: "", params: [], active: false };
|
|
164827
|
+
}
|
|
164828
|
+
const identities = uniqueValues(args.identities);
|
|
164829
|
+
const identitySet = new Set(identities);
|
|
164830
|
+
const ownSet = new Set(uniqueValues(args.ownIdentities ?? []).filter((identity) => identitySet.has(identity)));
|
|
164831
|
+
const foreignIdentities = identities.filter((identity) => !ownSet.has(identity));
|
|
164832
|
+
if (foreignIdentities.length === 0) {
|
|
164833
|
+
return { clause: "", params: [], active: false };
|
|
164834
|
+
}
|
|
164835
|
+
const ownIdentities = identities.filter((identity) => ownSet.has(identity));
|
|
164836
|
+
const shareCategories = uniqueValues([...args.shareCategories]);
|
|
164837
|
+
const qualifier = args.tableName ? `${args.tableName}.` : "";
|
|
164838
|
+
const predicates = [];
|
|
164839
|
+
const params = [];
|
|
164840
|
+
if (ownIdentities.length > 0) {
|
|
164841
|
+
predicates.push(`${qualifier}project_path IN (${sqlPlaceholders(ownIdentities)})`);
|
|
164842
|
+
params.push(...ownIdentities);
|
|
164843
|
+
}
|
|
164844
|
+
if (foreignIdentities.length > 0 && shareCategories.length > 0) {
|
|
164845
|
+
predicates.push(`(${qualifier}project_path IN (${sqlPlaceholders(foreignIdentities)}) AND ${qualifier}category IN (${sqlPlaceholders(shareCategories)}))`);
|
|
164846
|
+
params.push(...foreignIdentities, ...shareCategories);
|
|
164847
|
+
}
|
|
164848
|
+
if (predicates.length === 0) {
|
|
164849
|
+
return { clause: " AND 0 = 1", params: [], active: true };
|
|
164850
|
+
}
|
|
164851
|
+
return { clause: ` AND (${predicates.join(" OR ")})`, params, active: true };
|
|
164852
|
+
}
|
|
164853
|
+
function getMemoriesByProjects(db, projectPaths, statuses = ["active", "permanent"], expiryCutoff = Date.now(), ownIdentities, shareCategories) {
|
|
164854
|
+
const identities = uniqueValues(projectPaths);
|
|
164855
|
+
if (identities.length === 0 || statuses.length === 0)
|
|
164856
|
+
return [];
|
|
164857
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
164858
|
+
identities,
|
|
164859
|
+
ownIdentities,
|
|
164860
|
+
shareCategories
|
|
164861
|
+
});
|
|
164862
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
164863
|
+
return getMemoriesByProject(db, identities[0], statuses, expiryCutoff);
|
|
164864
|
+
}
|
|
164865
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
164866
|
+
FROM memories
|
|
164867
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
164868
|
+
AND status IN (${sqlPlaceholders(statuses)})
|
|
164869
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
164870
|
+
ORDER BY category ASC, updated_at DESC, id ASC`).all(...identities, ...statuses, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
164871
|
+
return rows.map(toMemory);
|
|
164872
|
+
}
|
|
164873
|
+
function getMaxMemoryIdForProjects(db, projectPaths, ownIdentities, shareCategories) {
|
|
164874
|
+
const identities = uniqueValues(projectPaths);
|
|
164875
|
+
if (identities.length === 0)
|
|
164876
|
+
return 0;
|
|
164877
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
164878
|
+
identities,
|
|
164879
|
+
ownIdentities,
|
|
164880
|
+
shareCategories
|
|
164881
|
+
});
|
|
164882
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
164883
|
+
const row2 = db.prepare("SELECT COALESCE(MAX(id), 0) AS max_id FROM memories WHERE project_path = ?").get(identities[0]);
|
|
164884
|
+
return typeof row2?.max_id === "number" ? row2.max_id : 0;
|
|
164885
|
+
}
|
|
164886
|
+
const row = db.prepare(`SELECT COALESCE(MAX(id), 0) AS max_id
|
|
164887
|
+
FROM memories
|
|
164888
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})${sharingFilter.clause}`).get(...identities, ...sharingFilter.params);
|
|
164889
|
+
return typeof row?.max_id === "number" ? row.max_id : 0;
|
|
164890
|
+
}
|
|
164891
|
+
function readNewMemoriesForM1Union(db, projectPaths, afterId, expiryCutoff, ownIdentities, shareCategories) {
|
|
164892
|
+
const identities = uniqueValues(projectPaths);
|
|
164893
|
+
if (identities.length === 0)
|
|
164894
|
+
return [];
|
|
164895
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
164896
|
+
identities,
|
|
164897
|
+
ownIdentities,
|
|
164898
|
+
shareCategories
|
|
164899
|
+
});
|
|
164900
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
164901
|
+
FROM memories
|
|
164902
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
164903
|
+
AND id > ?
|
|
164904
|
+
AND status IN ('active', 'permanent')
|
|
164905
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
164906
|
+
ORDER BY ${MEMORY_CATEGORY_ORDER_SQL}, id ASC`).all(...identities, afterId, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
164907
|
+
return rows.map(toMemory);
|
|
164908
|
+
}
|
|
164229
164909
|
function getAllActiveMemoriesForMigration(db, projectPath) {
|
|
164230
164910
|
const rows = getActiveMemoriesNoExpiryStatement(db).all(projectPath).filter(isMemoryRow);
|
|
164231
164911
|
return rows.map(toMemory);
|
|
@@ -164323,6 +165003,7 @@ function getMemoryCountsByStatus(db, projectPath) {
|
|
|
164323
165003
|
}
|
|
164324
165004
|
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;
|
|
164325
165005
|
var init_storage_memory = __esm(() => {
|
|
165006
|
+
init_constants();
|
|
164326
165007
|
init_embedding_cache();
|
|
164327
165008
|
init_normalize_hash();
|
|
164328
165009
|
COLUMN_MAP = {
|
|
@@ -164428,8 +165109,8 @@ function getUserMemoryCandidates(db) {
|
|
|
164428
165109
|
function deleteUserMemoryCandidates(db, ids) {
|
|
164429
165110
|
if (ids.length === 0)
|
|
164430
165111
|
return;
|
|
164431
|
-
const
|
|
164432
|
-
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${
|
|
165112
|
+
const placeholders3 = ids.map(() => "?").join(",");
|
|
165113
|
+
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${placeholders3})`).run(...ids);
|
|
164433
165114
|
}
|
|
164434
165115
|
function insertUserMemory(db, content, sourceCandidateIds) {
|
|
164435
165116
|
const now = Date.now();
|
|
@@ -164462,6 +165143,444 @@ function parseUserMemoryRow(row) {
|
|
|
164462
165143
|
};
|
|
164463
165144
|
}
|
|
164464
165145
|
|
|
165146
|
+
// src/features/magic-context/compartment-chunk-embedding.ts
|
|
165147
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
165148
|
+
function getLoadFtsRowsStatement(db) {
|
|
165149
|
+
let stmt = loadFtsRowsStatements.get(db);
|
|
165150
|
+
if (!stmt) {
|
|
165151
|
+
stmt = db.prepare(`SELECT message_ordinal AS messageOrdinal, role, content
|
|
165152
|
+
FROM message_history_fts
|
|
165153
|
+
WHERE session_id = ?
|
|
165154
|
+
AND message_ordinal >= ?
|
|
165155
|
+
AND message_ordinal <= ?
|
|
165156
|
+
AND role IN ('user', 'assistant')
|
|
165157
|
+
ORDER BY message_ordinal ASC`);
|
|
165158
|
+
loadFtsRowsStatements.set(db, stmt);
|
|
165159
|
+
}
|
|
165160
|
+
return stmt;
|
|
165161
|
+
}
|
|
165162
|
+
function getExistingHashStatement(db, scopedToProject) {
|
|
165163
|
+
const map2 = scopedToProject ? existingHashByProjectStatements : existingHashStatements;
|
|
165164
|
+
let stmt = map2.get(db);
|
|
165165
|
+
if (!stmt) {
|
|
165166
|
+
stmt = db.prepare(`SELECT window_index AS windowIndex, chunk_hash AS chunkHash
|
|
165167
|
+
FROM compartment_chunk_embeddings
|
|
165168
|
+
WHERE compartment_id = ?
|
|
165169
|
+
AND model_id = ?
|
|
165170
|
+
${scopedToProject ? "AND project_path = ?" : ""}
|
|
165171
|
+
ORDER BY window_index ASC`);
|
|
165172
|
+
map2.set(db, stmt);
|
|
165173
|
+
}
|
|
165174
|
+
return stmt;
|
|
165175
|
+
}
|
|
165176
|
+
function getDeleteByCompartmentStatement(db) {
|
|
165177
|
+
let stmt = deleteByCompartmentStatements.get(db);
|
|
165178
|
+
if (!stmt) {
|
|
165179
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE compartment_id = ?");
|
|
165180
|
+
deleteByCompartmentStatements.set(db, stmt);
|
|
165181
|
+
}
|
|
165182
|
+
return stmt;
|
|
165183
|
+
}
|
|
165184
|
+
function getInsertEmbeddingStatement(db) {
|
|
165185
|
+
let stmt = insertEmbeddingStatements.get(db);
|
|
165186
|
+
if (!stmt) {
|
|
165187
|
+
stmt = db.prepare(`INSERT INTO compartment_chunk_embeddings (
|
|
165188
|
+
compartment_id, session_id, project_path, harness, window_index,
|
|
165189
|
+
start_ordinal, end_ordinal, chunk_hash, model_id, dims, vector, created_at
|
|
165190
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
165191
|
+
insertEmbeddingStatements.set(db, stmt);
|
|
165192
|
+
}
|
|
165193
|
+
return stmt;
|
|
165194
|
+
}
|
|
165195
|
+
function getDistinctModelStatement(db) {
|
|
165196
|
+
let stmt = distinctModelStatements.get(db);
|
|
165197
|
+
if (!stmt) {
|
|
165198
|
+
stmt = db.prepare(`SELECT DISTINCT model_id AS modelId
|
|
165199
|
+
FROM compartment_chunk_embeddings
|
|
165200
|
+
WHERE project_path = ?`);
|
|
165201
|
+
distinctModelStatements.set(db, stmt);
|
|
165202
|
+
}
|
|
165203
|
+
return stmt;
|
|
165204
|
+
}
|
|
165205
|
+
function getClearProjectStatement(db) {
|
|
165206
|
+
let stmt = clearProjectStatements.get(db);
|
|
165207
|
+
if (!stmt) {
|
|
165208
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ?");
|
|
165209
|
+
clearProjectStatements.set(db, stmt);
|
|
165210
|
+
}
|
|
165211
|
+
return stmt;
|
|
165212
|
+
}
|
|
165213
|
+
function getClearProjectModelStatement(db) {
|
|
165214
|
+
let stmt = clearProjectModelStatements.get(db);
|
|
165215
|
+
if (!stmt) {
|
|
165216
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ? AND model_id = ?");
|
|
165217
|
+
clearProjectModelStatements.set(db, stmt);
|
|
165218
|
+
}
|
|
165219
|
+
return stmt;
|
|
165220
|
+
}
|
|
165221
|
+
function getSearchRowsStatement(db, withModel) {
|
|
165222
|
+
const map2 = withModel ? searchRowsByModelStatements : searchRowsStatements;
|
|
165223
|
+
let stmt = map2.get(db);
|
|
165224
|
+
if (!stmt) {
|
|
165225
|
+
stmt = db.prepare(`SELECT e.compartment_id AS compartmentId,
|
|
165226
|
+
e.session_id AS sessionId,
|
|
165227
|
+
c.title AS title,
|
|
165228
|
+
c.start_message AS compartmentStart,
|
|
165229
|
+
c.end_message AS compartmentEnd,
|
|
165230
|
+
e.window_index AS windowIndex,
|
|
165231
|
+
e.start_ordinal AS windowStart,
|
|
165232
|
+
e.end_ordinal AS windowEnd,
|
|
165233
|
+
e.chunk_hash AS chunkHash,
|
|
165234
|
+
e.model_id AS modelId,
|
|
165235
|
+
e.dims AS dims,
|
|
165236
|
+
e.vector AS vector
|
|
165237
|
+
FROM compartment_chunk_embeddings e
|
|
165238
|
+
JOIN compartments c ON c.id = e.compartment_id
|
|
165239
|
+
WHERE e.session_id = ?
|
|
165240
|
+
AND e.project_path = ?
|
|
165241
|
+
${withModel ? "AND e.model_id = ?" : ""}
|
|
165242
|
+
ORDER BY e.compartment_id ASC, e.window_index ASC`);
|
|
165243
|
+
map2.set(db, stmt);
|
|
165244
|
+
}
|
|
165245
|
+
return stmt;
|
|
165246
|
+
}
|
|
165247
|
+
function isFinitePositiveInteger(value) {
|
|
165248
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
165249
|
+
}
|
|
165250
|
+
function normalizeCompartmentChunkMaxInputTokens(value) {
|
|
165251
|
+
if (!isFinitePositiveInteger(value)) {
|
|
165252
|
+
return DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS;
|
|
165253
|
+
}
|
|
165254
|
+
return Math.max(1, Math.floor(value));
|
|
165255
|
+
}
|
|
165256
|
+
function normalizeContent(text) {
|
|
165257
|
+
return text.replace(/\s+/g, " ").trim();
|
|
165258
|
+
}
|
|
165259
|
+
function formatOrdinalRange(start, end) {
|
|
165260
|
+
return start === end ? `[${start}]` : `[${start}-${end}]`;
|
|
165261
|
+
}
|
|
165262
|
+
function rolePrefix(role) {
|
|
165263
|
+
if (role === "user")
|
|
165264
|
+
return "U";
|
|
165265
|
+
if (role === "assistant")
|
|
165266
|
+
return "A";
|
|
165267
|
+
return null;
|
|
165268
|
+
}
|
|
165269
|
+
function parseOrdinal(value) {
|
|
165270
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
165271
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
165272
|
+
}
|
|
165273
|
+
function parseCanonicalLineRange(line) {
|
|
165274
|
+
const match = /^\[(\d+)(?:-(\d+))?\]\s+[UA]:/.exec(line.trim());
|
|
165275
|
+
if (!match)
|
|
165276
|
+
return null;
|
|
165277
|
+
const start = Number.parseInt(match[1], 10);
|
|
165278
|
+
const end = match[2] ? Number.parseInt(match[2], 10) : start;
|
|
165279
|
+
if (!Number.isFinite(start) || !Number.isFinite(end))
|
|
165280
|
+
return null;
|
|
165281
|
+
return { start, end };
|
|
165282
|
+
}
|
|
165283
|
+
function hashChunkText(text) {
|
|
165284
|
+
return createHash8("sha256").update(text).digest("hex");
|
|
165285
|
+
}
|
|
165286
|
+
function vectorBlob(vector) {
|
|
165287
|
+
return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
|
|
165288
|
+
}
|
|
165289
|
+
function toFloat32Array2(blob) {
|
|
165290
|
+
if (blob instanceof Uint8Array) {
|
|
165291
|
+
const buffer2 = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
165292
|
+
return new Float32Array(buffer2);
|
|
165293
|
+
}
|
|
165294
|
+
return new Float32Array(blob.slice(0));
|
|
165295
|
+
}
|
|
165296
|
+
function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal) {
|
|
165297
|
+
if (endOrdinal < startOrdinal)
|
|
165298
|
+
return "";
|
|
165299
|
+
const rows = getLoadFtsRowsStatement(db).all(sessionId, startOrdinal, endOrdinal).map((row) => row);
|
|
165300
|
+
const lines = [];
|
|
165301
|
+
let current = null;
|
|
165302
|
+
const flush2 = () => {
|
|
165303
|
+
if (!current || current.parts.length === 0)
|
|
165304
|
+
return;
|
|
165305
|
+
lines.push(`${formatOrdinalRange(current.start, current.end)} ${current.role}: ${current.parts.join(" / ")}`);
|
|
165306
|
+
current = null;
|
|
165307
|
+
};
|
|
165308
|
+
for (const row of rows) {
|
|
165309
|
+
const ordinal = parseOrdinal(row.messageOrdinal);
|
|
165310
|
+
const prefix = rolePrefix(row.role);
|
|
165311
|
+
const content = typeof row.content === "string" ? normalizeContent(row.content) : "";
|
|
165312
|
+
if (ordinal === null || prefix === null || content.length === 0)
|
|
165313
|
+
continue;
|
|
165314
|
+
if (current && current.role === prefix) {
|
|
165315
|
+
current.end = ordinal;
|
|
165316
|
+
current.parts.push(content);
|
|
165317
|
+
continue;
|
|
165318
|
+
}
|
|
165319
|
+
flush2();
|
|
165320
|
+
current = { role: prefix, start: ordinal, end: ordinal, parts: [content] };
|
|
165321
|
+
}
|
|
165322
|
+
flush2();
|
|
165323
|
+
return lines.join(`
|
|
165324
|
+
`);
|
|
165325
|
+
}
|
|
165326
|
+
function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
|
|
165327
|
+
const lines = [];
|
|
165328
|
+
for (const rawLine of chunkText.split(/\r?\n/)) {
|
|
165329
|
+
const line = rawLine.trim();
|
|
165330
|
+
const match = /^(\[(\d+)(?:-(\d+))?\]\s+[UA]:)\s*(.*)$/.exec(line);
|
|
165331
|
+
if (!match)
|
|
165332
|
+
continue;
|
|
165333
|
+
const lineStart = Number.parseInt(match[2], 10);
|
|
165334
|
+
const lineEnd = match[3] ? Number.parseInt(match[3], 10) : lineStart;
|
|
165335
|
+
if (startOrdinal != null && lineEnd < startOrdinal)
|
|
165336
|
+
continue;
|
|
165337
|
+
if (endOrdinal != null && lineStart > endOrdinal)
|
|
165338
|
+
continue;
|
|
165339
|
+
const rawParts = match[4].split(" / ").map((part) => normalizeContent(part)).filter((part) => part.length > 0);
|
|
165340
|
+
const ordinalSpan = lineEnd - lineStart + 1;
|
|
165341
|
+
const roleLabel = match[1].slice(match[1].indexOf("]") + 2);
|
|
165342
|
+
if (ordinalSpan === rawParts.length) {
|
|
165343
|
+
const retained = rawParts.map((part, index) => ({ ordinal: lineStart + index, part })).filter(({ ordinal, part }) => {
|
|
165344
|
+
if (part.startsWith("TC:"))
|
|
165345
|
+
return false;
|
|
165346
|
+
if (startOrdinal != null && ordinal < startOrdinal)
|
|
165347
|
+
return false;
|
|
165348
|
+
if (endOrdinal != null && ordinal > endOrdinal)
|
|
165349
|
+
return false;
|
|
165350
|
+
return true;
|
|
165351
|
+
});
|
|
165352
|
+
if (retained.length === 0)
|
|
165353
|
+
continue;
|
|
165354
|
+
const retainedStart = retained[0].ordinal;
|
|
165355
|
+
const retainedEnd = retained[retained.length - 1].ordinal;
|
|
165356
|
+
lines.push(`${formatOrdinalRange(retainedStart, retainedEnd)} ${roleLabel} ${retained.map(({ part }) => part).join(" / ")}`);
|
|
165357
|
+
continue;
|
|
165358
|
+
}
|
|
165359
|
+
const parts = rawParts.filter((part) => !part.startsWith("TC:"));
|
|
165360
|
+
if (parts.length === 0)
|
|
165361
|
+
continue;
|
|
165362
|
+
lines.push(`${match[1]} ${parts.join(" / ")}`);
|
|
165363
|
+
}
|
|
165364
|
+
return lines.join(`
|
|
165365
|
+
`);
|
|
165366
|
+
}
|
|
165367
|
+
function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTokens) {
|
|
165368
|
+
const lines = canonicalText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
165369
|
+
if (lines.length === 0 || endOrdinal < startOrdinal)
|
|
165370
|
+
return [];
|
|
165371
|
+
const normalizedMax = normalizeCompartmentChunkMaxInputTokens(maxInputTokens);
|
|
165372
|
+
const fullText = lines.join(`
|
|
165373
|
+
`);
|
|
165374
|
+
if (estimateTokens(fullText) <= normalizedMax) {
|
|
165375
|
+
return [
|
|
165376
|
+
{
|
|
165377
|
+
windowIndex: 0,
|
|
165378
|
+
startOrdinal,
|
|
165379
|
+
endOrdinal,
|
|
165380
|
+
text: fullText,
|
|
165381
|
+
chunkHash: hashChunkText(fullText)
|
|
165382
|
+
}
|
|
165383
|
+
];
|
|
165384
|
+
}
|
|
165385
|
+
const windows = [];
|
|
165386
|
+
let currentLines = [];
|
|
165387
|
+
let currentStart = null;
|
|
165388
|
+
let currentEnd = null;
|
|
165389
|
+
let currentTokens = 0;
|
|
165390
|
+
const flush2 = () => {
|
|
165391
|
+
if (currentLines.length === 0 || currentStart === null || currentEnd === null)
|
|
165392
|
+
return;
|
|
165393
|
+
const text = currentLines.join(`
|
|
165394
|
+
`);
|
|
165395
|
+
windows.push({
|
|
165396
|
+
windowIndex: windows.length + 1,
|
|
165397
|
+
startOrdinal: currentStart,
|
|
165398
|
+
endOrdinal: currentEnd,
|
|
165399
|
+
text,
|
|
165400
|
+
chunkHash: hashChunkText(text)
|
|
165401
|
+
});
|
|
165402
|
+
currentLines = [];
|
|
165403
|
+
currentStart = null;
|
|
165404
|
+
currentEnd = null;
|
|
165405
|
+
currentTokens = 0;
|
|
165406
|
+
};
|
|
165407
|
+
for (const line of lines) {
|
|
165408
|
+
const range = parseCanonicalLineRange(line);
|
|
165409
|
+
const lineStart = range?.start ?? startOrdinal;
|
|
165410
|
+
const lineEnd = range?.end ?? lineStart;
|
|
165411
|
+
const lineTokens = estimateTokens(line);
|
|
165412
|
+
if (currentLines.length > 0 && currentTokens + lineTokens > normalizedMax) {
|
|
165413
|
+
flush2();
|
|
165414
|
+
}
|
|
165415
|
+
if (currentLines.length === 0) {
|
|
165416
|
+
currentStart = lineStart;
|
|
165417
|
+
}
|
|
165418
|
+
currentLines.push(line);
|
|
165419
|
+
currentEnd = lineEnd;
|
|
165420
|
+
currentTokens += lineTokens;
|
|
165421
|
+
}
|
|
165422
|
+
flush2();
|
|
165423
|
+
return windows;
|
|
165424
|
+
}
|
|
165425
|
+
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
165426
|
+
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
165427
|
+
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
165428
|
+
return new Map(rows.filter((row) => typeof row.windowIndex === "number" && typeof row.chunkHash === "string").map((row) => [row.windowIndex, row.chunkHash]));
|
|
165429
|
+
}
|
|
165430
|
+
function chunkEmbeddingWindowsAreCurrent(db, compartmentId, modelId, windows, projectPath) {
|
|
165431
|
+
const existing = getExistingChunkHashes(db, compartmentId, modelId, projectPath);
|
|
165432
|
+
if (existing.size !== windows.length)
|
|
165433
|
+
return false;
|
|
165434
|
+
return windows.every((window) => existing.get(window.windowIndex) === window.chunkHash);
|
|
165435
|
+
}
|
|
165436
|
+
function replaceCompartmentChunkEmbeddings(db, rows) {
|
|
165437
|
+
if (rows.length === 0)
|
|
165438
|
+
return;
|
|
165439
|
+
const compartmentId = rows[0].compartmentId;
|
|
165440
|
+
const now = Date.now();
|
|
165441
|
+
db.transaction(() => {
|
|
165442
|
+
getDeleteByCompartmentStatement(db).run(compartmentId);
|
|
165443
|
+
const insert = getInsertEmbeddingStatement(db);
|
|
165444
|
+
for (const row of rows) {
|
|
165445
|
+
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);
|
|
165446
|
+
}
|
|
165447
|
+
})();
|
|
165448
|
+
}
|
|
165449
|
+
function getDistinctChunkEmbeddingModelIds(db, projectPath) {
|
|
165450
|
+
const rows = getDistinctModelStatement(db).all(projectPath);
|
|
165451
|
+
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
165452
|
+
}
|
|
165453
|
+
function clearChunkEmbeddingsForProject(db, projectPath, modelId) {
|
|
165454
|
+
if (modelId) {
|
|
165455
|
+
return getClearProjectModelStatement(db).run(projectPath, modelId).changes;
|
|
165456
|
+
}
|
|
165457
|
+
return getClearProjectStatement(db).run(projectPath).changes;
|
|
165458
|
+
}
|
|
165459
|
+
function loadCompartmentChunkEmbeddingsForSearch(db, sessionId, projectPath, modelId) {
|
|
165460
|
+
const rows = modelId ? getSearchRowsStatement(db, true).all(sessionId, projectPath, modelId) : getSearchRowsStatement(db, false).all(sessionId, projectPath);
|
|
165461
|
+
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) => ({
|
|
165462
|
+
compartmentId: row.compartmentId,
|
|
165463
|
+
sessionId: row.sessionId,
|
|
165464
|
+
title: row.title,
|
|
165465
|
+
startOrdinal: row.compartmentStart,
|
|
165466
|
+
endOrdinal: row.compartmentEnd,
|
|
165467
|
+
windowIndex: row.windowIndex,
|
|
165468
|
+
windowStartOrdinal: row.windowStart,
|
|
165469
|
+
windowEndOrdinal: row.windowEnd,
|
|
165470
|
+
chunkHash: row.chunkHash,
|
|
165471
|
+
modelId: row.modelId,
|
|
165472
|
+
dims: row.dims,
|
|
165473
|
+
vector: toFloat32Array2(row.vector)
|
|
165474
|
+
}));
|
|
165475
|
+
}
|
|
165476
|
+
function mapBackfillCandidateRows(rows) {
|
|
165477
|
+
return rows.filter((row) => {
|
|
165478
|
+
if (row === null || typeof row !== "object")
|
|
165479
|
+
return false;
|
|
165480
|
+
const candidate = row;
|
|
165481
|
+
return typeof candidate.id === "number" && typeof candidate.sessionId === "string" && typeof candidate.startMessage === "number" && typeof candidate.endMessage === "number" && typeof candidate.title === "string";
|
|
165482
|
+
}).map((row) => ({
|
|
165483
|
+
id: row.id,
|
|
165484
|
+
sessionId: row.sessionId,
|
|
165485
|
+
startMessage: row.startMessage,
|
|
165486
|
+
endMessage: row.endMessage,
|
|
165487
|
+
title: row.title
|
|
165488
|
+
}));
|
|
165489
|
+
}
|
|
165490
|
+
function loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelId, limit, excludeIds) {
|
|
165491
|
+
if (excludeIds && excludeIds.length > 0) {
|
|
165492
|
+
const placeholders3 = excludeIds.map(() => "?").join(", ");
|
|
165493
|
+
const stmt2 = db.prepare(`SELECT c.id AS id,
|
|
165494
|
+
c.session_id AS sessionId,
|
|
165495
|
+
c.start_message AS startMessage,
|
|
165496
|
+
c.end_message AS endMessage,
|
|
165497
|
+
c.title AS title
|
|
165498
|
+
FROM compartments c
|
|
165499
|
+
JOIN session_projects sp
|
|
165500
|
+
ON sp.session_id = c.session_id
|
|
165501
|
+
AND sp.harness = c.harness
|
|
165502
|
+
AND sp.project_path = ?
|
|
165503
|
+
WHERE c.session_id = ?
|
|
165504
|
+
AND c.start_message IS NOT NULL
|
|
165505
|
+
AND c.end_message IS NOT NULL
|
|
165506
|
+
AND c.id NOT IN (${placeholders3})
|
|
165507
|
+
AND NOT EXISTS (
|
|
165508
|
+
SELECT 1
|
|
165509
|
+
FROM compartment_chunk_embeddings current
|
|
165510
|
+
WHERE current.compartment_id = c.id
|
|
165511
|
+
AND current.project_path = ?
|
|
165512
|
+
AND current.model_id = ?
|
|
165513
|
+
)
|
|
165514
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
165515
|
+
LIMIT ?`);
|
|
165516
|
+
const rows2 = stmt2.all(projectPath, sessionId, ...excludeIds, projectPath, modelId, Math.max(1, limit));
|
|
165517
|
+
return mapBackfillCandidateRows(rows2);
|
|
165518
|
+
}
|
|
165519
|
+
let stmt = sessionBackfillCandidateStatements.get(db);
|
|
165520
|
+
if (!stmt) {
|
|
165521
|
+
stmt = db.prepare(`SELECT c.id AS id,
|
|
165522
|
+
c.session_id AS sessionId,
|
|
165523
|
+
c.start_message AS startMessage,
|
|
165524
|
+
c.end_message AS endMessage,
|
|
165525
|
+
c.title AS title
|
|
165526
|
+
FROM compartments c
|
|
165527
|
+
JOIN session_projects sp
|
|
165528
|
+
ON sp.session_id = c.session_id
|
|
165529
|
+
AND sp.harness = c.harness
|
|
165530
|
+
AND sp.project_path = ?
|
|
165531
|
+
WHERE c.session_id = ?
|
|
165532
|
+
AND c.start_message IS NOT NULL
|
|
165533
|
+
AND c.end_message IS NOT NULL
|
|
165534
|
+
AND NOT EXISTS (
|
|
165535
|
+
SELECT 1
|
|
165536
|
+
FROM compartment_chunk_embeddings current
|
|
165537
|
+
WHERE current.compartment_id = c.id
|
|
165538
|
+
AND current.project_path = ?
|
|
165539
|
+
AND current.model_id = ?
|
|
165540
|
+
)
|
|
165541
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
165542
|
+
LIMIT ?`);
|
|
165543
|
+
sessionBackfillCandidateStatements.set(db, stmt);
|
|
165544
|
+
}
|
|
165545
|
+
const rows = stmt.all(projectPath, sessionId, projectPath, modelId, Math.max(1, limit));
|
|
165546
|
+
return mapBackfillCandidateRows(rows);
|
|
165547
|
+
}
|
|
165548
|
+
function countUnembeddedSessionCompartments(db, projectPath, sessionId, modelId) {
|
|
165549
|
+
const row = db.prepare(`SELECT COUNT(*) AS n
|
|
165550
|
+
FROM compartments c
|
|
165551
|
+
JOIN session_projects sp
|
|
165552
|
+
ON sp.session_id = c.session_id
|
|
165553
|
+
AND sp.harness = c.harness
|
|
165554
|
+
AND sp.project_path = ?
|
|
165555
|
+
WHERE c.session_id = ?
|
|
165556
|
+
AND c.start_message IS NOT NULL
|
|
165557
|
+
AND c.end_message IS NOT NULL
|
|
165558
|
+
AND NOT EXISTS (
|
|
165559
|
+
SELECT 1
|
|
165560
|
+
FROM compartment_chunk_embeddings current
|
|
165561
|
+
WHERE current.compartment_id = c.id
|
|
165562
|
+
AND current.project_path = ?
|
|
165563
|
+
AND current.model_id = ?
|
|
165564
|
+
)`).get(projectPath, sessionId, projectPath, modelId);
|
|
165565
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
165566
|
+
}
|
|
165567
|
+
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512, loadFtsRowsStatements, existingHashStatements, existingHashByProjectStatements, deleteByCompartmentStatements, insertEmbeddingStatements, distinctModelStatements, clearProjectStatements, clearProjectModelStatements, searchRowsStatements, searchRowsByModelStatements, backfillCandidateStatements, sessionBackfillCandidateStatements;
|
|
165568
|
+
var init_compartment_chunk_embedding = __esm(() => {
|
|
165569
|
+
init_read_session_formatting();
|
|
165570
|
+
loadFtsRowsStatements = new WeakMap;
|
|
165571
|
+
existingHashStatements = new WeakMap;
|
|
165572
|
+
existingHashByProjectStatements = new WeakMap;
|
|
165573
|
+
deleteByCompartmentStatements = new WeakMap;
|
|
165574
|
+
insertEmbeddingStatements = new WeakMap;
|
|
165575
|
+
distinctModelStatements = new WeakMap;
|
|
165576
|
+
clearProjectStatements = new WeakMap;
|
|
165577
|
+
clearProjectModelStatements = new WeakMap;
|
|
165578
|
+
searchRowsStatements = new WeakMap;
|
|
165579
|
+
searchRowsByModelStatements = new WeakMap;
|
|
165580
|
+
backfillCandidateStatements = new WeakMap;
|
|
165581
|
+
sessionBackfillCandidateStatements = new WeakMap;
|
|
165582
|
+
});
|
|
165583
|
+
|
|
164465
165584
|
// src/features/magic-context/memory/cosine-similarity.ts
|
|
164466
165585
|
function cosineSimilarity(a, b) {
|
|
164467
165586
|
if (a.length !== b.length) {
|
|
@@ -164619,19 +165738,19 @@ function isArrayLikeNumber(value) {
|
|
|
164619
165738
|
}
|
|
164620
165739
|
return arr.length === 0 || typeof arr[0] === "number";
|
|
164621
165740
|
}
|
|
164622
|
-
function
|
|
165741
|
+
function toFloat32Array3(values) {
|
|
164623
165742
|
return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
|
|
164624
165743
|
}
|
|
164625
165744
|
function extractBatchEmbeddings(result, expectedCount) {
|
|
164626
165745
|
const { data } = result;
|
|
164627
165746
|
if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
|
|
164628
|
-
return data.map((entry) =>
|
|
165747
|
+
return data.map((entry) => toFloat32Array3(entry));
|
|
164629
165748
|
}
|
|
164630
165749
|
if (!isArrayLikeNumber(data)) {
|
|
164631
165750
|
log("[magic-context] embedding batch returned unexpected data shape");
|
|
164632
165751
|
return Array.from({ length: expectedCount }, () => null);
|
|
164633
165752
|
}
|
|
164634
|
-
const flatData =
|
|
165753
|
+
const flatData = toFloat32Array3(data);
|
|
164635
165754
|
const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
|
|
164636
165755
|
if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
|
|
164637
165756
|
log("[magic-context] embedding batch returned invalid dimensions");
|
|
@@ -164646,6 +165765,7 @@ function extractBatchEmbeddings(result, expectedCount) {
|
|
|
164646
165765
|
|
|
164647
165766
|
class LocalEmbeddingProvider {
|
|
164648
165767
|
modelId;
|
|
165768
|
+
maxInputTokens;
|
|
164649
165769
|
model;
|
|
164650
165770
|
pipeline = null;
|
|
164651
165771
|
initPromise = null;
|
|
@@ -164653,8 +165773,9 @@ class LocalEmbeddingProvider {
|
|
|
164653
165773
|
disposing = false;
|
|
164654
165774
|
disposePromise = null;
|
|
164655
165775
|
inFlightWaiters = [];
|
|
164656
|
-
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
165776
|
+
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
|
|
164657
165777
|
this.model = model;
|
|
165778
|
+
this.maxInputTokens = maxInputTokens;
|
|
164658
165779
|
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
164659
165780
|
}
|
|
164660
165781
|
async initialize() {
|
|
@@ -164914,6 +166035,7 @@ function normalizeEndpoint3(endpoint) {
|
|
|
164914
166035
|
|
|
164915
166036
|
class OpenAICompatibleEmbeddingProvider {
|
|
164916
166037
|
modelId;
|
|
166038
|
+
maxInputTokens;
|
|
164917
166039
|
endpoint;
|
|
164918
166040
|
model;
|
|
164919
166041
|
apiKey;
|
|
@@ -164930,11 +166052,13 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164930
166052
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
164931
166053
|
this.inputType = options.inputType?.trim() ?? "";
|
|
164932
166054
|
this.truncate = options.truncate?.trim() ?? "";
|
|
166055
|
+
this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
|
|
164933
166056
|
this.modelId = getEmbeddingProviderIdentity({
|
|
164934
166057
|
provider: "openai-compatible",
|
|
164935
166058
|
endpoint: this.endpoint,
|
|
164936
166059
|
model: this.model,
|
|
164937
|
-
...this.apiKey ? { api_key: this.apiKey } : {}
|
|
166060
|
+
...this.apiKey ? { api_key: this.apiKey } : {},
|
|
166061
|
+
...this.inputType ? { input_type: this.inputType } : {}
|
|
164938
166062
|
});
|
|
164939
166063
|
}
|
|
164940
166064
|
async initialize() {
|
|
@@ -165178,12 +166302,12 @@ function getCountEmbeddedStatement(db) {
|
|
|
165178
166302
|
}
|
|
165179
166303
|
return stmt;
|
|
165180
166304
|
}
|
|
165181
|
-
function
|
|
165182
|
-
let stmt =
|
|
166305
|
+
function getClearProjectStatement2(db) {
|
|
166306
|
+
let stmt = clearProjectStatements2.get(db);
|
|
165183
166307
|
if (!stmt) {
|
|
165184
166308
|
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
165185
166309
|
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
165186
|
-
|
|
166310
|
+
clearProjectStatements2.set(db, stmt);
|
|
165187
166311
|
}
|
|
165188
166312
|
return stmt;
|
|
165189
166313
|
}
|
|
@@ -165219,19 +166343,19 @@ function countEmbeddedCommits(db, projectPath) {
|
|
|
165219
166343
|
return row?.count ?? 0;
|
|
165220
166344
|
}
|
|
165221
166345
|
function clearProjectCommitEmbeddings(db, projectPath) {
|
|
165222
|
-
return
|
|
166346
|
+
return getClearProjectStatement2(db).run(projectPath).changes;
|
|
165223
166347
|
}
|
|
165224
166348
|
function getDistinctCommitEmbeddingModelIds(db, projectPath) {
|
|
165225
166349
|
const rows = getDistinctModelIdStatement(db).all(projectPath);
|
|
165226
166350
|
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
165227
166351
|
}
|
|
165228
|
-
var saveStatements, loadProjectStatements, loadUnembeddedStatements, countEmbeddedStatements,
|
|
166352
|
+
var saveStatements, loadProjectStatements, loadUnembeddedStatements, countEmbeddedStatements, clearProjectStatements2, distinctModelIdStatements;
|
|
165229
166353
|
var init_storage_git_commit_embeddings = __esm(() => {
|
|
165230
166354
|
saveStatements = new WeakMap;
|
|
165231
166355
|
loadProjectStatements = new WeakMap;
|
|
165232
166356
|
loadUnembeddedStatements = new WeakMap;
|
|
165233
166357
|
countEmbeddedStatements = new WeakMap;
|
|
165234
|
-
|
|
166358
|
+
clearProjectStatements2 = new WeakMap;
|
|
165235
166359
|
distinctModelIdStatements = new WeakMap;
|
|
165236
166360
|
});
|
|
165237
166361
|
|
|
@@ -165357,13 +166481,90 @@ var init_sweep_coordinator = __esm(() => {
|
|
|
165357
166481
|
GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
|
|
165358
166482
|
});
|
|
165359
166483
|
|
|
166484
|
+
// src/features/magic-context/session-project-storage.ts
|
|
166485
|
+
function getUpsertSessionProjectStatement(db) {
|
|
166486
|
+
let stmt = upsertSessionProjectStatements.get(db);
|
|
166487
|
+
if (!stmt) {
|
|
166488
|
+
stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
|
|
166489
|
+
VALUES (?, ?, ?, ?)
|
|
166490
|
+
ON CONFLICT(session_id, harness) DO UPDATE SET
|
|
166491
|
+
project_path = excluded.project_path,
|
|
166492
|
+
updated_at = excluded.updated_at
|
|
166493
|
+
WHERE session_projects.project_path <> excluded.project_path`);
|
|
166494
|
+
upsertSessionProjectStatements.set(db, stmt);
|
|
166495
|
+
}
|
|
166496
|
+
return stmt;
|
|
166497
|
+
}
|
|
166498
|
+
function getRepairSessionChunkProjectStatement(db) {
|
|
166499
|
+
let stmt = repairSessionChunkProjectStatements.get(db);
|
|
166500
|
+
if (!stmt) {
|
|
166501
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
166502
|
+
SET project_path = ?
|
|
166503
|
+
WHERE session_id = ?
|
|
166504
|
+
AND harness = ?
|
|
166505
|
+
AND project_path <> ?`);
|
|
166506
|
+
repairSessionChunkProjectStatements.set(db, stmt);
|
|
166507
|
+
}
|
|
166508
|
+
return stmt;
|
|
166509
|
+
}
|
|
166510
|
+
function getRepairProjectChunkProjectStatement(db) {
|
|
166511
|
+
let stmt = repairProjectChunkProjectStatements.get(db);
|
|
166512
|
+
if (!stmt) {
|
|
166513
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
166514
|
+
SET project_path = (
|
|
166515
|
+
SELECT sp.project_path
|
|
166516
|
+
FROM session_projects sp
|
|
166517
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
166518
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
166519
|
+
LIMIT 1
|
|
166520
|
+
)
|
|
166521
|
+
WHERE EXISTS (
|
|
166522
|
+
SELECT 1
|
|
166523
|
+
FROM session_projects sp
|
|
166524
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
166525
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
166526
|
+
AND sp.project_path <> compartment_chunk_embeddings.project_path
|
|
166527
|
+
AND (
|
|
166528
|
+
sp.project_path = ?
|
|
166529
|
+
OR compartment_chunk_embeddings.project_path = ?
|
|
166530
|
+
)
|
|
166531
|
+
)`);
|
|
166532
|
+
repairProjectChunkProjectStatements.set(db, stmt);
|
|
166533
|
+
}
|
|
166534
|
+
return stmt;
|
|
166535
|
+
}
|
|
166536
|
+
function recordSessionProjectIdentity(db, sessionId, projectPath) {
|
|
166537
|
+
if (!sessionId || !projectPath)
|
|
166538
|
+
return;
|
|
166539
|
+
const harness = getHarness();
|
|
166540
|
+
const now = Date.now();
|
|
166541
|
+
db.transaction(() => {
|
|
166542
|
+
getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
|
|
166543
|
+
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
|
|
166544
|
+
})();
|
|
166545
|
+
}
|
|
166546
|
+
function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
166547
|
+
if (!projectPath)
|
|
166548
|
+
return 0;
|
|
166549
|
+
return getRepairProjectChunkProjectStatement(db).run(projectPath, projectPath).changes;
|
|
166550
|
+
}
|
|
166551
|
+
var upsertSessionProjectStatements, repairSessionChunkProjectStatements, repairProjectChunkProjectStatements;
|
|
166552
|
+
var init_session_project_storage = __esm(() => {
|
|
166553
|
+
upsertSessionProjectStatements = new WeakMap;
|
|
166554
|
+
repairSessionChunkProjectStatements = new WeakMap;
|
|
166555
|
+
repairProjectChunkProjectStatements = new WeakMap;
|
|
166556
|
+
});
|
|
166557
|
+
|
|
165360
166558
|
// src/features/magic-context/project-embedding-registry.ts
|
|
165361
|
-
import { createHash as
|
|
166559
|
+
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
165362
166560
|
function resolveEmbeddingConfig(config2) {
|
|
165363
166561
|
if (!config2 || config2.provider === "local") {
|
|
165364
166562
|
return {
|
|
165365
166563
|
provider: "local",
|
|
165366
|
-
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
166564
|
+
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
166565
|
+
...config2?.max_input_tokens ? {
|
|
166566
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
166567
|
+
} : {}
|
|
165367
166568
|
};
|
|
165368
166569
|
}
|
|
165369
166570
|
if (config2.provider === "openai-compatible") {
|
|
@@ -165376,7 +166577,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
165376
166577
|
endpoint: config2.endpoint.trim(),
|
|
165377
166578
|
...apiKey ? { api_key: apiKey } : {},
|
|
165378
166579
|
...inputType ? { input_type: inputType } : {},
|
|
165379
|
-
...truncate ? { truncate } : {}
|
|
166580
|
+
...truncate ? { truncate } : {},
|
|
166581
|
+
...config2.max_input_tokens ? {
|
|
166582
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
166583
|
+
} : {}
|
|
165380
166584
|
};
|
|
165381
166585
|
}
|
|
165382
166586
|
return { provider: "off" };
|
|
@@ -165394,10 +166598,11 @@ function createProvider(config2) {
|
|
|
165394
166598
|
model: config2.model,
|
|
165395
166599
|
apiKey: config2.api_key,
|
|
165396
166600
|
inputType: config2.input_type,
|
|
165397
|
-
truncate: config2.truncate
|
|
166601
|
+
truncate: config2.truncate,
|
|
166602
|
+
maxInputTokens: config2.max_input_tokens
|
|
165398
166603
|
});
|
|
165399
166604
|
}
|
|
165400
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
166605
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
165401
166606
|
}
|
|
165402
166607
|
function stableStringify2(value) {
|
|
165403
166608
|
if (Array.isArray(value)) {
|
|
@@ -165410,7 +166615,7 @@ function stableStringify2(value) {
|
|
|
165410
166615
|
return JSON.stringify(value);
|
|
165411
166616
|
}
|
|
165412
166617
|
function sha256Prefix(value, length = 16) {
|
|
165413
|
-
return
|
|
166618
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, length);
|
|
165414
166619
|
}
|
|
165415
166620
|
function getRuntimeFingerprint(config2) {
|
|
165416
166621
|
if (config2.provider === "off") {
|
|
@@ -165418,6 +166623,18 @@ function getRuntimeFingerprint(config2) {
|
|
|
165418
166623
|
}
|
|
165419
166624
|
return `${getEmbeddingProviderIdentity(config2)}:${sha256Prefix(stableStringify2(config2))}`;
|
|
165420
166625
|
}
|
|
166626
|
+
function getChunkEmbeddingModelId(config2, providerIdentity) {
|
|
166627
|
+
if (config2.provider === "off") {
|
|
166628
|
+
return OFF_PROVIDER_IDENTITY;
|
|
166629
|
+
}
|
|
166630
|
+
const chunkIdentity = {
|
|
166631
|
+
providerIdentity,
|
|
166632
|
+
chunkerVersion: 1,
|
|
166633
|
+
maxInputTokens: normalizeCompartmentChunkMaxInputTokens("max_input_tokens" in config2 ? config2.max_input_tokens : undefined),
|
|
166634
|
+
truncate: config2.provider === "openai-compatible" ? config2.truncate ?? "" : ""
|
|
166635
|
+
};
|
|
166636
|
+
return `${providerIdentity}:chunk:${sha256Prefix(stableStringify2(chunkIdentity))}`;
|
|
166637
|
+
}
|
|
165421
166638
|
function sameFeatures(a, b) {
|
|
165422
166639
|
return a.memoryEnabled === b.memoryEnabled && a.gitCommitEnabled === b.gitCommitEnabled;
|
|
165423
166640
|
}
|
|
@@ -165434,7 +166651,8 @@ function snapshotFor(registration) {
|
|
|
165434
166651
|
features: { ...registration.features },
|
|
165435
166652
|
enabled,
|
|
165436
166653
|
gitCommitEnabled,
|
|
165437
|
-
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId
|
|
166654
|
+
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
|
|
166655
|
+
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId
|
|
165438
166656
|
};
|
|
165439
166657
|
}
|
|
165440
166658
|
function disposeProvider(provider) {
|
|
@@ -165454,7 +166672,7 @@ function anyStoredModelIdIsStale(storedIds, currentId) {
|
|
|
165454
166672
|
}
|
|
165455
166673
|
return false;
|
|
165456
166674
|
}
|
|
165457
|
-
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, features) {
|
|
166675
|
+
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, currentChunkIdentity, features) {
|
|
165458
166676
|
if (currentProviderIdentity === OFF_PROVIDER_IDENTITY) {
|
|
165459
166677
|
return false;
|
|
165460
166678
|
}
|
|
@@ -165475,6 +166693,14 @@ function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity,
|
|
|
165475
166693
|
wiped = true;
|
|
165476
166694
|
}
|
|
165477
166695
|
}
|
|
166696
|
+
if (features.memoryEnabled) {
|
|
166697
|
+
repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectIdentity);
|
|
166698
|
+
const chunkIds = getDistinctChunkEmbeddingModelIds(db, projectIdentity);
|
|
166699
|
+
if (anyStoredModelIdIsStale(chunkIds, currentChunkIdentity)) {
|
|
166700
|
+
clearChunkEmbeddingsForProject(db, projectIdentity);
|
|
166701
|
+
wiped = true;
|
|
166702
|
+
}
|
|
166703
|
+
}
|
|
165478
166704
|
})();
|
|
165479
166705
|
return wiped;
|
|
165480
166706
|
}
|
|
@@ -165482,10 +166708,11 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
165482
166708
|
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
165483
166709
|
const providerIdentity = getEmbeddingProviderIdentity(resolvedConfig);
|
|
165484
166710
|
const runtimeFingerprint = getRuntimeFingerprint(resolvedConfig);
|
|
166711
|
+
const chunkModelId = getChunkEmbeddingModelId(resolvedConfig, providerIdentity);
|
|
165485
166712
|
const prior = projectRegistrations.get(projectIdentity);
|
|
165486
166713
|
const canReuseProvider = prior !== undefined && !prior.observationMode && prior.runtimeFingerprint === runtimeFingerprint && prior.providerIdentity === providerIdentity;
|
|
165487
|
-
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, features);
|
|
165488
|
-
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || !sameFeatures(prior.features, features) || wiped;
|
|
166714
|
+
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, chunkModelId, features);
|
|
166715
|
+
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || prior.chunkModelId !== chunkModelId || !sameFeatures(prior.features, features) || wiped;
|
|
165489
166716
|
const generation = generationChanged ? ++globalRegistrationGeneration : prior.generation;
|
|
165490
166717
|
const registration = {
|
|
165491
166718
|
projectIdentity,
|
|
@@ -165497,6 +166724,7 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
165497
166724
|
generation,
|
|
165498
166725
|
features: { ...features },
|
|
165499
166726
|
modelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : providerIdentity,
|
|
166727
|
+
chunkModelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : chunkModelId,
|
|
165500
166728
|
observationMode: false
|
|
165501
166729
|
};
|
|
165502
166730
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -165519,6 +166747,7 @@ function registerProjectInObservationMode(db, projectIdentity, sourceDirectory,
|
|
|
165519
166747
|
generation,
|
|
165520
166748
|
features: { memoryEnabled: false, gitCommitEnabled: false },
|
|
165521
166749
|
modelId: "off",
|
|
166750
|
+
chunkModelId: "off",
|
|
165522
166751
|
observationMode: true
|
|
165523
166752
|
};
|
|
165524
166753
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -165529,6 +166758,15 @@ function getProjectEmbeddingSnapshot(projectIdentity) {
|
|
|
165529
166758
|
const registration = projectRegistrations.get(projectIdentity);
|
|
165530
166759
|
return registration ? snapshotFor(registration) : null;
|
|
165531
166760
|
}
|
|
166761
|
+
function getProjectChunkEmbeddingModelId(projectIdentity) {
|
|
166762
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
166763
|
+
return registration && !registration.observationMode ? registration.chunkModelId : "off";
|
|
166764
|
+
}
|
|
166765
|
+
function getProjectEmbeddingMaxInputTokens(projectIdentity) {
|
|
166766
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
166767
|
+
const configMax = registration?.config && "max_input_tokens" in registration.config ? registration.config.max_input_tokens : undefined;
|
|
166768
|
+
return normalizeCompartmentChunkMaxInputTokens(registration?.provider?.maxInputTokens ?? configMax);
|
|
166769
|
+
}
|
|
165532
166770
|
function getOrCreateProjectProvider(registration) {
|
|
165533
166771
|
if (registration.providerIdentity === OFF_PROVIDER_IDENTITY || registration.observationMode) {
|
|
165534
166772
|
return null;
|
|
@@ -165623,10 +166861,136 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
165623
166861
|
return 0;
|
|
165624
166862
|
}
|
|
165625
166863
|
}
|
|
165626
|
-
|
|
166864
|
+
async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal) {
|
|
166865
|
+
const noWork = [];
|
|
166866
|
+
if (candidates.length === 0)
|
|
166867
|
+
return { embedded: 0, noWork };
|
|
166868
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
|
|
166869
|
+
const prepared = [];
|
|
166870
|
+
for (const candidate of candidates) {
|
|
166871
|
+
const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
|
|
166872
|
+
if (canonicalText.length === 0) {
|
|
166873
|
+
noWork.push(candidate.id);
|
|
166874
|
+
continue;
|
|
166875
|
+
}
|
|
166876
|
+
const windows = chunkCanonicalText(canonicalText, candidate.startMessage, candidate.endMessage, maxInputTokens);
|
|
166877
|
+
if (windows.length === 0 || chunkEmbeddingWindowsAreCurrent(db, candidate.id, modelId, windows, projectIdentity)) {
|
|
166878
|
+
noWork.push(candidate.id);
|
|
166879
|
+
continue;
|
|
166880
|
+
}
|
|
166881
|
+
prepared.push({ candidate, windows });
|
|
166882
|
+
}
|
|
166883
|
+
if (prepared.length === 0)
|
|
166884
|
+
return { embedded: 0, noWork };
|
|
166885
|
+
let embedded = 0;
|
|
166886
|
+
let i = 0;
|
|
166887
|
+
while (i < prepared.length) {
|
|
166888
|
+
if (signal?.aborted)
|
|
166889
|
+
break;
|
|
166890
|
+
const slice = [];
|
|
166891
|
+
let windowCount = 0;
|
|
166892
|
+
do {
|
|
166893
|
+
const item = prepared[i];
|
|
166894
|
+
slice.push(item);
|
|
166895
|
+
windowCount += item.windows.length;
|
|
166896
|
+
i += 1;
|
|
166897
|
+
} while (i < prepared.length && windowCount + prepared[i].windows.length <= MAX_WINDOWS_PER_EMBED_CALL);
|
|
166898
|
+
const texts = [];
|
|
166899
|
+
for (const item of slice)
|
|
166900
|
+
texts.push(...item.windows.map((w) => w.text));
|
|
166901
|
+
try {
|
|
166902
|
+
const result = await embedBatchForProject(projectIdentity, texts, signal);
|
|
166903
|
+
if (!result)
|
|
166904
|
+
continue;
|
|
166905
|
+
if (signal?.aborted)
|
|
166906
|
+
break;
|
|
166907
|
+
let offset = 0;
|
|
166908
|
+
for (const item of slice) {
|
|
166909
|
+
const vectors = result.vectors.slice(offset, offset + item.windows.length);
|
|
166910
|
+
offset += item.windows.length;
|
|
166911
|
+
if (vectors.length !== item.windows.length || vectors.some((v) => !v)) {
|
|
166912
|
+
continue;
|
|
166913
|
+
}
|
|
166914
|
+
const rows = item.windows.map((window, index) => ({
|
|
166915
|
+
compartmentId: item.candidate.id,
|
|
166916
|
+
sessionId: item.candidate.sessionId,
|
|
166917
|
+
projectPath: projectIdentity,
|
|
166918
|
+
window,
|
|
166919
|
+
modelId,
|
|
166920
|
+
vector: vectors[index]
|
|
166921
|
+
}));
|
|
166922
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
166923
|
+
embedded += 1;
|
|
166924
|
+
}
|
|
166925
|
+
} catch (error51) {
|
|
166926
|
+
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
166927
|
+
}
|
|
166928
|
+
}
|
|
166929
|
+
return { embedded, noWork };
|
|
166930
|
+
}
|
|
166931
|
+
async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, options) {
|
|
166932
|
+
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
166933
|
+
if (!snapshot?.enabled || snapshot.chunkModelId === "off") {
|
|
166934
|
+
return { status: "disabled", embedded: 0, total: 0 };
|
|
166935
|
+
}
|
|
166936
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
166937
|
+
const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId);
|
|
166938
|
+
if (total === 0)
|
|
166939
|
+
return { status: "nothing", embedded: 0, total: 0 };
|
|
166940
|
+
const holderId = `session-embed-${randomUUID()}`;
|
|
166941
|
+
const lease2 = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
|
|
166942
|
+
if (!lease2.acquired)
|
|
166943
|
+
return { status: "busy", embedded: 0, total };
|
|
166944
|
+
const renewal = setInterval(() => {
|
|
166945
|
+
try {
|
|
166946
|
+
renewGitSweepLease(db, projectIdentity, holderId);
|
|
166947
|
+
} catch {}
|
|
166948
|
+
}, SESSION_EMBED_LEASE_RENEWAL_MS);
|
|
166949
|
+
renewal.unref?.();
|
|
166950
|
+
const batchSize = Math.max(1, options?.batchSize ?? CHUNK_DRAIN_BATCH_SIZE);
|
|
166951
|
+
const skipIds = [];
|
|
166952
|
+
let embedded = 0;
|
|
166953
|
+
let aborted2 = false;
|
|
166954
|
+
let providerStalled = false;
|
|
166955
|
+
try {
|
|
166956
|
+
options?.onProgress?.({ embedded, total });
|
|
166957
|
+
for (;; ) {
|
|
166958
|
+
if (options?.signal?.aborted) {
|
|
166959
|
+
aborted2 = true;
|
|
166960
|
+
break;
|
|
166961
|
+
}
|
|
166962
|
+
const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, skipIds);
|
|
166963
|
+
if (candidates.length === 0)
|
|
166964
|
+
break;
|
|
166965
|
+
const { embedded: n, noWork } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, options?.signal);
|
|
166966
|
+
for (const id of noWork)
|
|
166967
|
+
skipIds.push(id);
|
|
166968
|
+
if (n === 0 && noWork.length === 0) {
|
|
166969
|
+
providerStalled = true;
|
|
166970
|
+
break;
|
|
166971
|
+
}
|
|
166972
|
+
embedded += n;
|
|
166973
|
+
options?.onProgress?.({ embedded: Math.min(embedded, total), total });
|
|
166974
|
+
await new Promise((resolve7) => setTimeout(resolve7, 0));
|
|
166975
|
+
}
|
|
166976
|
+
} finally {
|
|
166977
|
+
clearInterval(renewal);
|
|
166978
|
+
releaseGitSweepLease(db, projectIdentity, holderId);
|
|
166979
|
+
}
|
|
166980
|
+
if (aborted2)
|
|
166981
|
+
return { status: "aborted", embedded, total };
|
|
166982
|
+
if (providerStalled) {
|
|
166983
|
+
const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId) - skipIds.length);
|
|
166984
|
+
if (remaining > 0)
|
|
166985
|
+
return { status: "stalled", embedded, total, remaining };
|
|
166986
|
+
}
|
|
166987
|
+
return { status: "done", embedded, total };
|
|
166988
|
+
}
|
|
166989
|
+
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;
|
|
165627
166990
|
var init_project_embedding_registry = __esm(() => {
|
|
165628
166991
|
init_magic_context();
|
|
165629
166992
|
init_logger();
|
|
166993
|
+
init_compartment_chunk_embedding();
|
|
165630
166994
|
init_storage_git_commit_embeddings();
|
|
165631
166995
|
init_sweep_coordinator();
|
|
165632
166996
|
init_embedding_cache();
|
|
@@ -165634,7 +166998,9 @@ var init_project_embedding_registry = __esm(() => {
|
|
|
165634
166998
|
init_embedding_local();
|
|
165635
166999
|
init_embedding_openai();
|
|
165636
167000
|
init_storage_memory_embeddings();
|
|
167001
|
+
init_session_project_storage();
|
|
165637
167002
|
SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
167003
|
+
SESSION_EMBED_LEASE_RENEWAL_MS = 60 * 1000;
|
|
165638
167004
|
projectRegistrations = new Map;
|
|
165639
167005
|
loadUnembeddedMemoriesStatements = new WeakMap;
|
|
165640
167006
|
});
|
|
@@ -165650,10 +167016,11 @@ function createProvider2(config2) {
|
|
|
165650
167016
|
model: config2.model,
|
|
165651
167017
|
apiKey: config2.api_key,
|
|
165652
167018
|
inputType: config2.input_type,
|
|
165653
|
-
truncate: config2.truncate
|
|
167019
|
+
truncate: config2.truncate,
|
|
167020
|
+
maxInputTokens: config2.max_input_tokens
|
|
165654
167021
|
});
|
|
165655
167022
|
}
|
|
165656
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
167023
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
165657
167024
|
}
|
|
165658
167025
|
function getOrCreateProvider() {
|
|
165659
167026
|
if (provider) {
|
|
@@ -165679,6 +167046,7 @@ var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMe
|
|
|
165679
167046
|
var init_embedding = __esm(() => {
|
|
165680
167047
|
init_magic_context();
|
|
165681
167048
|
init_logger();
|
|
167049
|
+
init_compartment_chunk_embedding();
|
|
165682
167050
|
init_embedding_identity();
|
|
165683
167051
|
init_embedding_local();
|
|
165684
167052
|
init_embedding_openai();
|
|
@@ -165702,6 +167070,23 @@ function getSearchStatement(db) {
|
|
|
165702
167070
|
}
|
|
165703
167071
|
return stmt;
|
|
165704
167072
|
}
|
|
167073
|
+
function getUnionSearchStatement(db, arity) {
|
|
167074
|
+
let statements = unionSearchStatements.get(arity);
|
|
167075
|
+
if (!statements) {
|
|
167076
|
+
statements = new WeakMap;
|
|
167077
|
+
unionSearchStatements.set(arity, statements);
|
|
167078
|
+
}
|
|
167079
|
+
let stmt = statements.get(db);
|
|
167080
|
+
if (!stmt) {
|
|
167081
|
+
const placeholders3 = Array.from({ length: arity }, () => "?").join(", ");
|
|
167082
|
+
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 ?`);
|
|
167083
|
+
statements.set(db, stmt);
|
|
167084
|
+
}
|
|
167085
|
+
return stmt;
|
|
167086
|
+
}
|
|
167087
|
+
function uniqueProjectPaths2(projectPaths) {
|
|
167088
|
+
return [...new Set(projectPaths.filter((path6) => path6.length > 0))];
|
|
167089
|
+
}
|
|
165705
167090
|
function sanitizeFtsQuery(query) {
|
|
165706
167091
|
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
165707
167092
|
if (tokens.length === 0)
|
|
@@ -165720,10 +167105,33 @@ function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT)
|
|
|
165720
167105
|
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
165721
167106
|
return rows.map(toMemory);
|
|
165722
167107
|
}
|
|
165723
|
-
|
|
167108
|
+
function searchMemoriesFTSUnion(db, projectPaths, query, limit = DEFAULT_SEARCH_LIMIT, ownIdentities, shareCategories) {
|
|
167109
|
+
const identities = uniqueProjectPaths2(projectPaths);
|
|
167110
|
+
if (identities.length === 0)
|
|
167111
|
+
return [];
|
|
167112
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
167113
|
+
identities,
|
|
167114
|
+
ownIdentities,
|
|
167115
|
+
shareCategories,
|
|
167116
|
+
tableName: "memories"
|
|
167117
|
+
});
|
|
167118
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
167119
|
+
return searchMemoriesFTS(db, identities[0], query, limit);
|
|
167120
|
+
}
|
|
167121
|
+
const trimmedQuery = query.trim();
|
|
167122
|
+
if (trimmedQuery.length === 0 || limit <= 0)
|
|
167123
|
+
return [];
|
|
167124
|
+
const sanitized = sanitizeFtsQuery(trimmedQuery);
|
|
167125
|
+
if (sanitized.length === 0)
|
|
167126
|
+
return [];
|
|
167127
|
+
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);
|
|
167128
|
+
return rows.map(toMemory);
|
|
167129
|
+
}
|
|
167130
|
+
var DEFAULT_SEARCH_LIMIT = 10, searchStatements, unionSearchStatements;
|
|
165724
167131
|
var init_storage_memory_fts = __esm(() => {
|
|
165725
167132
|
init_storage_memory();
|
|
165726
167133
|
searchStatements = new WeakMap;
|
|
167134
|
+
unionSearchStatements = new Map;
|
|
165727
167135
|
});
|
|
165728
167136
|
|
|
165729
167137
|
// src/shared/models-dev-cache.ts
|
|
@@ -165917,26 +167325,54 @@ var init_rpc_notifications = __esm(() => {
|
|
|
165917
167325
|
});
|
|
165918
167326
|
|
|
165919
167327
|
// src/features/magic-context/compartment-embedding.ts
|
|
165920
|
-
async function
|
|
167328
|
+
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
165921
167329
|
if (compartments.length === 0)
|
|
165922
167330
|
return;
|
|
165923
|
-
const
|
|
165924
|
-
for (const
|
|
165925
|
-
if (!c.p1 || c.p1.length === 0)
|
|
165926
|
-
continue;
|
|
167331
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
167332
|
+
for (const compartment of compartments) {
|
|
165927
167333
|
try {
|
|
165928
|
-
const
|
|
165929
|
-
|
|
165930
|
-
|
|
165931
|
-
|
|
167334
|
+
const fromMemory = compartment.sourceChunkText ? canonicalizeInMemoryChunkTextForEmbedding(compartment.sourceChunkText, compartment.startMessage, compartment.endMessage) : "";
|
|
167335
|
+
const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage);
|
|
167336
|
+
if (canonicalText.length === 0)
|
|
167337
|
+
continue;
|
|
167338
|
+
const windows = chunkCanonicalText(canonicalText, compartment.startMessage, compartment.endMessage, maxInputTokens);
|
|
167339
|
+
if (windows.length === 0)
|
|
167340
|
+
continue;
|
|
167341
|
+
const currentModelId = getProjectChunkEmbeddingModelId(projectPath);
|
|
167342
|
+
if (currentModelId !== "off" && chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
167343
|
+
continue;
|
|
167344
|
+
}
|
|
167345
|
+
const result = await embedBatchForProject(projectPath, windows.map((window) => window.text));
|
|
167346
|
+
if (!result)
|
|
167347
|
+
continue;
|
|
167348
|
+
if (chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
167349
|
+
continue;
|
|
167350
|
+
}
|
|
167351
|
+
const rows = [];
|
|
167352
|
+
for (const [index, window] of windows.entries()) {
|
|
167353
|
+
const vector = result.vectors[index];
|
|
167354
|
+
if (!vector)
|
|
167355
|
+
continue;
|
|
167356
|
+
rows.push({
|
|
167357
|
+
compartmentId: compartment.id,
|
|
167358
|
+
sessionId,
|
|
167359
|
+
projectPath,
|
|
167360
|
+
window,
|
|
167361
|
+
modelId: currentModelId,
|
|
167362
|
+
vector
|
|
167363
|
+
});
|
|
167364
|
+
}
|
|
167365
|
+
if (rows.length === windows.length) {
|
|
167366
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
165932
167367
|
}
|
|
165933
167368
|
} catch (error51) {
|
|
165934
|
-
sessionLog(sessionId, `compartment embedding failed for compartment ${
|
|
167369
|
+
sessionLog(sessionId, `compartment chunk embedding failed for compartment ${compartment.id}:`, error51);
|
|
165935
167370
|
}
|
|
165936
167371
|
}
|
|
165937
167372
|
}
|
|
165938
167373
|
var init_compartment_embedding = __esm(() => {
|
|
165939
167374
|
init_logger();
|
|
167375
|
+
init_compartment_chunk_embedding();
|
|
165940
167376
|
init_project_embedding_registry();
|
|
165941
167377
|
});
|
|
165942
167378
|
|
|
@@ -167050,55 +168486,6 @@ var init_historian_state_file = __esm(() => {
|
|
|
167050
168486
|
init_data_path();
|
|
167051
168487
|
});
|
|
167052
168488
|
|
|
167053
|
-
// src/features/magic-context/memory/constants.ts
|
|
167054
|
-
var V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
167055
|
-
var init_constants = __esm(() => {
|
|
167056
|
-
V2_MEMORY_CATEGORIES = [
|
|
167057
|
-
"PROJECT_RULES",
|
|
167058
|
-
"ARCHITECTURE",
|
|
167059
|
-
"CONSTRAINTS",
|
|
167060
|
-
"CONFIG_VALUES",
|
|
167061
|
-
"NAMING"
|
|
167062
|
-
];
|
|
167063
|
-
PROMOTABLE_CATEGORIES = [
|
|
167064
|
-
"PROJECT_RULES",
|
|
167065
|
-
"ARCHITECTURE",
|
|
167066
|
-
"CONSTRAINTS",
|
|
167067
|
-
"CONFIG_VALUES",
|
|
167068
|
-
"NAMING",
|
|
167069
|
-
"ARCHITECTURE_DECISIONS",
|
|
167070
|
-
"CONFIG_DEFAULTS",
|
|
167071
|
-
"USER_PREFERENCES",
|
|
167072
|
-
"USER_DIRECTIVES",
|
|
167073
|
-
"ENVIRONMENT",
|
|
167074
|
-
"WORKFLOW_RULES",
|
|
167075
|
-
"KNOWN_ISSUES"
|
|
167076
|
-
];
|
|
167077
|
-
CATEGORY_PRIORITY = [
|
|
167078
|
-
"PROJECT_RULES",
|
|
167079
|
-
"ARCHITECTURE",
|
|
167080
|
-
"CONSTRAINTS",
|
|
167081
|
-
"CONFIG_VALUES",
|
|
167082
|
-
"NAMING",
|
|
167083
|
-
"USER_DIRECTIVES",
|
|
167084
|
-
"USER_PREFERENCES",
|
|
167085
|
-
"CONFIG_DEFAULTS",
|
|
167086
|
-
"ARCHITECTURE_DECISIONS",
|
|
167087
|
-
"ENVIRONMENT",
|
|
167088
|
-
"WORKFLOW_RULES",
|
|
167089
|
-
"KNOWN_ISSUES"
|
|
167090
|
-
];
|
|
167091
|
-
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
167092
|
-
acc[category] = index;
|
|
167093
|
-
return acc;
|
|
167094
|
-
}, {});
|
|
167095
|
-
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
167096
|
-
CATEGORY_DEFAULT_TTL = {
|
|
167097
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
167098
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
167099
|
-
};
|
|
167100
|
-
});
|
|
167101
|
-
|
|
167102
168489
|
// src/features/magic-context/memory/embedding-backfill.ts
|
|
167103
168490
|
async function ensureMemoryEmbeddings(args) {
|
|
167104
168491
|
const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -167122,7 +168509,7 @@ async function ensureMemoryEmbeddings(args) {
|
|
|
167122
168509
|
continue;
|
|
167123
168510
|
}
|
|
167124
168511
|
saveEmbedding(args.db, memory.id, embedding, result.modelId);
|
|
167125
|
-
staged.set(memory.id, embedding);
|
|
168512
|
+
staged.set(memory.id, { embedding, modelId: result.modelId });
|
|
167126
168513
|
}
|
|
167127
168514
|
})();
|
|
167128
168515
|
const currentSnapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -167919,6 +169306,71 @@ function lastCompartmentBoundaryId(compartments) {
|
|
|
167919
169306
|
const last = compartments.at(-1);
|
|
167920
169307
|
return last?.endMessageId && last.endMessageId.length > 0 ? last.endMessageId : null;
|
|
167921
169308
|
}
|
|
169309
|
+
function resolveWorkspaceRenderContext(args) {
|
|
169310
|
+
if (!args.projectPath) {
|
|
169311
|
+
return {
|
|
169312
|
+
identities: [],
|
|
169313
|
+
expandedIdentities: [],
|
|
169314
|
+
ownIdentities: [],
|
|
169315
|
+
shareCategories: null,
|
|
169316
|
+
namesByIdentity: new Map,
|
|
169317
|
+
canonicalIdentityByStoredPath: new Map,
|
|
169318
|
+
isWorkspaced: false
|
|
169319
|
+
};
|
|
169320
|
+
}
|
|
169321
|
+
const identitySet = args.workspaceIdentitySet ?? resolveWorkspaceIdentitySet(args.db, args.projectPath);
|
|
169322
|
+
const isWorkspaced = identitySet.identities.length > 1;
|
|
169323
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(args.db, identitySet.identities);
|
|
169324
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : identitySet.identities;
|
|
169325
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(identitySet.identities.map((identity) => [identity, identity]));
|
|
169326
|
+
let ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === args.projectPath);
|
|
169327
|
+
if (ownIdentities.length === 0 && expandedIdentities.includes(args.projectPath)) {
|
|
169328
|
+
ownIdentities = [args.projectPath];
|
|
169329
|
+
}
|
|
169330
|
+
return {
|
|
169331
|
+
identities: identitySet.identities,
|
|
169332
|
+
expandedIdentities,
|
|
169333
|
+
ownIdentities,
|
|
169334
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(args.db, args.projectPath) : null,
|
|
169335
|
+
namesByIdentity: identitySet.namesByIdentity,
|
|
169336
|
+
canonicalIdentityByStoredPath,
|
|
169337
|
+
isWorkspaced
|
|
169338
|
+
};
|
|
169339
|
+
}
|
|
169340
|
+
function sourceNamesForMemories(args) {
|
|
169341
|
+
if (!args.projectPath || !args.workspace.isWorkspaced)
|
|
169342
|
+
return;
|
|
169343
|
+
const names = new Map;
|
|
169344
|
+
for (const memory of args.memories) {
|
|
169345
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
169346
|
+
if (source)
|
|
169347
|
+
names.set(memory.id, source);
|
|
169348
|
+
}
|
|
169349
|
+
return names.size > 0 ? names : undefined;
|
|
169350
|
+
}
|
|
169351
|
+
function memoryCanonicalIdentity(memory, workspace) {
|
|
169352
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
169353
|
+
}
|
|
169354
|
+
function memorySelectionOrder(left, right) {
|
|
169355
|
+
if (left.status === "permanent" && right.status !== "permanent")
|
|
169356
|
+
return -1;
|
|
169357
|
+
if (right.status === "permanent" && left.status !== "permanent")
|
|
169358
|
+
return 1;
|
|
169359
|
+
const leftImportance = left.importance ?? Number.NEGATIVE_INFINITY;
|
|
169360
|
+
const rightImportance = right.importance ?? Number.NEGATIVE_INFINITY;
|
|
169361
|
+
const importanceDiff = rightImportance - leftImportance;
|
|
169362
|
+
if (importanceDiff !== 0)
|
|
169363
|
+
return importanceDiff;
|
|
169364
|
+
return left.id - right.id;
|
|
169365
|
+
}
|
|
169366
|
+
function memoryRenderOrder(left, right) {
|
|
169367
|
+
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[left.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
169368
|
+
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[right.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
169369
|
+
const categoryDiff = aPriority - bPriority;
|
|
169370
|
+
if (categoryDiff !== 0)
|
|
169371
|
+
return categoryDiff;
|
|
169372
|
+
return left.id - right.id;
|
|
169373
|
+
}
|
|
167922
169374
|
function cachedStatement(cache, db, sql) {
|
|
167923
169375
|
let stmt = cache.get(db);
|
|
167924
169376
|
if (!stmt) {
|
|
@@ -167961,13 +169413,19 @@ function getGlobalUserProfileVersion(db) {
|
|
|
167961
169413
|
function readCurrentM0SnapshotMarkers(args) {
|
|
167962
169414
|
const projectDirectory = args.projectDirectory ?? args.projectPath ?? "";
|
|
167963
169415
|
const hard = args.hardSignals ?? EMPTY_HARD_SIGNALS;
|
|
169416
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
169417
|
+
db: args.db,
|
|
169418
|
+
projectPath: args.projectPath,
|
|
169419
|
+
workspaceIdentitySet: args.workspaceIdentitySet
|
|
169420
|
+
});
|
|
167964
169421
|
return {
|
|
167965
169422
|
projectMemoryEpoch: getProjectMemoryEpoch(args.db, args.projectPath),
|
|
169423
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(args.db, workspace.identities) : null,
|
|
167966
169424
|
projectUserProfileVersion: getGlobalUserProfileVersion(args.db),
|
|
167967
169425
|
maxCompartmentSeq: getMaxCompartmentSeq(args.db, args.sessionId),
|
|
167968
|
-
maxMemoryId: getMaxMemoryId(args.db, args.projectPath),
|
|
169426
|
+
maxMemoryId: workspace.isWorkspaced ? getMaxMemoryIdForProjects(args.db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryId(args.db, args.projectPath),
|
|
167969
169427
|
maxMutationId: getMaxM0MutationId(args.db, args.sessionId) ?? 0,
|
|
167970
|
-
maxMemoryMutationId: args.projectPath ? getMaxMemoryMutationId(args.db, args.projectPath) ?? 0 : 0,
|
|
169428
|
+
maxMemoryMutationId: workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(args.db, workspace.expandedIdentities) ?? 0 : args.projectPath ? getMaxMemoryMutationId(args.db, args.projectPath) ?? 0 : 0,
|
|
167971
169429
|
projectDocsHash: projectDirectory ? computeProjectDocsHash(projectDirectory) : "",
|
|
167972
169430
|
materializedAt: Date.now(),
|
|
167973
169431
|
sessionFactsVersion: getSessionFactsVersion(args.db, args.sessionId),
|
|
@@ -167995,6 +169453,7 @@ function snapshotMarkersFromCachedM0(state) {
|
|
|
167995
169453
|
return null;
|
|
167996
169454
|
return {
|
|
167997
169455
|
projectMemoryEpoch: state.cachedM0ProjectMemoryEpoch,
|
|
169456
|
+
workspaceFingerprint: state.cachedM0WorkspaceFingerprint,
|
|
167998
169457
|
projectUserProfileVersion: state.cachedM0ProjectUserProfileVersion,
|
|
167999
169458
|
maxCompartmentSeq: state.cachedM0MaxCompartmentSeq,
|
|
168000
169459
|
maxMemoryId: state.cachedM0MaxMemoryId,
|
|
@@ -168024,35 +169483,27 @@ function mustMaterialize(args) {
|
|
|
168024
169483
|
if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (args.state.cachedM0MaterializedAt ?? 0)) {
|
|
168025
169484
|
return { value: true, reason: "ttl_idle" };
|
|
168026
169485
|
}
|
|
168027
|
-
if (args.state.
|
|
169486
|
+
if (current.workspaceFingerprint !== null || (args.state.cachedM0WorkspaceFingerprint ?? null) !== null) {
|
|
169487
|
+
if ((args.state.cachedM0WorkspaceFingerprint ?? null) !== current.workspaceFingerprint) {
|
|
169488
|
+
return { value: true, reason: "project_memory_epoch" };
|
|
169489
|
+
}
|
|
169490
|
+
} else if (args.state.cachedM0ProjectMemoryEpoch !== current.projectMemoryEpoch) {
|
|
168028
169491
|
return { value: true, reason: "project_memory_epoch" };
|
|
168029
169492
|
}
|
|
168030
169493
|
if (args.state.cachedM0MaxMutationId !== current.maxMutationId) {
|
|
168031
169494
|
return { value: true, reason: "max_mutation_id" };
|
|
168032
169495
|
}
|
|
168033
|
-
if ((args.state.cachedM0ProjectDocsHash ?? "") !== current.projectDocsHash) {
|
|
168034
|
-
return { value: true, reason: "project_docs_hash" };
|
|
168035
|
-
}
|
|
168036
169496
|
if ((args.state.cachedM0UpgradeState ?? null) !== current.upgradeState) {
|
|
168037
169497
|
return { value: true, reason: "upgrade_state" };
|
|
168038
169498
|
}
|
|
168039
169499
|
return { value: false, reason: null };
|
|
168040
169500
|
}
|
|
168041
|
-
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
168042
|
-
const selectionOrder = [...memories].sort(
|
|
168043
|
-
if (a.status === "permanent" && b.status !== "permanent")
|
|
168044
|
-
return -1;
|
|
168045
|
-
if (b.status === "permanent" && a.status !== "permanent")
|
|
168046
|
-
return 1;
|
|
168047
|
-
const importanceDiff = (b.importance ?? 50) - (a.importance ?? 50);
|
|
168048
|
-
if (importanceDiff !== 0)
|
|
168049
|
-
return importanceDiff;
|
|
168050
|
-
return a.id - b.id;
|
|
168051
|
-
});
|
|
169501
|
+
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions = {}) {
|
|
169502
|
+
const selectionOrder = [...memories].sort(memorySelectionOrder);
|
|
168052
169503
|
const selected = [];
|
|
168053
169504
|
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
168054
169505
|
for (const memory of selectionOrder) {
|
|
168055
|
-
const memoryTokens = estimateTokens(renderMemoryLineV2(memory));
|
|
169506
|
+
const memoryTokens = estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
168056
169507
|
if (usedTokens + memoryTokens > budgetTokens)
|
|
168057
169508
|
continue;
|
|
168058
169509
|
selected.push(memory);
|
|
@@ -168061,16 +169512,70 @@ function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
|
168061
169512
|
if (selected.length < memories.length) {
|
|
168062
169513
|
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
168063
169514
|
}
|
|
168064
|
-
const renderOrder = [...selected].sort(
|
|
168065
|
-
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[a.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
168066
|
-
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[b.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
168067
|
-
const categoryDiff = aPriority - bPriority;
|
|
168068
|
-
if (categoryDiff !== 0)
|
|
168069
|
-
return categoryDiff;
|
|
168070
|
-
return a.id - b.id;
|
|
168071
|
-
});
|
|
169515
|
+
const renderOrder = [...selected].sort(memoryRenderOrder);
|
|
168072
169516
|
return { selected, renderOrder };
|
|
168073
169517
|
}
|
|
169518
|
+
function trimWorkspaceMemoriesToBudgetV2(sessionId, memories, budgetTokens, workspace, renderOptions = {}) {
|
|
169519
|
+
if (!workspace.isWorkspaced) {
|
|
169520
|
+
return trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions);
|
|
169521
|
+
}
|
|
169522
|
+
const selected = [];
|
|
169523
|
+
const selectedIds = new Set;
|
|
169524
|
+
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
169525
|
+
const tokenCost = (memory) => estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
169526
|
+
const trySelect = (memory) => {
|
|
169527
|
+
if (selectedIds.has(memory.id))
|
|
169528
|
+
return false;
|
|
169529
|
+
const tokens = tokenCost(memory);
|
|
169530
|
+
if (usedTokens + tokens > budgetTokens)
|
|
169531
|
+
return false;
|
|
169532
|
+
selected.push(memory);
|
|
169533
|
+
selectedIds.add(memory.id);
|
|
169534
|
+
usedTokens += tokens;
|
|
169535
|
+
return true;
|
|
169536
|
+
};
|
|
169537
|
+
for (const memory of memories.filter((candidate) => candidate.status === "permanent").sort(memorySelectionOrder)) {
|
|
169538
|
+
trySelect(memory);
|
|
169539
|
+
}
|
|
169540
|
+
const remainingAfterPermanent = Math.max(0, budgetTokens - usedTokens);
|
|
169541
|
+
const floorTokens = remainingAfterPermanent / Math.max(1, workspace.identities.length);
|
|
169542
|
+
const byIdentity = new Map;
|
|
169543
|
+
for (const memory of memories) {
|
|
169544
|
+
if (memory.status === "permanent")
|
|
169545
|
+
continue;
|
|
169546
|
+
const identity = memoryCanonicalIdentity(memory, workspace);
|
|
169547
|
+
if (!identity)
|
|
169548
|
+
continue;
|
|
169549
|
+
const list = byIdentity.get(identity) ?? [];
|
|
169550
|
+
list.push(memory);
|
|
169551
|
+
byIdentity.set(identity, list);
|
|
169552
|
+
}
|
|
169553
|
+
for (const identity of workspace.identities) {
|
|
169554
|
+
let memberTokens = 0;
|
|
169555
|
+
const candidates = (byIdentity.get(identity) ?? []).sort(memorySelectionOrder);
|
|
169556
|
+
for (const memory of candidates) {
|
|
169557
|
+
if (selectedIds.has(memory.id))
|
|
169558
|
+
continue;
|
|
169559
|
+
const tokens = tokenCost(memory);
|
|
169560
|
+
if (memberTokens + tokens > floorTokens)
|
|
169561
|
+
continue;
|
|
169562
|
+
if (usedTokens + tokens > budgetTokens)
|
|
169563
|
+
continue;
|
|
169564
|
+
selected.push(memory);
|
|
169565
|
+
selectedIds.add(memory.id);
|
|
169566
|
+
usedTokens += tokens;
|
|
169567
|
+
memberTokens += tokens;
|
|
169568
|
+
}
|
|
169569
|
+
}
|
|
169570
|
+
const remaining = memories.filter((memory) => !selectedIds.has(memory.id)).sort(memorySelectionOrder);
|
|
169571
|
+
for (const memory of remaining) {
|
|
169572
|
+
trySelect(memory);
|
|
169573
|
+
}
|
|
169574
|
+
if (selected.length < memories.length) {
|
|
169575
|
+
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
169576
|
+
}
|
|
169577
|
+
return { selected, renderOrder: [...selected].sort(memoryRenderOrder) };
|
|
169578
|
+
}
|
|
168074
169579
|
function safeGetActiveUserMemories(db) {
|
|
168075
169580
|
try {
|
|
168076
169581
|
return getActiveUserMemories(db);
|
|
@@ -168146,15 +169651,16 @@ function readNewMemoriesForM1(db, projectPath, afterId, expiryCutoff) {
|
|
|
168146
169651
|
ORDER BY ${MEMORY_CATEGORY_ORDER_SQL}, id ASC`).all(projectPath, afterId, expiryCutoff).filter(isMemoryRow);
|
|
168147
169652
|
return rows.map((row) => ({ ...row }));
|
|
168148
169653
|
}
|
|
168149
|
-
function renderMemoryLineV2(memory) {
|
|
168150
|
-
|
|
169654
|
+
function renderMemoryLineV2(memory, sourceName) {
|
|
169655
|
+
const sourceAttr = sourceName ? ` source="${escapeXmlAttr(sourceName)}"` : "";
|
|
169656
|
+
return ` <memory id="${memory.id}" category="${escapeXmlAttr(memory.category)}"${sourceAttr} importance="${memory.importance ?? 50}">${escapeXmlContent(memory.content)}</memory>`;
|
|
168151
169657
|
}
|
|
168152
|
-
function renderMemoryBlockV2(memories, wrapper = "project-memory") {
|
|
169658
|
+
function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions = {}) {
|
|
168153
169659
|
if (memories.length === 0)
|
|
168154
169660
|
return "";
|
|
168155
169661
|
const lines = [`<${wrapper}>`];
|
|
168156
169662
|
for (const memory of memories) {
|
|
168157
|
-
lines.push(renderMemoryLineV2(memory));
|
|
169663
|
+
lines.push(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
168158
169664
|
}
|
|
168159
169665
|
lines.push(`</${wrapper}>`);
|
|
168160
169666
|
return lines.join(`
|
|
@@ -168193,7 +169699,7 @@ function renderM0(args) {
|
|
|
168193
169699
|
sections.push(sessionHistory.length > 0 ? `<session-history>
|
|
168194
169700
|
${sessionHistory}
|
|
168195
169701
|
</session-history>` : M0_EMPTY_BODY);
|
|
168196
|
-
const memoriesBlock = renderMemoryBlockV2(args.memories);
|
|
169702
|
+
const memoriesBlock = renderMemoryBlockV2(args.memories, "project-memory", args.memoryRenderOptions);
|
|
168197
169703
|
if (memoriesBlock)
|
|
168198
169704
|
sections.push(memoriesBlock);
|
|
168199
169705
|
return sections.join(`
|
|
@@ -168205,6 +169711,7 @@ function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
|
|
|
168205
169711
|
if (m1Bytes)
|
|
168206
169712
|
state.cachedM1Bytes = m1Bytes;
|
|
168207
169713
|
state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
|
|
169714
|
+
state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
|
|
168208
169715
|
state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
|
|
168209
169716
|
state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
|
|
168210
169717
|
state.cachedM0MaxMemoryId = markers.maxMemoryId;
|
|
@@ -168230,24 +169737,38 @@ function materializeM0(options) {
|
|
|
168230
169737
|
let facts = [];
|
|
168231
169738
|
let memories = [];
|
|
168232
169739
|
let userMemories = [];
|
|
169740
|
+
let workspace = resolveWorkspaceRenderContext({
|
|
169741
|
+
db: options.db,
|
|
169742
|
+
projectPath,
|
|
169743
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169744
|
+
});
|
|
168233
169745
|
let docs = {
|
|
168234
169746
|
renderedBlock: "",
|
|
168235
169747
|
canonicalHash: ""
|
|
168236
169748
|
};
|
|
168237
169749
|
options.db.exec("BEGIN");
|
|
168238
169750
|
try {
|
|
169751
|
+
workspace = resolveWorkspaceRenderContext({
|
|
169752
|
+
db: options.db,
|
|
169753
|
+
projectPath,
|
|
169754
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169755
|
+
});
|
|
168239
169756
|
snapshotMarkers = readCurrentM0SnapshotMarkers({
|
|
168240
169757
|
db: options.db,
|
|
168241
169758
|
sessionId: options.sessionId,
|
|
168242
169759
|
projectPath,
|
|
168243
169760
|
projectDirectory,
|
|
168244
|
-
hardSignals: options.hardSignals
|
|
169761
|
+
hardSignals: options.hardSignals,
|
|
169762
|
+
workspaceIdentitySet: {
|
|
169763
|
+
identities: workspace.identities,
|
|
169764
|
+
namesByIdentity: workspace.namesByIdentity
|
|
169765
|
+
}
|
|
168245
169766
|
});
|
|
168246
169767
|
docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
|
|
168247
169768
|
snapshotMarkers.projectDocsHash = docs.canonicalHash;
|
|
168248
169769
|
compartments = readM0Compartments(options.db, options.sessionId);
|
|
168249
169770
|
facts = [];
|
|
168250
|
-
memories = projectPath ? getMemoriesByProject(options.db, projectPath, ["active", "permanent"]) : [];
|
|
169771
|
+
memories = projectPath ? workspace.isWorkspaced ? getMemoriesByProjects(options.db, workspace.expandedIdentities, ["active", "permanent"], Date.now(), workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(options.db, projectPath, ["active", "permanent"]) : [];
|
|
168251
169772
|
userMemories = safeGetActiveUserMemories(options.db);
|
|
168252
169773
|
options.db.exec("COMMIT");
|
|
168253
169774
|
} catch (error51) {
|
|
@@ -168257,7 +169778,14 @@ function materializeM0(options) {
|
|
|
168257
169778
|
throw error51;
|
|
168258
169779
|
}
|
|
168259
169780
|
const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
168260
|
-
const
|
|
169781
|
+
const memoryRenderOptions = {
|
|
169782
|
+
sourceNameByMemoryId: sourceNamesForMemories({
|
|
169783
|
+
memories,
|
|
169784
|
+
projectPath,
|
|
169785
|
+
workspace
|
|
169786
|
+
})
|
|
169787
|
+
};
|
|
169788
|
+
const trimmed = workspace.isWorkspaced ? trimWorkspaceMemoriesToBudgetV2(options.sessionId, memories, memoryBudget, workspace, memoryRenderOptions) : trimMemoriesToBudgetV2(options.sessionId, memories, memoryBudget);
|
|
168261
169789
|
let decayPressureMultiplier = 1;
|
|
168262
169790
|
let m0Text = renderM0({
|
|
168263
169791
|
projectDocs: docs.renderedBlock,
|
|
@@ -168265,6 +169793,7 @@ function materializeM0(options) {
|
|
|
168265
169793
|
compartments,
|
|
168266
169794
|
memories: trimmed.renderOrder,
|
|
168267
169795
|
facts,
|
|
169796
|
+
memoryRenderOptions,
|
|
168268
169797
|
historyBudgetTokens: options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS,
|
|
168269
169798
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168270
169799
|
decayPressureMultiplier
|
|
@@ -168279,6 +169808,7 @@ function materializeM0(options) {
|
|
|
168279
169808
|
compartments,
|
|
168280
169809
|
memories: trimmed.renderOrder,
|
|
168281
169810
|
facts,
|
|
169811
|
+
memoryRenderOptions,
|
|
168282
169812
|
historyBudgetTokens: budget,
|
|
168283
169813
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168284
169814
|
decayPressureMultiplier
|
|
@@ -168297,13 +169827,19 @@ function materializeM0(options) {
|
|
|
168297
169827
|
let m1Bytes = Buffer4.from(m1Text, "utf8");
|
|
168298
169828
|
options.db.exec("BEGIN IMMEDIATE");
|
|
168299
169829
|
try {
|
|
169830
|
+
const currentWorkspace = resolveWorkspaceRenderContext({
|
|
169831
|
+
db: options.db,
|
|
169832
|
+
projectPath,
|
|
169833
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169834
|
+
});
|
|
168300
169835
|
const current = {
|
|
168301
169836
|
projectMemoryEpoch: getProjectMemoryEpoch(options.db, projectPath),
|
|
169837
|
+
workspaceFingerprint: currentWorkspace.isWorkspaced ? computeWorkspaceEpochFingerprint(options.db, currentWorkspace.identities) : null,
|
|
168302
169838
|
projectUserProfileVersion: getGlobalUserProfileVersion(options.db),
|
|
168303
169839
|
maxCompartmentSeq: getMaxCompartmentSeq(options.db, options.sessionId),
|
|
168304
|
-
maxMemoryId: getMaxMemoryId(options.db, projectPath),
|
|
169840
|
+
maxMemoryId: currentWorkspace.isWorkspaced ? getMaxMemoryIdForProjects(options.db, currentWorkspace.expandedIdentities, currentWorkspace.ownIdentities, currentWorkspace.shareCategories) : getMaxMemoryId(options.db, projectPath),
|
|
168305
169841
|
maxMutationId: getMaxM0MutationId(options.db, options.sessionId) ?? 0,
|
|
168306
|
-
maxMemoryMutationId: projectPath ? getMaxMemoryMutationId(options.db, projectPath) ?? 0 : 0,
|
|
169842
|
+
maxMemoryMutationId: currentWorkspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(options.db, currentWorkspace.expandedIdentities) ?? 0 : projectPath ? getMaxMemoryMutationId(options.db, projectPath) ?? 0 : 0,
|
|
168307
169843
|
projectDocsHash: phase3ProjectDocsHash,
|
|
168308
169844
|
materializedAt: Date.now(),
|
|
168309
169845
|
sessionFactsVersion: getSessionFactsVersion(options.db, options.sessionId),
|
|
@@ -168311,17 +169847,26 @@ function materializeM0(options) {
|
|
|
168311
169847
|
systemHash: snapshotMarkers.systemHash,
|
|
168312
169848
|
modelKey: snapshotMarkers.modelKey
|
|
168313
169849
|
};
|
|
168314
|
-
const
|
|
169850
|
+
const memoryEpochStale = current.workspaceFingerprint !== null || snapshotMarkers.workspaceFingerprint !== null ? current.workspaceFingerprint !== snapshotMarkers.workspaceFingerprint : current.projectMemoryEpoch !== snapshotMarkers.projectMemoryEpoch;
|
|
169851
|
+
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;
|
|
168315
169852
|
if (stale) {
|
|
168316
169853
|
options.db.exec("ROLLBACK");
|
|
168317
169854
|
throw new MaterializeContentionError({ reason: "snapshot changed before Phase 3" });
|
|
168318
169855
|
}
|
|
168319
|
-
const m1Render = renderM1WithMetadata({
|
|
169856
|
+
const m1Render = renderM1WithMetadata({
|
|
169857
|
+
...options,
|
|
169858
|
+
preRenderedKeyFilesBlock,
|
|
169859
|
+
workspaceIdentitySet: {
|
|
169860
|
+
identities: workspace.identities,
|
|
169861
|
+
namesByIdentity: workspace.namesByIdentity
|
|
169862
|
+
}
|
|
169863
|
+
}, snapshotMarkers, renderedMemoryIds);
|
|
168320
169864
|
m1Text = m1Render.text;
|
|
168321
169865
|
m1Bytes = Buffer4.from(m1Text, "utf8");
|
|
168322
169866
|
persistCachedM0(options.db, options.sessionId, {
|
|
168323
169867
|
m0Bytes,
|
|
168324
169868
|
projectMemoryEpoch: snapshotMarkers.projectMemoryEpoch,
|
|
169869
|
+
workspaceFingerprint: snapshotMarkers.workspaceFingerprint,
|
|
168325
169870
|
projectUserProfileVersion: snapshotMarkers.projectUserProfileVersion,
|
|
168326
169871
|
maxCompartmentSeq: snapshotMarkers.maxCompartmentSeq,
|
|
168327
169872
|
maxMemoryId: snapshotMarkers.maxMemoryId,
|
|
@@ -168384,7 +169929,7 @@ function renderMemoryUpdatesBlock(args) {
|
|
|
168384
169929
|
return { block: "", count: 0 };
|
|
168385
169930
|
}
|
|
168386
169931
|
const renderedIds = new Set(args.renderedMemoryIds);
|
|
168387
|
-
const mutations = getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
169932
|
+
const mutations = args.workspace.isWorkspaced ? getMemoryMutationsForRenderByProjects(args.db, args.workspace.expandedIdentities, args.afterId, args.renderedMemoryIds) : getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
168388
169933
|
if (mutations.length === 0)
|
|
168389
169934
|
return { block: "", count: 0 };
|
|
168390
169935
|
const lines = ["These memories changed since the snapshot below — trust these:"];
|
|
@@ -168416,12 +169961,18 @@ function renderM1WithMetadata(options, markers, renderedMemoryIds) {
|
|
|
168416
169961
|
throw new RenderM1InvalidMarkersError(options.sessionId);
|
|
168417
169962
|
}
|
|
168418
169963
|
const blocks = [];
|
|
169964
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
169965
|
+
db: options.db,
|
|
169966
|
+
projectPath: options.projectPath,
|
|
169967
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169968
|
+
});
|
|
168419
169969
|
const keyFiles = renderedKeyFilesBlock(options);
|
|
168420
169970
|
if (keyFiles)
|
|
168421
169971
|
blocks.push(keyFiles);
|
|
168422
169972
|
const memoryUpdates = renderMemoryUpdatesBlock({
|
|
168423
169973
|
db: options.db,
|
|
168424
169974
|
projectPath: options.projectPath,
|
|
169975
|
+
workspace,
|
|
168425
169976
|
afterId: markers.maxMemoryMutationId,
|
|
168426
169977
|
renderedMemoryIds
|
|
168427
169978
|
});
|
|
@@ -168435,9 +169986,16 @@ ${newCompartments.map((compartment) => renderCompartmentAtTier(compartment, 1)).
|
|
|
168435
169986
|
`)}
|
|
168436
169987
|
</new-compartments>`);
|
|
168437
169988
|
}
|
|
168438
|
-
const newMemories = readNewMemoriesForM1(options.db, options.projectPath, markers.maxMemoryId, markers.materializedAt);
|
|
168439
|
-
const
|
|
168440
|
-
|
|
169989
|
+
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);
|
|
169990
|
+
const newMemoryRenderOptions = {
|
|
169991
|
+
sourceNameByMemoryId: sourceNamesForMemories({
|
|
169992
|
+
memories: newMemories,
|
|
169993
|
+
projectPath: options.projectPath,
|
|
169994
|
+
workspace
|
|
169995
|
+
})
|
|
169996
|
+
};
|
|
169997
|
+
const trimmedNewMemories = trimMemoriesToBudgetV2(options.sessionId, newMemories, Math.max(1, Math.floor((options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS) * 0.25)), newMemoryRenderOptions).renderOrder;
|
|
169998
|
+
const newMemoriesBlock = renderMemoryBlockV2(trimmedNewMemories, "new-memories", newMemoryRenderOptions);
|
|
168441
169999
|
if (newMemoriesBlock)
|
|
168442
170000
|
blocks.push(newMemoriesBlock);
|
|
168443
170001
|
const currentUserProfileVersion = getGlobalUserProfileVersion(options.db);
|
|
@@ -168485,6 +170043,7 @@ function parseMemoryBlockIds(raw) {
|
|
|
168485
170043
|
function readCachedM0M1Row(db, sessionId) {
|
|
168486
170044
|
return db.prepare(`SELECT cached_m0_bytes, cached_m1_bytes,
|
|
168487
170045
|
cached_m0_project_memory_epoch,
|
|
170046
|
+
cached_m0_workspace_fingerprint,
|
|
168488
170047
|
cached_m0_project_user_profile_version,
|
|
168489
170048
|
cached_m0_max_compartment_seq,
|
|
168490
170049
|
cached_m0_max_memory_id,
|
|
@@ -168519,6 +170078,7 @@ function markersFromCachedRow(row) {
|
|
|
168519
170078
|
return null;
|
|
168520
170079
|
return {
|
|
168521
170080
|
projectMemoryEpoch: row.cached_m0_project_memory_epoch,
|
|
170081
|
+
workspaceFingerprint: row.cached_m0_workspace_fingerprint,
|
|
168522
170082
|
projectUserProfileVersion: row.cached_m0_project_user_profile_version,
|
|
168523
170083
|
maxCompartmentSeq: row.cached_m0_max_compartment_seq,
|
|
168524
170084
|
maxMemoryId: row.cached_m0_max_memory_id,
|
|
@@ -168533,7 +170093,7 @@ function markersFromCachedRow(row) {
|
|
|
168533
170093
|
};
|
|
168534
170094
|
}
|
|
168535
170095
|
function cachedRowMatchesState(row, state) {
|
|
168536
|
-
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 &&
|
|
170096
|
+
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 ?? "");
|
|
168537
170097
|
}
|
|
168538
170098
|
function applyCachedRowToState(state, row) {
|
|
168539
170099
|
const markers = markersFromCachedRow(row);
|
|
@@ -168543,6 +170103,7 @@ function applyCachedRowToState(state, row) {
|
|
|
168543
170103
|
state.cachedM0Bytes = toBuffer(row.cached_m0_bytes);
|
|
168544
170104
|
state.cachedM1Bytes = toBuffer(row.cached_m1_bytes);
|
|
168545
170105
|
state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
|
|
170106
|
+
state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
|
|
168546
170107
|
state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
|
|
168547
170108
|
state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
|
|
168548
170109
|
state.cachedM0MaxMemoryId = markers.maxMemoryId;
|
|
@@ -168606,20 +170167,36 @@ function prependM0M1Messages(sessionId, messages, m0Text, m1Text) {
|
|
|
168606
170167
|
function renderFreshM0NonPersisted(options) {
|
|
168607
170168
|
const projectPath = options.projectPath;
|
|
168608
170169
|
const projectDirectory = options.projectDirectory;
|
|
170170
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
170171
|
+
db: options.db,
|
|
170172
|
+
projectPath,
|
|
170173
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
170174
|
+
});
|
|
168609
170175
|
const snapshotMarkers = readCurrentM0SnapshotMarkers({
|
|
168610
170176
|
db: options.db,
|
|
168611
170177
|
sessionId: options.sessionId,
|
|
168612
170178
|
projectPath,
|
|
168613
|
-
projectDirectory
|
|
170179
|
+
projectDirectory,
|
|
170180
|
+
workspaceIdentitySet: {
|
|
170181
|
+
identities: workspace.identities,
|
|
170182
|
+
namesByIdentity: workspace.namesByIdentity
|
|
170183
|
+
}
|
|
168614
170184
|
});
|
|
168615
170185
|
const docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
|
|
168616
170186
|
snapshotMarkers.projectDocsHash = docs.canonicalHash;
|
|
168617
170187
|
snapshotMarkers.materializedAt = options.state.cachedM0MaterializedAt ?? 0;
|
|
168618
170188
|
const compartments = readM0Compartments(options.db, options.sessionId);
|
|
168619
|
-
const memories = projectPath ? getMemoriesByProject(options.db, projectPath, ["active", "permanent"], snapshotMarkers.materializedAt) : [];
|
|
170189
|
+
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) : [];
|
|
168620
170190
|
const userMemories = safeGetActiveUserMemories(options.db);
|
|
168621
170191
|
const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
168622
|
-
const
|
|
170192
|
+
const memoryRenderOptions = {
|
|
170193
|
+
sourceNameByMemoryId: sourceNamesForMemories({
|
|
170194
|
+
memories,
|
|
170195
|
+
projectPath,
|
|
170196
|
+
workspace
|
|
170197
|
+
})
|
|
170198
|
+
};
|
|
170199
|
+
const trimmed = workspace.isWorkspaced ? trimWorkspaceMemoriesToBudgetV2(options.sessionId, memories, memoryBudget, workspace, memoryRenderOptions) : trimMemoriesToBudgetV2(options.sessionId, memories, memoryBudget);
|
|
168623
170200
|
const budget = options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
168624
170201
|
let decayPressureMultiplier = 1;
|
|
168625
170202
|
let m0Text = renderM0({
|
|
@@ -168628,6 +170205,7 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168628
170205
|
compartments,
|
|
168629
170206
|
memories: trimmed.renderOrder,
|
|
168630
170207
|
facts: [],
|
|
170208
|
+
memoryRenderOptions,
|
|
168631
170209
|
historyBudgetTokens: budget,
|
|
168632
170210
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168633
170211
|
decayPressureMultiplier
|
|
@@ -168641,6 +170219,7 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168641
170219
|
compartments,
|
|
168642
170220
|
memories: trimmed.renderOrder,
|
|
168643
170221
|
facts: [],
|
|
170222
|
+
memoryRenderOptions,
|
|
168644
170223
|
historyBudgetTokens: budget,
|
|
168645
170224
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168646
170225
|
decayPressureMultiplier
|
|
@@ -168656,6 +170235,12 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168656
170235
|
};
|
|
168657
170236
|
}
|
|
168658
170237
|
function injectM0M1(options) {
|
|
170238
|
+
if (!options.workspaceIdentitySet && options.projectPath) {
|
|
170239
|
+
options = {
|
|
170240
|
+
...options,
|
|
170241
|
+
workspaceIdentitySet: resolveWorkspaceIdentitySet(options.db, options.projectPath)
|
|
170242
|
+
};
|
|
170243
|
+
}
|
|
168659
170244
|
const skipped = {
|
|
168660
170245
|
injected: false,
|
|
168661
170246
|
m0RematerializedThisPass: false,
|
|
@@ -168672,7 +170257,8 @@ function injectM0M1(options) {
|
|
|
168672
170257
|
state: options.state,
|
|
168673
170258
|
projectPath: options.projectPath,
|
|
168674
170259
|
projectDirectory: options.projectDirectory,
|
|
168675
|
-
hardSignals: options.hardSignals
|
|
170260
|
+
hardSignals: options.hardSignals,
|
|
170261
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
168676
170262
|
});
|
|
168677
170263
|
let rematerialized = false;
|
|
168678
170264
|
let contentionExhausted = false;
|
|
@@ -168766,6 +170352,7 @@ var init_inject_compartments = __esm(async () => {
|
|
|
168766
170352
|
init_compartment_storage();
|
|
168767
170353
|
init_constants();
|
|
168768
170354
|
init_storage_memory();
|
|
170355
|
+
init_workspaces();
|
|
168769
170356
|
init_logger();
|
|
168770
170357
|
init_decay_render();
|
|
168771
170358
|
init_key_files_block();
|
|
@@ -171905,18 +173492,38 @@ async function runCompartmentAgent(deps) {
|
|
|
171905
173492
|
return;
|
|
171906
173493
|
}
|
|
171907
173494
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
171908
|
-
|
|
173495
|
+
let boundarySnapshot = deps.boundarySnapshot ?? null;
|
|
171909
173496
|
if (!boundarySnapshot) {
|
|
171910
173497
|
telemetry.failureReason = "missing protected-tail boundary snapshot";
|
|
171911
173498
|
sessionLog(sessionId, "historian no-op: missing protected-tail boundary snapshot from trigger decision");
|
|
171912
173499
|
rollbackDrainReservation();
|
|
171913
173500
|
return;
|
|
171914
173501
|
}
|
|
171915
|
-
|
|
173502
|
+
let validation = boundarySnapshot.rawRangeFingerprint.length > 0 ? validateBoundarySnapshot({
|
|
171916
173503
|
db,
|
|
171917
173504
|
snapshot: boundarySnapshot,
|
|
171918
173505
|
currentContextLimit: deps.currentContextLimit ?? boundarySnapshot.contextLimit
|
|
171919
173506
|
}) : { ok: true };
|
|
173507
|
+
if (!validation.ok && validation.reason === "stale_snapshot") {
|
|
173508
|
+
const refreshed = resolveOpenCodeProtectedTailBoundary({
|
|
173509
|
+
db,
|
|
173510
|
+
sessionId,
|
|
173511
|
+
mode: "incremental-runner",
|
|
173512
|
+
contextLimit: deps.currentContextLimit ?? boundarySnapshot.contextLimit,
|
|
173513
|
+
executeThresholdPercentage: boundarySnapshot.executeThresholdPercentage,
|
|
173514
|
+
usage: {
|
|
173515
|
+
percentage: boundarySnapshot.usagePercentage,
|
|
173516
|
+
inputTokens: boundarySnapshot.usageInputTokens
|
|
173517
|
+
},
|
|
173518
|
+
usageSource: boundarySnapshot.usageSource,
|
|
173519
|
+
emergencyTailScale: boundarySnapshot.emergencyTailScale
|
|
173520
|
+
});
|
|
173521
|
+
if (hasRunnableCompartmentWindow(refreshed)) {
|
|
173522
|
+
sessionLog(sessionId, `historian: refreshed stale protected-tail snapshot at run time (was: ${validation.detail ?? "stale"}) — eligible head ${refreshed.offset}-${refreshed.eligibleEndOrdinal - 1}`);
|
|
173523
|
+
boundarySnapshot = refreshed;
|
|
173524
|
+
validation = { ok: true };
|
|
173525
|
+
}
|
|
173526
|
+
}
|
|
171920
173527
|
if (!validation.ok) {
|
|
171921
173528
|
sessionLog(sessionId, `historian no-op: stale protected-tail snapshot (${validation.detail ?? validation.reason ?? "unknown"})`);
|
|
171922
173529
|
telemetry.status = "noop";
|
|
@@ -171985,6 +173592,7 @@ async function runCompartmentAgent(deps) {
|
|
|
171985
173592
|
rollbackDrainReservation();
|
|
171986
173593
|
return;
|
|
171987
173594
|
}
|
|
173595
|
+
deps.onHistorianRunStarted?.();
|
|
171988
173596
|
const projectPath = resolveProjectIdentity(directory ?? process.cwd());
|
|
171989
173597
|
const memories = getMemoriesByProject(db, projectPath, ["active", "permanent"]);
|
|
171990
173598
|
const projectMemory = renderMemoryBlock(memories) ?? "";
|
|
@@ -172117,8 +173725,13 @@ ${chunkText}`,
|
|
|
172117
173725
|
}
|
|
172118
173726
|
if (embeddingActive) {
|
|
172119
173727
|
const projectIdentity = resolveProjectIdentity(promotionDirectory);
|
|
172120
|
-
const
|
|
172121
|
-
|
|
173728
|
+
const chunksToEmbed = persistedCompartments.map((c, i) => ({
|
|
173729
|
+
id: persistedIds[i],
|
|
173730
|
+
startMessage: c.startMessage,
|
|
173731
|
+
endMessage: c.endMessage,
|
|
173732
|
+
sourceChunkText: chunk.text
|
|
173733
|
+
})).filter((c) => typeof c.id === "number");
|
|
173734
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
172122
173735
|
}
|
|
172123
173736
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
172124
173737
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
@@ -172349,8 +173962,12 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
172349
173962
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172350
173963
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
172351
173964
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172352
|
-
const
|
|
172353
|
-
|
|
173965
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
173966
|
+
id: c.id,
|
|
173967
|
+
startMessage: c.startMessage,
|
|
173968
|
+
endMessage: c.endMessage
|
|
173969
|
+
}));
|
|
173970
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
172354
173971
|
}
|
|
172355
173972
|
const lastCompartmentEnd2 = promoted2.compartments[promoted2.compartments.length - 1]?.endMessage ?? 0;
|
|
172356
173973
|
if (lastCompartmentEnd2 > 0) {
|
|
@@ -172563,8 +174180,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
172563
174180
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172564
174181
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
172565
174182
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172566
|
-
const
|
|
172567
|
-
|
|
174183
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
174184
|
+
id: c.id,
|
|
174185
|
+
startMessage: c.startMessage,
|
|
174186
|
+
endMessage: c.endMessage
|
|
174187
|
+
}));
|
|
174188
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
172568
174189
|
}
|
|
172569
174190
|
if (lastCompartmentEnd > 0) {
|
|
172570
174191
|
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
@@ -172745,8 +174366,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
172745
174366
|
if (deps.memoryEnabled !== false) {
|
|
172746
174367
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172747
174368
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172748
|
-
const
|
|
172749
|
-
|
|
174369
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
174370
|
+
id: c.id,
|
|
174371
|
+
startMessage: c.startMessage,
|
|
174372
|
+
endMessage: c.endMessage
|
|
174373
|
+
}));
|
|
174374
|
+
Promise.resolve(deps.ensureProjectRegistered?.(sessionDirectory, db)).then(() => embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed));
|
|
172750
174375
|
}
|
|
172751
174376
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
172752
174377
|
if (lastEnd > 0) {
|
|
@@ -174996,7 +176621,14 @@ function startCompartmentAgent(deps) {
|
|
|
174996
176621
|
return;
|
|
174997
176622
|
}
|
|
174998
176623
|
const renewal = startLeaseRenewal(deps, holderId);
|
|
174999
|
-
|
|
176624
|
+
let realRunStarted = false;
|
|
176625
|
+
const runnerDeps = withPublishedCallback({
|
|
176626
|
+
...deps,
|
|
176627
|
+
compartmentLeaseHolderId: holderId,
|
|
176628
|
+
onHistorianRunStarted: () => {
|
|
176629
|
+
realRunStarted = true;
|
|
176630
|
+
}
|
|
176631
|
+
});
|
|
175000
176632
|
const promise2 = runCompartmentAgent(runnerDeps).catch((err) => {
|
|
175001
176633
|
sessionLog(deps.sessionId, "compartment agent: unhandled rejection:", err);
|
|
175002
176634
|
try {
|
|
@@ -175010,6 +176642,9 @@ function startCompartmentAgent(deps) {
|
|
|
175010
176642
|
}
|
|
175011
176643
|
});
|
|
175012
176644
|
activeRuns.set(deps.sessionId, { promise: promise2, published: false });
|
|
176645
|
+
if (!realRunStarted && activeRuns.get(deps.sessionId)?.promise === promise2) {
|
|
176646
|
+
activeRuns.delete(deps.sessionId);
|
|
176647
|
+
}
|
|
175013
176648
|
}
|
|
175014
176649
|
async function executeContextRecompWithResult(deps, options = {}) {
|
|
175015
176650
|
const { sessionId } = deps;
|
|
@@ -175144,7 +176779,7 @@ function applyMemoryMigration(db, projectPath, result) {
|
|
|
175144
176779
|
inserted++;
|
|
175145
176780
|
}
|
|
175146
176781
|
if (removed > 0 || inserted > 0) {
|
|
175147
|
-
|
|
176782
|
+
bumpEpochsForWorkspaceMembers(db, projectPath);
|
|
175148
176783
|
}
|
|
175149
176784
|
})();
|
|
175150
176785
|
return { removed, inserted };
|
|
@@ -175602,15 +177237,15 @@ function shouldShowAnnouncement() {
|
|
|
175602
177237
|
}
|
|
175603
177238
|
return state.version !== ANNOUNCEMENT_VERSION;
|
|
175604
177239
|
}
|
|
175605
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
177240
|
+
var ANNOUNCEMENT_VERSION = "0.24.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
|
|
175606
177241
|
var init_announcement = __esm(() => {
|
|
175607
177242
|
init_data_path();
|
|
175608
177243
|
ANNOUNCEMENT_FEATURES = [
|
|
175609
|
-
"
|
|
175610
|
-
"
|
|
175611
|
-
"
|
|
175612
|
-
"
|
|
175613
|
-
"
|
|
177244
|
+
"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).",
|
|
177245
|
+
"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.",
|
|
177246
|
+
"Pi: fixed sessions overflowing the model context while still showing moderate usage — Pi now sheds context before a tool-heavy turn overflows.",
|
|
177247
|
+
"Fewer prompt-cache busts: doc edits, processed screenshots, and a rebuild-then-bust-again case no longer re-bill large prompt prefixes.",
|
|
177248
|
+
"Setup wizard now lists your actual models with type-ahead instead of fixed recommendations, and explains the historian/dreamer roles (issue #144). Plus a GitHub Copilot tool-pairing fix (#135)."
|
|
175614
177249
|
];
|
|
175615
177250
|
});
|
|
175616
177251
|
|
|
@@ -176404,6 +178039,10 @@ function getMagicContextBuiltinCommands() {
|
|
|
176404
178039
|
"ctx-dream": {
|
|
176405
178040
|
template: "ctx-dream",
|
|
176406
178041
|
description: "Run the hidden dreamer maintenance pass for this project now"
|
|
178042
|
+
},
|
|
178043
|
+
"ctx-embed-history": {
|
|
178044
|
+
template: "ctx-embed-history",
|
|
178045
|
+
description: "Embed all of this session's history compartments for semantic search, in one pass"
|
|
176407
178046
|
}
|
|
176408
178047
|
};
|
|
176409
178048
|
}
|
|
@@ -176897,7 +178536,7 @@ await init_storage_db();
|
|
|
176897
178536
|
// src/features/magic-context/v22-deferred-backfill.ts
|
|
176898
178537
|
init_logger();
|
|
176899
178538
|
init_project_identity();
|
|
176900
|
-
import { createHash as
|
|
178539
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
176901
178540
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
176902
178541
|
import path5 from "node:path";
|
|
176903
178542
|
var BATCH_SIZE = 25;
|
|
@@ -176951,7 +178590,7 @@ function computeLegacyRustDirIdentity(rawProjectPath) {
|
|
|
176951
178590
|
} catch {
|
|
176952
178591
|
canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
|
|
176953
178592
|
}
|
|
176954
|
-
return `dir:${
|
|
178593
|
+
return `dir:${createHash6("sha256").update(canonical, "utf8").digest("hex")}`;
|
|
176955
178594
|
}
|
|
176956
178595
|
function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
|
|
176957
178596
|
db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
|
|
@@ -180089,7 +181728,7 @@ init_project_identity();
|
|
|
180089
181728
|
// src/plugin/embedding-bootstrap-helpers.ts
|
|
180090
181729
|
init_embedding();
|
|
180091
181730
|
init_logger();
|
|
180092
|
-
import { createHash as
|
|
181731
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
180093
181732
|
var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
180094
181733
|
"embedding.api_key",
|
|
180095
181734
|
"embedding.endpoint",
|
|
@@ -180110,7 +181749,7 @@ var EMBEDDING_WARNING_TERMS = [
|
|
|
180110
181749
|
];
|
|
180111
181750
|
var loggedFailureSignatures = new Map;
|
|
180112
181751
|
function sha256Prefix2(value, length = 16) {
|
|
180113
|
-
return
|
|
181752
|
+
return createHash10("sha256").update(value).digest("hex").slice(0, length);
|
|
180114
181753
|
}
|
|
180115
181754
|
function warningLooksEmbeddingRelated(message) {
|
|
180116
181755
|
const lower = message.toLowerCase();
|
|
@@ -180747,6 +182386,7 @@ function createTagger() {
|
|
|
180747
182386
|
// src/hooks/magic-context/hook.ts
|
|
180748
182387
|
init_magic_context();
|
|
180749
182388
|
init_project_identity();
|
|
182389
|
+
init_project_embedding_registry();
|
|
180750
182390
|
await init_storage();
|
|
180751
182391
|
init_logger();
|
|
180752
182392
|
init_resolve_fallbacks();
|
|
@@ -181340,6 +182980,7 @@ function createMagicContextCommandHandler(deps) {
|
|
|
181340
182980
|
const isAugCommand = (command) => command === "ctx-aug";
|
|
181341
182981
|
const isDreamCommand = (command) => command === "ctx-dream";
|
|
181342
182982
|
const isSessionUpgradeCommand = (command) => command === "ctx-session-upgrade";
|
|
182983
|
+
const isEmbedHistoryCommand = (command) => command === "ctx-embed-history";
|
|
181343
182984
|
return {
|
|
181344
182985
|
"command.execute.before": async (input, _output, _params) => {
|
|
181345
182986
|
const isStatus = isStatusCommand(input.command);
|
|
@@ -181348,7 +182989,8 @@ function createMagicContextCommandHandler(deps) {
|
|
|
181348
182989
|
const isAug = isAugCommand(input.command);
|
|
181349
182990
|
const isDream = isDreamCommand(input.command);
|
|
181350
182991
|
const isSessionUpgrade = isSessionUpgradeCommand(input.command);
|
|
181351
|
-
|
|
182992
|
+
const isEmbedHistory = isEmbedHistoryCommand(input.command);
|
|
182993
|
+
if (!isStatus && !isFlush && !isRecomp && !isAug && !isDream && !isSessionUpgrade && !isEmbedHistory) {
|
|
181352
182994
|
return;
|
|
181353
182995
|
}
|
|
181354
182996
|
const sessionId = input.sessionID;
|
|
@@ -181361,6 +183003,11 @@ function createMagicContextCommandHandler(deps) {
|
|
|
181361
183003
|
await executeDreaming(deps, sessionId);
|
|
181362
183004
|
return;
|
|
181363
183005
|
}
|
|
183006
|
+
if (isEmbedHistory) {
|
|
183007
|
+
const summary = deps.executeEmbedHistory ? await deps.executeEmbedHistory(sessionId) : "Semantic embedding is not configured for this project, so there is nothing to embed.";
|
|
183008
|
+
await deps.sendNotification(sessionId, summary, {});
|
|
183009
|
+
throwSentinel(input.command);
|
|
183010
|
+
}
|
|
181364
183011
|
if (isFlush) {
|
|
181365
183012
|
result = executeFlush(deps.db, sessionId);
|
|
181366
183013
|
clearCachedM0M1(deps.db, sessionId);
|
|
@@ -182101,6 +183748,7 @@ await init_read_session_chunk();
|
|
|
182101
183748
|
// src/hooks/magic-context/transform.ts
|
|
182102
183749
|
init_project_identity();
|
|
182103
183750
|
import * as crypto2 from "node:crypto";
|
|
183751
|
+
init_session_project_storage();
|
|
182104
183752
|
init_storage_meta_persisted();
|
|
182105
183753
|
init_logger();
|
|
182106
183754
|
await init_storage();
|
|
@@ -182701,6 +184349,7 @@ await __promiseAll([
|
|
|
182701
184349
|
init_read_session_chunk(),
|
|
182702
184350
|
init_read_session_db()
|
|
182703
184351
|
]);
|
|
184352
|
+
|
|
182704
184353
|
// src/hooks/magic-context/sentinel.ts
|
|
182705
184354
|
var WHOLE_MESSAGE_PLACEHOLDER_TEXT = "[dropped]";
|
|
182706
184355
|
function modelAcceptsEmptyContent(providerID) {
|
|
@@ -182758,7 +184407,6 @@ function replaySentinelByMessageIds(messages, ids, providerID) {
|
|
|
182758
184407
|
missingIds.push(id);
|
|
182759
184408
|
return { replayed, missingIds };
|
|
182760
184409
|
}
|
|
182761
|
-
|
|
182762
184410
|
// src/hooks/magic-context/strip-content.ts
|
|
182763
184411
|
var DROPPED_PLACEHOLDER_PATTERN = /^\[dropped §\d+§\]$/;
|
|
182764
184412
|
var TAG_PREFIX_PATTERN = /^§\d+§\s*/;
|
|
@@ -183111,8 +184759,10 @@ function stripReasoningFromMergedAssistants(messages, providerID) {
|
|
|
183111
184759
|
}
|
|
183112
184760
|
return stripped;
|
|
183113
184761
|
}
|
|
183114
|
-
function stripProcessedImages(messages,
|
|
184762
|
+
function stripProcessedImages(messages, frozenIds, options) {
|
|
184763
|
+
const { detect, watermark, messageTagNumbers } = options;
|
|
183115
184764
|
let stripped = 0;
|
|
184765
|
+
const newlyStrippedIds = [];
|
|
183116
184766
|
let hasAssistantResponse = false;
|
|
183117
184767
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
183118
184768
|
const msg = messages[i];
|
|
@@ -183120,13 +184770,17 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
183120
184770
|
hasAssistantResponse = true;
|
|
183121
184771
|
continue;
|
|
183122
184772
|
}
|
|
183123
|
-
if (msg.info.role !== "user"
|
|
184773
|
+
if (msg.info.role !== "user") {
|
|
183124
184774
|
continue;
|
|
183125
184775
|
}
|
|
184776
|
+
const id = typeof msg.info.id === "string" ? msg.info.id : undefined;
|
|
184777
|
+
const inFrozen = id !== undefined && frozenIds.has(id);
|
|
183126
184778
|
const maxTag = messageTagNumbers.get(msg) ?? 0;
|
|
183127
|
-
|
|
184779
|
+
const isNewDetection = !inFrozen && detect && hasAssistantResponse && id !== undefined && maxTag <= watermark;
|
|
184780
|
+
if (!inFrozen && !isNewDetection) {
|
|
183128
184781
|
continue;
|
|
183129
184782
|
}
|
|
184783
|
+
let touchedThisMsg = false;
|
|
183130
184784
|
for (let j = 0;j < msg.parts.length; j++) {
|
|
183131
184785
|
const part = msg.parts[j];
|
|
183132
184786
|
if (!isRecord(part) || part.type !== "file") {
|
|
@@ -183138,10 +184792,14 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
183138
184792
|
if (typeof part.url === "string" && part.url.startsWith("data:") && part.url.length > 200) {
|
|
183139
184793
|
msg.parts[j] = makeSentinel(part);
|
|
183140
184794
|
stripped++;
|
|
184795
|
+
touchedThisMsg = true;
|
|
183141
184796
|
}
|
|
183142
184797
|
}
|
|
184798
|
+
if (touchedThisMsg && isNewDetection && id !== undefined) {
|
|
184799
|
+
newlyStrippedIds.push(id);
|
|
184800
|
+
}
|
|
183143
184801
|
}
|
|
183144
|
-
return stripped;
|
|
184802
|
+
return { stripped, newlyStrippedIds };
|
|
183145
184803
|
}
|
|
183146
184804
|
|
|
183147
184805
|
// src/hooks/magic-context/transform.ts
|
|
@@ -184084,6 +185742,7 @@ init_embedding();
|
|
|
184084
185742
|
|
|
184085
185743
|
// src/features/magic-context/search.ts
|
|
184086
185744
|
init_logger();
|
|
185745
|
+
init_compartment_chunk_embedding();
|
|
184087
185746
|
|
|
184088
185747
|
// src/features/magic-context/literal-probes.ts
|
|
184089
185748
|
var MAX_PROBES = 5;
|
|
@@ -184145,6 +185804,7 @@ function containsProbeVerbatim(text, probes) {
|
|
|
184145
185804
|
init_memory();
|
|
184146
185805
|
init_embedding();
|
|
184147
185806
|
init_storage_memory_fts();
|
|
185807
|
+
init_workspaces();
|
|
184148
185808
|
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
184149
185809
|
var FTS_SEMANTIC_CANDIDATE_LIMIT = 50;
|
|
184150
185810
|
var SEMANTIC_WEIGHT = 0.7;
|
|
@@ -184174,6 +185834,37 @@ function previewText(text) {
|
|
|
184174
185834
|
}
|
|
184175
185835
|
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}…`;
|
|
184176
185836
|
}
|
|
185837
|
+
function resolveSearchWorkspaceContext(db, projectPath, identitySet) {
|
|
185838
|
+
const resolved = identitySet ?? resolveWorkspaceIdentitySet(db, projectPath);
|
|
185839
|
+
const isWorkspaced = resolved.identities.length > 1;
|
|
185840
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(db, resolved.identities);
|
|
185841
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : resolved.identities;
|
|
185842
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(resolved.identities.map((identity) => [identity, identity]));
|
|
185843
|
+
const ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === projectPath);
|
|
185844
|
+
return {
|
|
185845
|
+
identities: resolved.identities,
|
|
185846
|
+
expandedIdentities,
|
|
185847
|
+
ownIdentities,
|
|
185848
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(db, projectPath) : null,
|
|
185849
|
+
namesByIdentity: resolved.namesByIdentity,
|
|
185850
|
+
canonicalIdentityByStoredPath,
|
|
185851
|
+
isWorkspaced
|
|
185852
|
+
};
|
|
185853
|
+
}
|
|
185854
|
+
function memoryWorkspaceIdentity(memory, workspace) {
|
|
185855
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
185856
|
+
}
|
|
185857
|
+
function sourceNamesForSearchMemories(args) {
|
|
185858
|
+
if (!args.workspace.isWorkspaced)
|
|
185859
|
+
return;
|
|
185860
|
+
const sourceNames = new Map;
|
|
185861
|
+
for (const memory of args.memories) {
|
|
185862
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
185863
|
+
if (source)
|
|
185864
|
+
sourceNames.set(memory.id, source);
|
|
185865
|
+
}
|
|
185866
|
+
return sourceNames.size > 0 ? sourceNames : undefined;
|
|
185867
|
+
}
|
|
184177
185868
|
function getMessageSearchStatement(db) {
|
|
184178
185869
|
let stmt = messageSearchStatements.get(db);
|
|
184179
185870
|
if (!stmt) {
|
|
@@ -184182,6 +185873,30 @@ function getMessageSearchStatement(db) {
|
|
|
184182
185873
|
}
|
|
184183
185874
|
return stmt;
|
|
184184
185875
|
}
|
|
185876
|
+
var ftsRowCountStatements = new WeakMap;
|
|
185877
|
+
var ftsMatchCountStatements = new WeakMap;
|
|
185878
|
+
function getSessionFtsRowCount(db, sessionId) {
|
|
185879
|
+
let stmt = ftsRowCountStatements.get(db);
|
|
185880
|
+
if (!stmt) {
|
|
185881
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ?");
|
|
185882
|
+
ftsRowCountStatements.set(db, stmt);
|
|
185883
|
+
}
|
|
185884
|
+
const row = stmt.get(sessionId);
|
|
185885
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
185886
|
+
}
|
|
185887
|
+
function countSessionFtsMatches(db, sessionId, ftsQuery) {
|
|
185888
|
+
let stmt = ftsMatchCountStatements.get(db);
|
|
185889
|
+
if (!stmt) {
|
|
185890
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ?");
|
|
185891
|
+
ftsMatchCountStatements.set(db, stmt);
|
|
185892
|
+
}
|
|
185893
|
+
try {
|
|
185894
|
+
const row = stmt.get(sessionId, ftsQuery);
|
|
185895
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
185896
|
+
} catch {
|
|
185897
|
+
return 0;
|
|
185898
|
+
}
|
|
185899
|
+
}
|
|
184185
185900
|
function getMessageOrdinal(value) {
|
|
184186
185901
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
184187
185902
|
return value;
|
|
@@ -184197,25 +185912,63 @@ async function getSemanticScores(args) {
|
|
|
184197
185912
|
if (!args.queryEmbedding || args.memories.length === 0) {
|
|
184198
185913
|
return semanticScores;
|
|
184199
185914
|
}
|
|
184200
|
-
|
|
184201
|
-
|
|
184202
|
-
|
|
184203
|
-
|
|
184204
|
-
|
|
184205
|
-
|
|
184206
|
-
|
|
185915
|
+
if (!args.workspace?.isWorkspaced) {
|
|
185916
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
185917
|
+
const embeddings = await ensureMemoryEmbeddings({
|
|
185918
|
+
db: args.db,
|
|
185919
|
+
projectIdentity: args.projectPath,
|
|
185920
|
+
memories: args.memories,
|
|
185921
|
+
existingEmbeddings: cachedEmbeddings
|
|
185922
|
+
});
|
|
185923
|
+
for (const memory of args.memories) {
|
|
185924
|
+
const memoryEmbedding = embeddings.get(memory.id);
|
|
185925
|
+
if (!memoryEmbedding) {
|
|
185926
|
+
continue;
|
|
185927
|
+
}
|
|
185928
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
185929
|
+
}
|
|
185930
|
+
return semanticScores;
|
|
185931
|
+
}
|
|
185932
|
+
if (!args.queryModelId || args.queryModelId === "off") {
|
|
185933
|
+
return semanticScores;
|
|
185934
|
+
}
|
|
185935
|
+
const workspace = args.workspace;
|
|
185936
|
+
const memoriesByIdentity = new Map;
|
|
184207
185937
|
for (const memory of args.memories) {
|
|
184208
|
-
const
|
|
184209
|
-
if (!
|
|
185938
|
+
const identity = memoryWorkspaceIdentity(memory, workspace);
|
|
185939
|
+
if (!identity)
|
|
185940
|
+
continue;
|
|
185941
|
+
const list = memoriesByIdentity.get(identity) ?? [];
|
|
185942
|
+
list.push(memory);
|
|
185943
|
+
memoriesByIdentity.set(identity, list);
|
|
185944
|
+
}
|
|
185945
|
+
const ownMemories = memoriesByIdentity.get(args.projectPath) ?? [];
|
|
185946
|
+
if (ownMemories.length > 0) {
|
|
185947
|
+
const ownEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
185948
|
+
await ensureMemoryEmbeddings({
|
|
185949
|
+
db: args.db,
|
|
185950
|
+
projectIdentity: args.projectPath,
|
|
185951
|
+
memories: ownMemories,
|
|
185952
|
+
existingEmbeddings: ownEmbeddings
|
|
185953
|
+
});
|
|
185954
|
+
}
|
|
185955
|
+
for (const identity of workspace.identities) {
|
|
185956
|
+
const memberMemories = memoriesByIdentity.get(identity) ?? [];
|
|
185957
|
+
if (memberMemories.length === 0)
|
|
184210
185958
|
continue;
|
|
185959
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, identity);
|
|
185960
|
+
for (const memory of memberMemories) {
|
|
185961
|
+
const memoryEmbedding = cachedEmbeddings.get(memory.id);
|
|
185962
|
+
if (!memoryEmbedding || memoryEmbedding.modelId !== args.queryModelId)
|
|
185963
|
+
continue;
|
|
185964
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
184211
185965
|
}
|
|
184212
|
-
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
|
|
184213
185966
|
}
|
|
184214
185967
|
return semanticScores;
|
|
184215
185968
|
}
|
|
184216
185969
|
function getFtsMatches(args) {
|
|
184217
185970
|
try {
|
|
184218
|
-
return searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
185971
|
+
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);
|
|
184219
185972
|
} catch (error51) {
|
|
184220
185973
|
log(`[search] FTS query failed for "${args.query}": ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
184221
185974
|
return [];
|
|
@@ -184229,8 +185982,11 @@ function selectSemanticCandidates(args) {
|
|
|
184229
185982
|
return args.memories;
|
|
184230
185983
|
}
|
|
184231
185984
|
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
184232
|
-
const
|
|
184233
|
-
|
|
185985
|
+
const embeddingProjects = args.workspace?.isWorkspaced ? args.workspace.identities : [args.projectPath];
|
|
185986
|
+
for (const projectPath of embeddingProjects) {
|
|
185987
|
+
const cachedEmbeddings = peekProjectEmbeddings(projectPath);
|
|
185988
|
+
if (!cachedEmbeddings)
|
|
185989
|
+
continue;
|
|
184234
185990
|
for (const memoryId of cachedEmbeddings.keys()) {
|
|
184235
185991
|
candidateIds.add(memoryId);
|
|
184236
185992
|
}
|
|
@@ -184272,7 +186028,8 @@ function mergeMemoryResults(args) {
|
|
|
184272
186028
|
score,
|
|
184273
186029
|
memoryId: memory.id,
|
|
184274
186030
|
category: memory.category,
|
|
184275
|
-
matchType
|
|
186031
|
+
matchType,
|
|
186032
|
+
sourceName: args.sourceNameByMemoryId?.get(memory.id)
|
|
184276
186033
|
});
|
|
184277
186034
|
}
|
|
184278
186035
|
return results.sort((left, right) => {
|
|
@@ -184286,7 +186043,7 @@ async function searchMemories(args) {
|
|
|
184286
186043
|
if (!args.memoryEnabled) {
|
|
184287
186044
|
return [];
|
|
184288
186045
|
}
|
|
184289
|
-
const memories = getMemoriesByProject(args.db, args.projectPath);
|
|
186046
|
+
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);
|
|
184290
186047
|
if (memories.length === 0) {
|
|
184291
186048
|
return [];
|
|
184292
186049
|
}
|
|
@@ -184294,26 +186051,43 @@ async function searchMemories(args) {
|
|
|
184294
186051
|
db: args.db,
|
|
184295
186052
|
projectPath: args.projectPath,
|
|
184296
186053
|
query: args.query,
|
|
184297
|
-
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
186054
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT,
|
|
186055
|
+
workspace: args.workspace
|
|
184298
186056
|
});
|
|
184299
186057
|
const ftsScores = getFtsScores(ftsMatches);
|
|
184300
186058
|
const semanticCandidates = selectSemanticCandidates({
|
|
184301
186059
|
memories,
|
|
184302
186060
|
projectPath: args.projectPath,
|
|
184303
|
-
ftsMatches
|
|
186061
|
+
ftsMatches,
|
|
186062
|
+
workspace: args.workspace
|
|
184304
186063
|
});
|
|
184305
186064
|
const semanticScores = await getSemanticScores({
|
|
184306
186065
|
db: args.db,
|
|
184307
186066
|
projectPath: args.projectPath,
|
|
184308
186067
|
memories: semanticCandidates,
|
|
184309
|
-
queryEmbedding: args.queryEmbedding
|
|
186068
|
+
queryEmbedding: args.queryEmbedding,
|
|
186069
|
+
queryModelId: args.queryModelId,
|
|
186070
|
+
workspace: args.workspace
|
|
184310
186071
|
});
|
|
184311
186072
|
return mergeMemoryResults({
|
|
184312
186073
|
memories,
|
|
184313
186074
|
semanticScores,
|
|
184314
186075
|
ftsScores,
|
|
184315
186076
|
limit: args.limit,
|
|
184316
|
-
visibleMemoryIds: args.visibleMemoryIds
|
|
186077
|
+
visibleMemoryIds: args.visibleMemoryIds,
|
|
186078
|
+
sourceNameByMemoryId: sourceNamesForSearchMemories({
|
|
186079
|
+
memories,
|
|
186080
|
+
projectPath: args.projectPath,
|
|
186081
|
+
workspace: args.workspace ?? {
|
|
186082
|
+
identities: [args.projectPath],
|
|
186083
|
+
expandedIdentities: [args.projectPath],
|
|
186084
|
+
namesByIdentity: new Map,
|
|
186085
|
+
canonicalIdentityByStoredPath: new Map([[args.projectPath, args.projectPath]]),
|
|
186086
|
+
ownIdentities: [args.projectPath],
|
|
186087
|
+
shareCategories: null,
|
|
186088
|
+
isWorkspaced: false
|
|
186089
|
+
}
|
|
186090
|
+
})
|
|
184317
186091
|
});
|
|
184318
186092
|
}
|
|
184319
186093
|
function linearDecayScore(rank, total) {
|
|
@@ -184344,7 +186118,13 @@ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
|
|
|
184344
186118
|
return result;
|
|
184345
186119
|
}
|
|
184346
186120
|
var RRF_K = 60;
|
|
184347
|
-
var
|
|
186121
|
+
var VERBATIM_RANK_BONUS = 1 / RRF_K;
|
|
186122
|
+
var IDF_FALLOFF = 100;
|
|
186123
|
+
function probeDiscriminationWeight(df, corpusSize) {
|
|
186124
|
+
if (corpusSize <= 0 || df <= 0)
|
|
186125
|
+
return 1;
|
|
186126
|
+
return 1 / (1 + IDF_FALLOFF * df / corpusSize);
|
|
186127
|
+
}
|
|
184348
186128
|
function searchMessages(args) {
|
|
184349
186129
|
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
184350
186130
|
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
@@ -184361,20 +186141,31 @@ function searchMessages(args) {
|
|
|
184361
186141
|
role: row.role
|
|
184362
186142
|
}));
|
|
184363
186143
|
}
|
|
186144
|
+
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId);
|
|
184364
186145
|
const queryLists = [];
|
|
184365
186146
|
if (baseQuery.length > 0) {
|
|
184366
|
-
queryLists.push(
|
|
186147
|
+
queryLists.push({
|
|
186148
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff),
|
|
186149
|
+
weight: 1
|
|
186150
|
+
});
|
|
184367
186151
|
}
|
|
186152
|
+
const probeWeights = new Map;
|
|
184368
186153
|
for (const probe of probes) {
|
|
184369
186154
|
const probeQuery = sanitizeFtsQuery(probe);
|
|
184370
186155
|
if (probeQuery.length === 0)
|
|
184371
186156
|
continue;
|
|
184372
|
-
|
|
186157
|
+
const df = countSessionFtsMatches(args.db, args.sessionId, probeQuery);
|
|
186158
|
+
const weight = probeDiscriminationWeight(df, corpusSize);
|
|
186159
|
+
probeWeights.set(probe, weight);
|
|
186160
|
+
queryLists.push({
|
|
186161
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff),
|
|
186162
|
+
weight
|
|
186163
|
+
});
|
|
184373
186164
|
}
|
|
184374
186165
|
const fused = new Map;
|
|
184375
186166
|
for (const list of queryLists) {
|
|
184376
|
-
list.forEach((row, rank) => {
|
|
184377
|
-
const rrf =
|
|
186167
|
+
list.rows.forEach((row, rank) => {
|
|
186168
|
+
const rrf = list.weight / (RRF_K + rank);
|
|
184378
186169
|
const existing = fused.get(row.messageId);
|
|
184379
186170
|
if (existing) {
|
|
184380
186171
|
existing.score += rrf;
|
|
@@ -184384,26 +186175,107 @@ function searchMessages(args) {
|
|
|
184384
186175
|
});
|
|
184385
186176
|
}
|
|
184386
186177
|
for (const entry of fused.values()) {
|
|
184387
|
-
|
|
184388
|
-
|
|
186178
|
+
let best = 0;
|
|
186179
|
+
for (const probe of probes) {
|
|
186180
|
+
const weight = probeWeights.get(probe) ?? 0;
|
|
186181
|
+
if (weight > best && containsProbeVerbatim(entry.row.content, [probe])) {
|
|
186182
|
+
best = weight;
|
|
186183
|
+
}
|
|
186184
|
+
}
|
|
186185
|
+
if (best > 0) {
|
|
186186
|
+
entry.score += best * VERBATIM_RANK_BONUS;
|
|
184389
186187
|
}
|
|
184390
186188
|
}
|
|
184391
186189
|
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);
|
|
184392
|
-
|
|
184393
|
-
return ranked.map((entry) => ({
|
|
186190
|
+
return ranked.map((entry, rank) => ({
|
|
184394
186191
|
source: "message",
|
|
184395
186192
|
content: previewText(entry.row.content),
|
|
184396
|
-
score:
|
|
186193
|
+
score: linearDecayScore(rank, ranked.length),
|
|
184397
186194
|
messageOrdinal: entry.row.messageOrdinal,
|
|
184398
186195
|
messageId: entry.row.messageId,
|
|
184399
186196
|
role: entry.row.role
|
|
184400
186197
|
}));
|
|
184401
186198
|
}
|
|
186199
|
+
function searchCompartmentChunks(args) {
|
|
186200
|
+
if (!args.queryEmbedding || args.limit <= 0)
|
|
186201
|
+
return [];
|
|
186202
|
+
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
186203
|
+
const rows = loadCompartmentChunkEmbeddingsForSearch(args.db, args.sessionId, args.projectPath, args.modelId);
|
|
186204
|
+
if (rows.length === 0)
|
|
186205
|
+
return [];
|
|
186206
|
+
const byCompartment = new Map;
|
|
186207
|
+
for (const row of rows) {
|
|
186208
|
+
if (cutoff !== null && row.endOrdinal > cutoff) {
|
|
186209
|
+
continue;
|
|
186210
|
+
}
|
|
186211
|
+
const score = normalizeCosineScore(cosineSimilarity(args.queryEmbedding, row.vector));
|
|
186212
|
+
if (score <= 0)
|
|
186213
|
+
continue;
|
|
186214
|
+
const existing = byCompartment.get(row.compartmentId);
|
|
186215
|
+
if (!existing || score > existing.score) {
|
|
186216
|
+
byCompartment.set(row.compartmentId, { row, score });
|
|
186217
|
+
}
|
|
186218
|
+
}
|
|
186219
|
+
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 }) => ({
|
|
186220
|
+
source: "compartment",
|
|
186221
|
+
content: previewText(row.title),
|
|
186222
|
+
score: score * SINGLE_SOURCE_PENALTY,
|
|
186223
|
+
compartmentId: row.compartmentId,
|
|
186224
|
+
sessionId: row.sessionId,
|
|
186225
|
+
title: row.title,
|
|
186226
|
+
startOrdinal: row.startOrdinal,
|
|
186227
|
+
endOrdinal: row.endOrdinal,
|
|
186228
|
+
matchType: "semantic"
|
|
186229
|
+
}));
|
|
186230
|
+
}
|
|
186231
|
+
function mergeMessageAndCompartmentResults(args) {
|
|
186232
|
+
if (args.compartments.length === 0)
|
|
186233
|
+
return args.messages;
|
|
186234
|
+
if (args.messages.length === 0)
|
|
186235
|
+
return args.compartments;
|
|
186236
|
+
const fused = new Map;
|
|
186237
|
+
const add = (key, result, score, tieOrdinal) => {
|
|
186238
|
+
const existing = fused.get(key);
|
|
186239
|
+
if (existing) {
|
|
186240
|
+
existing.score += score;
|
|
186241
|
+
return existing;
|
|
186242
|
+
}
|
|
186243
|
+
const entry = { result, score, tieOrdinal, snippetScore: -1 };
|
|
186244
|
+
fused.set(key, entry);
|
|
186245
|
+
return entry;
|
|
186246
|
+
};
|
|
186247
|
+
args.compartments.forEach((compartment, rank) => {
|
|
186248
|
+
add(`compartment:${compartment.compartmentId}`, compartment, 1 / (RRF_K + rank), compartment.startOrdinal);
|
|
186249
|
+
});
|
|
186250
|
+
for (const [rank, message] of args.messages.entries()) {
|
|
186251
|
+
const containing = args.compartments.find((compartment) => message.messageOrdinal >= compartment.startOrdinal && message.messageOrdinal <= compartment.endOrdinal);
|
|
186252
|
+
const contribution = 1 / (RRF_K + rank);
|
|
186253
|
+
if (!containing) {
|
|
186254
|
+
add(`message:${message.messageId}`, message, contribution, message.messageOrdinal);
|
|
186255
|
+
continue;
|
|
186256
|
+
}
|
|
186257
|
+
const entry = add(`compartment:${containing.compartmentId}`, containing, contribution, containing.startOrdinal);
|
|
186258
|
+
if (message.score > entry.snippetScore && entry.result.source === "compartment") {
|
|
186259
|
+
entry.snippetScore = message.score;
|
|
186260
|
+
entry.result = {
|
|
186261
|
+
...entry.result,
|
|
186262
|
+
matchType: "hybrid",
|
|
186263
|
+
snippet: message.content
|
|
186264
|
+
};
|
|
186265
|
+
}
|
|
186266
|
+
}
|
|
186267
|
+
const ranked = [...fused.values()].sort((left, right) => right.score !== left.score ? right.score - left.score : left.tieOrdinal - right.tieOrdinal).slice(0, args.limit);
|
|
186268
|
+
return ranked.map((entry, rank) => ({
|
|
186269
|
+
...entry.result,
|
|
186270
|
+
score: linearDecayScore(rank, ranked.length)
|
|
186271
|
+
}));
|
|
186272
|
+
}
|
|
184402
186273
|
function getSourceBoost(result) {
|
|
184403
186274
|
switch (result.source) {
|
|
184404
186275
|
case "memory":
|
|
184405
186276
|
return MEMORY_SOURCE_BOOST;
|
|
184406
186277
|
case "message":
|
|
186278
|
+
case "compartment":
|
|
184407
186279
|
return MESSAGE_SOURCE_BOOST;
|
|
184408
186280
|
case "git_commit":
|
|
184409
186281
|
return GIT_COMMIT_SOURCE_BOOST;
|
|
@@ -184421,6 +186293,9 @@ function compareUnifiedResults(left, right) {
|
|
|
184421
186293
|
if (left.source === "message" && right.source === "message") {
|
|
184422
186294
|
return left.messageOrdinal - right.messageOrdinal;
|
|
184423
186295
|
}
|
|
186296
|
+
if (left.source === "compartment" && right.source === "compartment") {
|
|
186297
|
+
return left.startOrdinal - right.startOrdinal;
|
|
186298
|
+
}
|
|
184424
186299
|
if (left.source === "git_commit" && right.source === "git_commit") {
|
|
184425
186300
|
return right.committedAtMs - left.committedAtMs;
|
|
184426
186301
|
}
|
|
@@ -184471,10 +186346,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
184471
186346
|
const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
|
|
184472
186347
|
const gitCommitsEnabled = options.gitCommitsEnabled ?? false;
|
|
184473
186348
|
const activeSources = resolveSources(options.sources);
|
|
184474
|
-
const
|
|
186349
|
+
const memoryFeatureEnabled = options.memoryEnabled ?? true;
|
|
186350
|
+
const runMemory = activeSources.has("memory") && memoryFeatureEnabled;
|
|
184475
186351
|
const runMessages = activeSources.has("message");
|
|
184476
186352
|
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
184477
|
-
const
|
|
186353
|
+
const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
|
|
186354
|
+
const needsEmbedding = (runMemory || runGitCommits || runCompartmentChunks) && embeddingEnabled && isEmbeddingRuntimeEnabled();
|
|
184478
186355
|
const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error51) => {
|
|
184479
186356
|
log(`[search] query embedding failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
184480
186357
|
return null;
|
|
@@ -184490,6 +186367,24 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
184490
186367
|
probes: messageProbes
|
|
184491
186368
|
}) : [];
|
|
184492
186369
|
const queryEmbedding = await queryEmbeddingPromise;
|
|
186370
|
+
const workspace = resolveSearchWorkspaceContext(db, projectPath);
|
|
186371
|
+
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
186372
|
+
const embeddingModelId = embeddingSnapshot?.modelId;
|
|
186373
|
+
const chunkModelId = embeddingSnapshot?.chunkModelId;
|
|
186374
|
+
const compartmentResults = runCompartmentChunks ? searchCompartmentChunks({
|
|
186375
|
+
db,
|
|
186376
|
+
sessionId,
|
|
186377
|
+
projectPath,
|
|
186378
|
+
queryEmbedding,
|
|
186379
|
+
limit: tierLimit,
|
|
186380
|
+
maxOrdinal: options.maxMessageOrdinal,
|
|
186381
|
+
modelId: chunkModelId && chunkModelId !== "off" ? chunkModelId : null
|
|
186382
|
+
}) : [];
|
|
186383
|
+
const messageLikeResults = mergeMessageAndCompartmentResults({
|
|
186384
|
+
messages: messageResults,
|
|
186385
|
+
compartments: compartmentResults,
|
|
186386
|
+
limit: tierLimit
|
|
186387
|
+
});
|
|
184493
186388
|
const [memoryResults, gitCommitResults] = await Promise.all([
|
|
184494
186389
|
runMemory ? searchMemories({
|
|
184495
186390
|
db,
|
|
@@ -184498,6 +186393,8 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
184498
186393
|
limit: tierLimit,
|
|
184499
186394
|
memoryEnabled: true,
|
|
184500
186395
|
queryEmbedding,
|
|
186396
|
+
queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null,
|
|
186397
|
+
workspace,
|
|
184501
186398
|
visibleMemoryIds: options.visibleMemoryIds
|
|
184502
186399
|
}) : Promise.resolve([]),
|
|
184503
186400
|
runGitCommits ? Promise.resolve(searchGitCommits({
|
|
@@ -184508,7 +186405,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
184508
186405
|
queryEmbedding
|
|
184509
186406
|
})) : Promise.resolve([])
|
|
184510
186407
|
]);
|
|
184511
|
-
const results = [...memoryResults, ...
|
|
186408
|
+
const results = [...memoryResults, ...messageLikeResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
|
|
184512
186409
|
const countRetrievals = options.countRetrievals ?? true;
|
|
184513
186410
|
if (countRetrievals) {
|
|
184514
186411
|
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
@@ -184572,6 +186469,11 @@ function renderFragment(result, charCap) {
|
|
|
184572
186469
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
184573
186470
|
return truncate(compressed, charCap);
|
|
184574
186471
|
}
|
|
186472
|
+
case "compartment": {
|
|
186473
|
+
const source = result.snippet ?? result.title;
|
|
186474
|
+
const compressed = cavemanCompress(source, "ultra");
|
|
186475
|
+
return truncate(compressed, charCap);
|
|
186476
|
+
}
|
|
184575
186477
|
}
|
|
184576
186478
|
}
|
|
184577
186479
|
function buildAutoSearchHint(results, options = {}) {
|
|
@@ -185212,7 +187114,7 @@ function isVisibleNoteReadPart(part) {
|
|
|
185212
187114
|
}
|
|
185213
187115
|
|
|
185214
187116
|
// src/hooks/magic-context/todo-view.ts
|
|
185215
|
-
import { createHash as
|
|
187117
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
185216
187118
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
185217
187119
|
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
185218
187120
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
@@ -185257,7 +187159,7 @@ function buildSyntheticTodoPart(stateJson) {
|
|
|
185257
187159
|
};
|
|
185258
187160
|
}
|
|
185259
187161
|
function computeSyntheticCallId(stateJson) {
|
|
185260
|
-
const hash2 =
|
|
187162
|
+
const hash2 = createHash11("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
185261
187163
|
return `${SYNTHETIC_CALL_ID_PREFIX}${hash2}`;
|
|
185262
187164
|
}
|
|
185263
187165
|
function parseTodoState(stateJson) {
|
|
@@ -185308,15 +187210,25 @@ async function runPostTransformPhase(args) {
|
|
|
185308
187210
|
const emergencyBypassCompartmentGate = forceMaterialization;
|
|
185309
187211
|
const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
185310
187212
|
const materializationRequested = isExplicitFlush || deferredMaterialize;
|
|
185311
|
-
const
|
|
187213
|
+
const m0M1EnabledForFold = args.fullFeatureMode && args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory);
|
|
187214
|
+
const m0HardFoldThisPass = m0M1EnabledForFold && args.m0M1 ? mustMaterialize({
|
|
187215
|
+
db: args.db,
|
|
187216
|
+
sessionId: args.sessionId,
|
|
187217
|
+
state: args.sessionMeta,
|
|
187218
|
+
projectPath: args.m0M1.projectPath,
|
|
187219
|
+
projectDirectory: args.m0M1.projectDirectory,
|
|
187220
|
+
hardSignals: args.m0M1.hardSignals
|
|
187221
|
+
}).value : false;
|
|
187222
|
+
const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning;
|
|
185312
187223
|
const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
|
|
185313
187224
|
const hasPendingUserOps = pendingOps.length > 0;
|
|
185314
|
-
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization) && (!compartmentRunning || emergencyBypassCompartmentGate);
|
|
185315
|
-
const shouldRunHeuristics = (!compartmentRunning || emergencyBypassCompartmentGate) && (materializationRequested || forceMaterialization || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
|
|
187225
|
+
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || emergencyBypassCompartmentGate);
|
|
187226
|
+
const shouldRunHeuristics = (!compartmentRunning || emergencyBypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
|
|
185316
187227
|
const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
|
|
187228
|
+
const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
|
|
185317
187229
|
if (shouldRunHeuristics) {
|
|
185318
187230
|
const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
|
|
185319
|
-
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})`;
|
|
187231
|
+
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})`;
|
|
185320
187232
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
|
|
185321
187233
|
}
|
|
185322
187234
|
if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
|
|
@@ -185359,7 +187271,9 @@ async function runPostTransformPhase(args) {
|
|
|
185359
187271
|
logTransformTiming(args.sessionId, "applyHeuristicCleanup", t5, `droppedTools=${cleanup.droppedTools} deduplicatedTools=${cleanup.deduplicatedTools} droppedInjections=${cleanup.droppedInjections} compressedTextTags=${cleanup.compressedTextTags}`);
|
|
185360
187272
|
const t7 = performance.now();
|
|
185361
187273
|
const clearedReasoning = clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge);
|
|
185362
|
-
|
|
187274
|
+
if (canUseEmptySentinels) {
|
|
187275
|
+
stripClearedReasoning(args.messages);
|
|
187276
|
+
}
|
|
185363
187277
|
const strippedInline = stripInlineThinking(args.messages, args.messageTagNumbers, args.clearReasoningAge);
|
|
185364
187278
|
if (clearedReasoning > 0 || strippedInline > 0) {
|
|
185365
187279
|
let maxTag = 0;
|
|
@@ -185405,7 +187319,6 @@ async function runPostTransformPhase(args) {
|
|
|
185405
187319
|
if (args.watermark > 0) {
|
|
185406
187320
|
const tWatermarkCleanup = performance.now();
|
|
185407
187321
|
truncateErroredTools(args.messages, args.watermark, args.messageTagNumbers);
|
|
185408
|
-
stripProcessedImages(args.messages, args.watermark, args.messageTagNumbers);
|
|
185409
187322
|
logTransformTiming(args.sessionId, "watermarkCleanup", tWatermarkCleanup);
|
|
185410
187323
|
}
|
|
185411
187324
|
if (shouldApplyPendingOps) {
|
|
@@ -185415,21 +187328,40 @@ async function runPostTransformPhase(args) {
|
|
|
185415
187328
|
sessionLog(args.sessionId, "transform failed applying pending operations:", error51);
|
|
185416
187329
|
updateSessionMeta(args.db, args.sessionId, { lastTransformError: getErrorMessage(error51) });
|
|
185417
187330
|
}
|
|
185418
|
-
|
|
185419
|
-
|
|
185420
|
-
|
|
185421
|
-
|
|
185422
|
-
|
|
185423
|
-
|
|
185424
|
-
|
|
185425
|
-
|
|
185426
|
-
|
|
187331
|
+
if (canUseEmptySentinels) {
|
|
187332
|
+
try {
|
|
187333
|
+
const t8 = performance.now();
|
|
187334
|
+
const frozenStaleReduceIds = getStaleReduceStrippedIds(args.db, args.sessionId);
|
|
187335
|
+
const staleReduceResult = dropStaleReduceCalls(args.messages, frozenStaleReduceIds, {
|
|
187336
|
+
detect: isCacheBustingPass,
|
|
187337
|
+
protectedCount: args.protectedTags
|
|
187338
|
+
});
|
|
187339
|
+
if (isCacheBustingPass && staleReduceResult.newlyStrippedIds.length > 0) {
|
|
187340
|
+
addStaleReduceStrippedIds(args.db, args.sessionId, staleReduceResult.newlyStrippedIds);
|
|
187341
|
+
}
|
|
187342
|
+
logTransformTiming(args.sessionId, "dropStaleReduceCalls", t8);
|
|
187343
|
+
} catch (error51) {
|
|
187344
|
+
sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error51);
|
|
187345
|
+
}
|
|
187346
|
+
}
|
|
187347
|
+
if (canUseEmptySentinels && args.watermark > 0) {
|
|
187348
|
+
try {
|
|
187349
|
+
const tImg = performance.now();
|
|
187350
|
+
const frozenImageIds = getProcessedImageStrippedIds(args.db, args.sessionId);
|
|
187351
|
+
const imageResult = stripProcessedImages(args.messages, frozenImageIds, {
|
|
187352
|
+
detect: isCacheBustingPass,
|
|
187353
|
+
watermark: args.watermark,
|
|
187354
|
+
messageTagNumbers: args.messageTagNumbers
|
|
187355
|
+
});
|
|
187356
|
+
if (isCacheBustingPass && imageResult.newlyStrippedIds.length > 0) {
|
|
187357
|
+
addProcessedImageStrippedIds(args.db, args.sessionId, imageResult.newlyStrippedIds);
|
|
187358
|
+
}
|
|
187359
|
+
logTransformTiming(args.sessionId, "stripProcessedImages", tImg);
|
|
187360
|
+
} catch (error51) {
|
|
187361
|
+
sessionLog(args.sessionId, "transform failed stripping processed images:", error51);
|
|
185427
187362
|
}
|
|
185428
|
-
logTransformTiming(args.sessionId, "dropStaleReduceCalls", t8);
|
|
185429
|
-
} catch (error51) {
|
|
185430
|
-
sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error51);
|
|
185431
187363
|
}
|
|
185432
|
-
const m0M1Enabled =
|
|
187364
|
+
const m0M1Enabled = m0M1EnabledForFold;
|
|
185433
187365
|
if (m0M1Enabled && args.m0M1) {
|
|
185434
187366
|
const tInjectM0M1 = performance.now();
|
|
185435
187367
|
try {
|
|
@@ -185476,7 +187408,7 @@ async function runPostTransformPhase(args) {
|
|
|
185476
187408
|
const tPlaceholder = performance.now();
|
|
185477
187409
|
const persistedIds = getStrippedPlaceholderIds(args.db, args.sessionId);
|
|
185478
187410
|
if (persistedIds.size > 0) {
|
|
185479
|
-
const { replayed, missingIds } = replaySentinelByMessageIds(args.messages, persistedIds, args.
|
|
187411
|
+
const { replayed, missingIds } = replaySentinelByMessageIds(args.messages, persistedIds, args.resolvedProviderID);
|
|
185480
187412
|
if (replayed > 0) {
|
|
185481
187413
|
sessionLog(args.sessionId, `sentinel replay: neutralized ${replayed} previously-stripped messages`);
|
|
185482
187414
|
}
|
|
@@ -185487,9 +187419,9 @@ async function runPostTransformPhase(args) {
|
|
|
185487
187419
|
}
|
|
185488
187420
|
}
|
|
185489
187421
|
if (isCacheBustingPass) {
|
|
185490
|
-
const droppedResult = stripDroppedPlaceholderMessages(args.messages, args.
|
|
187422
|
+
const droppedResult = stripDroppedPlaceholderMessages(args.messages, args.resolvedProviderID);
|
|
185491
187423
|
const protectedTailStart = Math.max(0, args.messages.length - args.protectedTags * 2);
|
|
185492
|
-
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart, args.
|
|
187424
|
+
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart, args.resolvedProviderID);
|
|
185493
187425
|
const newlyNeutralized = droppedResult.sentineledIds.length + systemInjectedResult.sentineledIds.length;
|
|
185494
187426
|
if (newlyNeutralized > 0) {
|
|
185495
187427
|
const addedIds = [
|
|
@@ -185689,6 +187621,7 @@ function clearMessageTokensCache(sessionId, messageId) {
|
|
|
185689
187621
|
if (cache)
|
|
185690
187622
|
cache.delete(messageId);
|
|
185691
187623
|
}
|
|
187624
|
+
var recordedSessionProjectIdentity = new BoundedSessionMap(MESSAGE_TOKENS_CACHE_MAX);
|
|
185692
187625
|
function findLastAssistantModel2(messages) {
|
|
185693
187626
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
185694
187627
|
const info = messages[i].info;
|
|
@@ -185736,9 +187669,11 @@ function createTransform(deps) {
|
|
|
185736
187669
|
const fullFeatureMode = !reducedMode;
|
|
185737
187670
|
const ctxReduceEnabledEffective = deps.ctxReduceEnabled !== false && resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
|
|
185738
187671
|
let sessionDirectory = deps.directory ?? "";
|
|
187672
|
+
let sessionDirectoryResolvedFromHost = false;
|
|
185739
187673
|
const cachedDirectory = deps.sessionDirectoryBySession?.get(sessionId);
|
|
185740
187674
|
if (cachedDirectory && cachedDirectory.length > 0) {
|
|
185741
187675
|
sessionDirectory = cachedDirectory;
|
|
187676
|
+
sessionDirectoryResolvedFromHost = true;
|
|
185742
187677
|
} else if (deps.client !== undefined) {
|
|
185743
187678
|
try {
|
|
185744
187679
|
const sessionResponse = await deps.client.session.get({ path: { id: sessionId } }).catch(() => null);
|
|
@@ -185746,6 +187681,7 @@ function createTransform(deps) {
|
|
|
185746
187681
|
if (sessionInfo && typeof sessionInfo.directory === "string" && sessionInfo.directory.length > 0) {
|
|
185747
187682
|
sessionDirectory = sessionInfo.directory;
|
|
185748
187683
|
deps.sessionDirectoryBySession?.set(sessionId, sessionDirectory);
|
|
187684
|
+
sessionDirectoryResolvedFromHost = true;
|
|
185749
187685
|
}
|
|
185750
187686
|
} catch {}
|
|
185751
187687
|
}
|
|
@@ -185840,6 +187776,8 @@ function createTransform(deps) {
|
|
|
185840
187776
|
deps.liveModelBySession?.set(sessionId, recovered);
|
|
185841
187777
|
}
|
|
185842
187778
|
}
|
|
187779
|
+
const resolvedProviderID = modelForBudget?.providerID;
|
|
187780
|
+
const canUseEmptySentinels = modelAcceptsEmptyContent(resolvedProviderID);
|
|
185843
187781
|
const resolvedContextLimit = modelForBudget ? resolveTrustedContextLimit(modelForBudget.providerID, modelForBudget.modelID, {
|
|
185844
187782
|
db,
|
|
185845
187783
|
sessionID: sessionId
|
|
@@ -186004,6 +187942,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
186004
187942
|
logTransformTiming(sessionId, "emergencyRecoveryBlock", tFirstPass);
|
|
186005
187943
|
const projectIdentity = deps.memoryConfig?.enabled ? resolveProjectIdentity(compartmentDirectory || process.cwd()) : undefined;
|
|
186006
187944
|
const sessionProjectIdentity = projectIdentity ?? (sessionDirectory ? resolveProjectIdentity(sessionDirectory) : deps.projectPath);
|
|
187945
|
+
if (sessionProjectIdentity && sessionDirectoryResolvedFromHost && recordedSessionProjectIdentity.get(sessionId) !== sessionProjectIdentity) {
|
|
187946
|
+
recordSessionProjectIdentity(db, sessionId, sessionProjectIdentity);
|
|
187947
|
+
recordedSessionProjectIdentity.set(sessionId, sessionProjectIdentity);
|
|
187948
|
+
}
|
|
186007
187949
|
let triggerBoundarySnapshot;
|
|
186008
187950
|
if (fullFeatureMode && historianRunnable && !sessionMeta.compartmentInProgress) {
|
|
186009
187951
|
const tTrigger = performance.now();
|
|
@@ -186098,7 +188040,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
186098
188040
|
}
|
|
186099
188041
|
}
|
|
186100
188042
|
const t3 = performance.now();
|
|
186101
|
-
const strippedStructuralNoise = stripStructuralNoise(messages);
|
|
188043
|
+
const strippedStructuralNoise = canUseEmptySentinels ? stripStructuralNoise(messages) : 0;
|
|
186102
188044
|
logTransformTiming(sessionId, "stripStructuralNoise", t3, `strippedParts=${strippedStructuralNoise}`);
|
|
186103
188045
|
const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
|
|
186104
188046
|
if (persistedReasoningWatermark > 0) {
|
|
@@ -186119,18 +188061,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
186119
188061
|
logTransformTiming(sessionId, "replayCavemanCompression", tCavemanReplay);
|
|
186120
188062
|
}
|
|
186121
188063
|
const t4 = performance.now();
|
|
186122
|
-
const strippedClearedReasoning = stripClearedReasoning(messages);
|
|
188064
|
+
const strippedClearedReasoning = canUseEmptySentinels ? stripClearedReasoning(messages) : 0;
|
|
186123
188065
|
logTransformTiming(sessionId, "stripClearedReasoning", t4, `strippedParts=${strippedClearedReasoning}`);
|
|
186124
188066
|
const tMergeStrip = performance.now();
|
|
186125
|
-
|
|
186126
|
-
if (liveProviderID === undefined) {
|
|
186127
|
-
const recovered = findLastAssistantModelFromOpenCodeDb(sessionId);
|
|
186128
|
-
if (recovered) {
|
|
186129
|
-
liveProviderID = recovered.providerID;
|
|
186130
|
-
deps.liveModelBySession?.set(sessionId, recovered);
|
|
186131
|
-
}
|
|
186132
|
-
}
|
|
186133
|
-
const strippedMergedReasoning = stripReasoningFromMergedAssistants(messages, liveProviderID);
|
|
188067
|
+
const strippedMergedReasoning = stripReasoningFromMergedAssistants(messages, resolvedProviderID);
|
|
186134
188068
|
if (strippedMergedReasoning > 0) {
|
|
186135
188069
|
sessionLog(sessionId, `stripped ${strippedMergedReasoning} reasoning parts from merged assistants (anthropic groupIntoBlocks workaround)`);
|
|
186136
188070
|
}
|
|
@@ -186249,7 +188183,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
186249
188183
|
sessionDirectory,
|
|
186250
188184
|
autoSearch: deps.autoSearch,
|
|
186251
188185
|
cavemanTextCompression: deps.ctxReduceEnabled === false && !reducedMode ? deps.cavemanTextCompression : undefined,
|
|
186252
|
-
|
|
188186
|
+
resolvedProviderID,
|
|
186253
188187
|
historyRefreshSessions: deps.historyRefreshSessions,
|
|
186254
188188
|
m0M1: {
|
|
186255
188189
|
projectPath: projectIdentity,
|
|
@@ -187078,7 +189012,7 @@ function createToolExecuteAfterHook(args) {
|
|
|
187078
189012
|
init_send_session_notification();
|
|
187079
189013
|
|
|
187080
189014
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
187081
|
-
import { createHash as
|
|
189015
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
187082
189016
|
|
|
187083
189017
|
// src/agents/magic-context-prompt.ts
|
|
187084
189018
|
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
@@ -187278,7 +189212,7 @@ function createSystemPromptHashHandler(deps) {
|
|
|
187278
189212
|
`);
|
|
187279
189213
|
if (systemContent.length === 0)
|
|
187280
189214
|
return;
|
|
187281
|
-
const currentHash =
|
|
189215
|
+
const currentHash = createHash12("md5").update(systemContent).digest("hex");
|
|
187282
189216
|
if (!sessionMetaEarly) {
|
|
187283
189217
|
return;
|
|
187284
189218
|
}
|
|
@@ -187539,6 +189473,46 @@ function createMagicContextHook(deps) {
|
|
|
187539
189473
|
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
187540
189474
|
getNotificationParams: (sid) => getLiveNotificationParams(sid, liveModelBySession, variantBySession, agentBySession)
|
|
187541
189475
|
});
|
|
189476
|
+
const executeEmbedHistory = async (sessionId) => {
|
|
189477
|
+
if (deps.config.memory?.enabled === false) {
|
|
189478
|
+
return "Memory is disabled for this project, so there is no semantic embedding to backfill.";
|
|
189479
|
+
}
|
|
189480
|
+
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
189481
|
+
await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
|
|
189482
|
+
const sessionProjectIdentity = resolveProjectIdentity(directory);
|
|
189483
|
+
setRecompStarting({ recompProgressBySession }, sessionId, "Embedding history…", "embed");
|
|
189484
|
+
const outcome = await embedSessionCompartmentChunks(db, sessionProjectIdentity, sessionId, {
|
|
189485
|
+
onProgress: ({ embedded, total }) => {
|
|
189486
|
+
const cur = recompProgressBySession.get(sessionId);
|
|
189487
|
+
if (!cur || cur.phase !== "recomp")
|
|
189488
|
+
return;
|
|
189489
|
+
recompProgressBySession.set(sessionId, {
|
|
189490
|
+
...cur,
|
|
189491
|
+
processedMessages: embedded,
|
|
189492
|
+
totalMessages: total,
|
|
189493
|
+
updatedAt: Date.now()
|
|
189494
|
+
});
|
|
189495
|
+
}
|
|
189496
|
+
});
|
|
189497
|
+
const terminal = (phase, message) => {
|
|
189498
|
+
setRecompTerminal({ recompProgressBySession }, sessionId, phase, message);
|
|
189499
|
+
return message;
|
|
189500
|
+
};
|
|
189501
|
+
switch (outcome.status) {
|
|
189502
|
+
case "nothing":
|
|
189503
|
+
return terminal("done", "All of this session's history is already embedded.");
|
|
189504
|
+
case "disabled":
|
|
189505
|
+
return terminal("skipped", "No embedding provider is configured, so there is nothing to embed.");
|
|
189506
|
+
case "busy":
|
|
189507
|
+
return terminal("skipped", `Embedding is already running for this project — ${outcome.total} compartment${outcome.total === 1 ? "" : "s"} still pending. Try again shortly.`);
|
|
189508
|
+
case "aborted":
|
|
189509
|
+
return terminal("done", `Embedded ${outcome.embedded} of ${outcome.total} compartments before stopping.`);
|
|
189510
|
+
case "stalled":
|
|
189511
|
+
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.`);
|
|
189512
|
+
default:
|
|
189513
|
+
return terminal("done", `Embedded ${outcome.embedded} compartment${outcome.embedded === 1 ? "" : "s"} of history for semantic search.`);
|
|
189514
|
+
}
|
|
189515
|
+
};
|
|
187542
189516
|
const sidekickRunnable = isSidekickRunnable(deps.config);
|
|
187543
189517
|
const sidekickConfig = sidekickRunnable ? deps.config.sidekick : undefined;
|
|
187544
189518
|
const transform2 = createTransform({
|
|
@@ -187693,6 +189667,7 @@ function createMagicContextHook(deps) {
|
|
|
187693
189667
|
},
|
|
187694
189668
|
executeRecomp: historianRunnable ? async (sessionId, options) => runManagedRecomp(buildManagedRecompCtx(sessionId), sessionId, options) : undefined,
|
|
187695
189669
|
runUpgrade: historianRunnable ? async (sessionId) => runManagedUpgrade(buildManagedRecompCtx(sessionId), sessionId) : undefined,
|
|
189670
|
+
executeEmbedHistory,
|
|
187696
189671
|
sendNotification: async (sessionId, text, params) => {
|
|
187697
189672
|
await sendIgnoredMessage(deps.client, sessionId, text, {
|
|
187698
189673
|
...getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
|
|
@@ -188830,6 +190805,7 @@ init_memory();
|
|
|
188830
190805
|
init_embedding();
|
|
188831
190806
|
init_embedding_cache();
|
|
188832
190807
|
init_normalize_hash();
|
|
190808
|
+
init_workspaces();
|
|
188833
190809
|
init_logger();
|
|
188834
190810
|
await init_storage();
|
|
188835
190811
|
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
@@ -188989,6 +190965,23 @@ function createCtxMemoryTool(deps) {
|
|
|
188989
190965
|
}
|
|
188990
190966
|
const projectPath = deps.resolveProjectPath(toolContext.directory);
|
|
188991
190967
|
await deps.ensureProjectRegistered?.(toolContext.directory, deps.db);
|
|
190968
|
+
const workspaceIdentitySet = resolveWorkspaceIdentitySet(deps.db, projectPath);
|
|
190969
|
+
const expandedWorkspace = expandWorkspaceIdentitySetWithAliases(deps.db, workspaceIdentitySet.identities);
|
|
190970
|
+
const workspaceVisibleIdentities = workspaceIdentitySet.identities.length > 1 ? expandedWorkspace.expandedIdentities : workspaceIdentitySet.identities;
|
|
190971
|
+
const targetIdentityForStoredPath = (rawProjectPath) => workspaceIdentitySet.identities.length > 1 ? resolveStoredPathWorkspaceIdentity(rawProjectPath, workspaceIdentitySet.identities, expandedWorkspace.canonicalIdentityByStoredPath) ?? projectIdentityForStoredPath(rawProjectPath) : projectIdentityForStoredPath(rawProjectPath);
|
|
190972
|
+
const toolShareCategories = workspaceIdentitySet.identities.length > 1 ? resolveWorkspaceShareCategories(deps.db, projectPath) : null;
|
|
190973
|
+
const memoryVisibleToTool = (memory) => {
|
|
190974
|
+
if (workspaceIdentitySet.identities.length <= 1) {
|
|
190975
|
+
return memoryBelongsToProject(memory, projectPath);
|
|
190976
|
+
}
|
|
190977
|
+
if (!storedPathBelongsToWorkspace(memory.projectPath, workspaceIdentitySet.identities, workspaceVisibleIdentities, expandedWorkspace.canonicalIdentityByStoredPath)) {
|
|
190978
|
+
return false;
|
|
190979
|
+
}
|
|
190980
|
+
const isOwn = targetIdentityForStoredPath(memory.projectPath) === projectPath;
|
|
190981
|
+
if (isOwn)
|
|
190982
|
+
return true;
|
|
190983
|
+
return toolShareCategories === null || toolShareCategories.includes(memory.category);
|
|
190984
|
+
};
|
|
188992
190985
|
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
188993
190986
|
if (embeddingSnapshot ? !embeddingSnapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
188994
190987
|
return getDisabledMessage();
|
|
@@ -189045,18 +191038,18 @@ function createCtxMemoryTool(deps) {
|
|
|
189045
191038
|
}
|
|
189046
191039
|
const rawProjectPath = projectPathForMemoryId(deps.db, updateId);
|
|
189047
191040
|
const memory = getMemoryById(deps.db, updateId);
|
|
189048
|
-
if (!memory || !rawProjectPath || !
|
|
191041
|
+
if (!memory || !rawProjectPath || !memoryVisibleToTool(memory)) {
|
|
189049
191042
|
return `Error: Memory with ID ${updateId} was not found.`;
|
|
189050
191043
|
}
|
|
189051
191044
|
if (toolContext.agent !== DREAMER_AGENT && !isPrimaryMutableMemory(memory)) {
|
|
189052
191045
|
return inactiveMemoryError(updateId, "updating");
|
|
189053
191046
|
}
|
|
189054
191047
|
const normalizedHash = computeNormalizedHash(content);
|
|
189055
|
-
const duplicate = getMemoryByHash(deps.db,
|
|
191048
|
+
const duplicate = getMemoryByHash(deps.db, targetIdentityForStoredPath(rawProjectPath), memory.category, normalizedHash);
|
|
189056
191049
|
if (duplicate && duplicate.id !== memory.id) {
|
|
189057
191050
|
return `Error: Memory content already exists as ID ${duplicate.id}; merge or archive duplicates instead.`;
|
|
189058
191051
|
}
|
|
189059
|
-
const projectIdentity =
|
|
191052
|
+
const projectIdentity = targetIdentityForStoredPath(rawProjectPath);
|
|
189060
191053
|
deps.db.transaction(() => {
|
|
189061
191054
|
updateMemoryContentInCurrentTransaction(deps.db, memory, content, normalizedHash);
|
|
189062
191055
|
queueMemoryMutation(deps.db, {
|
|
@@ -189070,7 +191063,7 @@ function createCtxMemoryTool(deps) {
|
|
|
189070
191063
|
queueMemoryEmbedding({
|
|
189071
191064
|
deps,
|
|
189072
191065
|
sessionId: toolContext.sessionID,
|
|
189073
|
-
projectPath,
|
|
191066
|
+
projectPath: projectIdentity,
|
|
189074
191067
|
memoryId: memory.id,
|
|
189075
191068
|
content
|
|
189076
191069
|
});
|
|
@@ -189093,7 +191086,7 @@ function createCtxMemoryTool(deps) {
|
|
|
189093
191086
|
return "Error: One or more source memories were not found.";
|
|
189094
191087
|
}
|
|
189095
191088
|
if (toolContext.agent !== DREAMER_AGENT) {
|
|
189096
|
-
const foreign = sourceMemories.find((memory) => !
|
|
191089
|
+
const foreign = sourceMemories.find((memory) => !memoryVisibleToTool(memory));
|
|
189097
191090
|
if (foreign) {
|
|
189098
191091
|
return `Error: Memory with ID ${foreign.id} was not found.`;
|
|
189099
191092
|
}
|
|
@@ -189177,15 +191170,16 @@ function createCtxMemoryTool(deps) {
|
|
|
189177
191170
|
return `Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`;
|
|
189178
191171
|
}
|
|
189179
191172
|
if (args.action === "archive") {
|
|
189180
|
-
const
|
|
189181
|
-
if (!
|
|
191173
|
+
const rawArchiveIds = args.ids;
|
|
191174
|
+
if (!rawArchiveIds || rawArchiveIds.length === 0 || !rawArchiveIds.every(Number.isInteger)) {
|
|
189182
191175
|
return "Error: 'ids' must contain at least one integer memory ID when action is 'archive'.";
|
|
189183
191176
|
}
|
|
191177
|
+
const archiveIds = [...new Set(rawArchiveIds)];
|
|
189184
191178
|
const targets = [];
|
|
189185
191179
|
for (const memoryId of archiveIds) {
|
|
189186
191180
|
const rawProjectPath = projectPathForMemoryId(deps.db, memoryId);
|
|
189187
191181
|
const memory = getMemoryById(deps.db, memoryId);
|
|
189188
|
-
if (!memory || !rawProjectPath || !
|
|
191182
|
+
if (!memory || !rawProjectPath || !memoryVisibleToTool(memory)) {
|
|
189189
191183
|
return `Error: Memory with ID ${memoryId} was not found.`;
|
|
189190
191184
|
}
|
|
189191
191185
|
if (toolContext.agent !== DREAMER_AGENT && !isPrimaryMutableMemory(memory)) {
|
|
@@ -189193,7 +191187,7 @@ function createCtxMemoryTool(deps) {
|
|
|
189193
191187
|
}
|
|
189194
191188
|
targets.push({
|
|
189195
191189
|
memoryId,
|
|
189196
|
-
projectIdentity:
|
|
191190
|
+
projectIdentity: targetIdentityForStoredPath(rawProjectPath)
|
|
189197
191191
|
});
|
|
189198
191192
|
}
|
|
189199
191193
|
deps.db.transaction(() => {
|
|
@@ -189667,8 +191661,9 @@ function formatAge2(committedAtMs) {
|
|
|
189667
191661
|
}
|
|
189668
191662
|
function formatResult(result, index) {
|
|
189669
191663
|
if (result.source === "memory") {
|
|
191664
|
+
const source = result.sourceName ? ` source=${result.sourceName}` : "";
|
|
189670
191665
|
return [
|
|
189671
|
-
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category} match=${result.matchType}`,
|
|
191666
|
+
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category}${source} match=${result.matchType}`,
|
|
189672
191667
|
result.content
|
|
189673
191668
|
].join(`
|
|
189674
191669
|
`);
|
|
@@ -189678,6 +191673,13 @@ function formatResult(result, index) {
|
|
|
189678
191673
|
`[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge2(result.committedAtMs)} match=${result.matchType}`,
|
|
189679
191674
|
result.content
|
|
189680
191675
|
].join(`
|
|
191676
|
+
`);
|
|
191677
|
+
}
|
|
191678
|
+
if (result.source === "compartment") {
|
|
191679
|
+
return [
|
|
191680
|
+
`[${index}] [message] score=${result.score.toFixed(2)} compartment_id=${result.compartmentId} range=${result.startOrdinal}-${result.endOrdinal} match=${result.matchType} title=${result.title}`,
|
|
191681
|
+
result.snippet ? `Snippet: ${result.snippet}` : result.content
|
|
191682
|
+
].join(`
|
|
189681
191683
|
`);
|
|
189682
191684
|
}
|
|
189683
191685
|
const expandStart = Math.max(1, result.messageOrdinal - 3);
|
|
@@ -189693,7 +191695,7 @@ function formatSearchResults(query, results) {
|
|
|
189693
191695
|
return `No results found for "${query}" across memories, git commits, or message history.`;
|
|
189694
191696
|
}
|
|
189695
191697
|
const bodyParts = results.map((result, index) => formatResult(result, index + 1));
|
|
189696
|
-
if (results.some((result) => result.source === "message")) {
|
|
191698
|
+
if (results.some((result) => result.source === "message" || result.source === "compartment")) {
|
|
189697
191699
|
bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
|
|
189698
191700
|
}
|
|
189699
191701
|
const body = bodyParts.join(`
|
|
@@ -189851,11 +191853,11 @@ import { createServer } from "node:http";
|
|
|
189851
191853
|
import { dirname as dirname8 } from "node:path";
|
|
189852
191854
|
|
|
189853
191855
|
// src/shared/rpc-utils.ts
|
|
189854
|
-
import { createHash as
|
|
191856
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
189855
191857
|
import { join as join24 } from "node:path";
|
|
189856
191858
|
function projectHash(directory) {
|
|
189857
191859
|
const normalized = directory.replace(/\/+$/, "");
|
|
189858
|
-
return
|
|
191860
|
+
return createHash13("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
189859
191861
|
}
|
|
189860
191862
|
function rpcPortDir(storageDir, directory) {
|
|
189861
191863
|
return join24(storageDir, "rpc", projectHash(directory));
|