@wolfx/opencode-magic-context 0.23.1 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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 +80 -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 +17 -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-tags.d.ts +10 -1
- package/dist/features/magic-context/storage-tags.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/apply-operations.d.ts +23 -0
- package/dist/hooks/magic-context/apply-operations.d.ts.map +1 -1
- package/dist/hooks/magic-context/auto-search-hint.d.ts.map +1 -1
- package/dist/hooks/magic-context/command-handler.d.ts +5 -0
- package/dist/hooks/magic-context/command-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-incremental.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-partial-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-recomp.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts +11 -1
- package/dist/hooks/magic-context/compartment-runner-types.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts +7 -2
- package/dist/hooks/magic-context/ctx-reduce-nudge.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.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 +2411 -365
- 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/shared/tui-preferences.d.ts +32 -0
- package/dist/shared/tui-preferences.d.ts.map +1 -0
- 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/shared/tui-preferences.test.ts +210 -0
- package/src/shared/tui-preferences.ts +303 -0
- package/src/tui/index.tsx +5 -3
- package/src/tui/slots/sidebar-content.tsx +119 -14
package/dist/index.js
CHANGED
|
@@ -14887,7 +14887,8 @@ var init_magic_context = __esm(() => {
|
|
|
14887
14887
|
endpoint: exports_external.string().optional().describe("API endpoint URL. Required when provider is openai-compatible."),
|
|
14888
14888
|
api_key: exports_external.string().optional().describe("API key for remote embedding provider (optional)"),
|
|
14889
14889
|
input_type: exports_external.string().optional().describe("Optional input_type sent in the embedding request body. Required by some openai-compatible providers (e.g. NVIDIA NIM expects 'query' or 'passage'). Omitted from the request when unset."),
|
|
14890
|
-
truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset.")
|
|
14890
|
+
truncate: exports_external.string().optional().describe("Optional truncate mode sent in the embedding request body (e.g. NVIDIA NIM accepts 'NONE' | 'START' | 'END'). Omitted from the request when unset."),
|
|
14891
|
+
max_input_tokens: exports_external.number().int().positive().optional().describe("Optional maximum input tokens for chunk embeddings. Defaults conservatively to 512 when omitted.")
|
|
14891
14892
|
}).superRefine((data, ctx) => {
|
|
14892
14893
|
if (data.provider === "openai-compatible" && !data.endpoint?.trim()) {
|
|
14893
14894
|
ctx.addIssue({
|
|
@@ -14908,7 +14909,8 @@ var init_magic_context = __esm(() => {
|
|
|
14908
14909
|
if (data.provider === "local") {
|
|
14909
14910
|
return {
|
|
14910
14911
|
provider: "local",
|
|
14911
|
-
model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
14912
|
+
model: data.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
14913
|
+
...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
|
|
14912
14914
|
};
|
|
14913
14915
|
}
|
|
14914
14916
|
if (data.provider === "openai-compatible") {
|
|
@@ -14921,7 +14923,8 @@ var init_magic_context = __esm(() => {
|
|
|
14921
14923
|
endpoint: data.endpoint?.trim() ?? "",
|
|
14922
14924
|
...apiKey ? { api_key: apiKey } : {},
|
|
14923
14925
|
...inputType ? { input_type: inputType } : {},
|
|
14924
|
-
...truncate ? { truncate } : {}
|
|
14926
|
+
...truncate ? { truncate } : {},
|
|
14927
|
+
...data.max_input_tokens ? { max_input_tokens: data.max_input_tokens } : {}
|
|
14925
14928
|
};
|
|
14926
14929
|
}
|
|
14927
14930
|
return { provider: "off" };
|
|
@@ -15844,7 +15847,7 @@ function isSessionMetaRow(row) {
|
|
|
15844
15847
|
if (row === null || typeof row !== "object")
|
|
15845
15848
|
return false;
|
|
15846
15849
|
const r = row;
|
|
15847
|
-
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
15850
|
+
return typeof r.session_id === "string" && typeof r.last_response_time === "number" && isStringOrNull(r.cache_ttl) && typeof r.counter === "number" && typeof r.last_nudge_tokens === "number" && isStringOrNull(r.last_nudge_band) && isStringOrNull(r.last_transform_error) && typeof r.is_subagent === "number" && typeof r.last_context_percentage === "number" && typeof r.last_input_tokens === "number" && isNumberOrNull(r.observed_safe_input_tokens) && isNumberOrNull(r.cache_alert_sent) && isNumberOrNull(r.times_execute_threshold_reached) && isNumberOrNull(r.compartment_in_progress) && (r.system_prompt_hash === null || typeof r.system_prompt_hash === "string" || typeof r.system_prompt_hash === "number") && isNumberOrNull(r.system_prompt_tokens) && isNumberOrNull(r.conversation_tokens) && isNumberOrNull(r.tool_call_tokens) && isNumberOrNull(r.cleared_reasoning_through_tag) && isStringOrNull(r.last_todo_state) && isBlobOrNull(r.cached_m0_bytes) && isBlobOrNull(r.cached_m1_bytes) && isNumberOrNull(r.cached_m0_project_memory_epoch) && isStringOrNull(r.cached_m0_workspace_fingerprint) && isNumberOrNull(r.cached_m0_project_user_profile_version) && isNumberOrNull(r.cached_m0_max_compartment_seq) && isNumberOrNull(r.cached_m0_max_memory_id) && isNumberOrNull(r.cached_m0_max_mutation_id) && isNumberOrNull(r.cached_m0_max_memory_mutation_id) && isStringOrNull(r.cached_m0_project_docs_hash) && isNumberOrNull(r.cached_m0_materialized_at) && isNumberOrNull(r.cached_m0_session_facts_version) && isStringOrNull(r.cached_m0_upgrade_state) && isStringOrNull(r.cached_m0_system_hash) && isStringOrNull(r.cached_m0_tool_set_hash) && isStringOrNull(r.cached_m0_model_key) && isStringOrNull(r.last_observed_model_key) && isNumberOrNull(r.last_usage_context_limit) && isNumberOrNull(r.prior_boundary_ordinal) && isNumberOrNull(r.protected_tail_policy_version) && isNumberOrNull(r.protected_tail_drain_window_started_at) && isNumberOrNull(r.protected_tail_drain_tokens) && isNumberOrNull(r.recovery_no_eligible_head_count) && isNumberOrNull(r.force_emergency_bypass_window_start) && isNumberOrNull(r.force_emergency_bypass_used) && isNumberOrNull(r.upgrade_reminded_at) && isNumberOrNull(r.pi_stable_id_scheme);
|
|
15848
15851
|
}
|
|
15849
15852
|
function getDefaultSessionMeta(sessionId) {
|
|
15850
15853
|
return {
|
|
@@ -15871,6 +15874,7 @@ function getDefaultSessionMeta(sessionId) {
|
|
|
15871
15874
|
cachedM0Bytes: null,
|
|
15872
15875
|
cachedM1Bytes: null,
|
|
15873
15876
|
cachedM0ProjectMemoryEpoch: null,
|
|
15877
|
+
cachedM0WorkspaceFingerprint: null,
|
|
15874
15878
|
cachedM0ProjectUserProfileVersion: null,
|
|
15875
15879
|
cachedM0MaxCompartmentSeq: null,
|
|
15876
15880
|
cachedM0MaxMemoryId: null,
|
|
@@ -15933,6 +15937,7 @@ function toSessionMeta(row) {
|
|
|
15933
15937
|
cachedM0Bytes: toBufferOrNull(row.cached_m0_bytes),
|
|
15934
15938
|
cachedM1Bytes: toBufferOrNull(row.cached_m1_bytes),
|
|
15935
15939
|
cachedM0ProjectMemoryEpoch: numOrNull(row.cached_m0_project_memory_epoch),
|
|
15940
|
+
cachedM0WorkspaceFingerprint: stringOrNull(row.cached_m0_workspace_fingerprint),
|
|
15936
15941
|
cachedM0ProjectUserProfileVersion: numOrNull(row.cached_m0_project_user_profile_version),
|
|
15937
15942
|
cachedM0MaxCompartmentSeq: numOrNull(row.cached_m0_max_compartment_seq),
|
|
15938
15943
|
cachedM0MaxMemoryId: numOrNull(row.cached_m0_max_memory_id),
|
|
@@ -15963,6 +15968,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
15963
15968
|
db.prepare(`UPDATE session_meta SET
|
|
15964
15969
|
cached_m0_bytes = ?,
|
|
15965
15970
|
cached_m0_project_memory_epoch = ?,
|
|
15971
|
+
cached_m0_workspace_fingerprint = ?,
|
|
15966
15972
|
cached_m0_project_user_profile_version = ?,
|
|
15967
15973
|
cached_m0_max_compartment_seq = ?,
|
|
15968
15974
|
cached_m0_max_memory_id = ?,
|
|
@@ -15975,7 +15981,7 @@ function persistCachedM0(db, sessionId, payload) {
|
|
|
15975
15981
|
cached_m0_upgrade_state = ?,
|
|
15976
15982
|
cached_m0_system_hash = ?,
|
|
15977
15983
|
cached_m0_model_key = ?
|
|
15978
|
-
WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.modelKey ?? "", sessionId);
|
|
15984
|
+
WHERE session_id = ?`).run(Buffer2.from(payload.m0Bytes), payload.projectMemoryEpoch, payload.workspaceFingerprint ?? null, payload.projectUserProfileVersion, payload.maxCompartmentSeq, payload.maxMemoryId, payload.maxMutationId, payload.maxMemoryMutationId ?? null, payload.m1Bytes ? Buffer2.from(payload.m1Bytes) : null, payload.projectDocsHash, payload.materializedAt, payload.sessionFactsVersion, payload.upgradeState, payload.systemHash ?? "", payload.modelKey ?? "", sessionId);
|
|
15979
15985
|
}
|
|
15980
15986
|
function clearCachedM0M1(db, sessionId) {
|
|
15981
15987
|
ensureSessionMetaRow(db, sessionId);
|
|
@@ -15984,6 +15990,7 @@ function clearCachedM0M1(db, sessionId) {
|
|
|
15984
15990
|
["cached_m0_bytes", null],
|
|
15985
15991
|
["cached_m1_bytes", null],
|
|
15986
15992
|
["cached_m0_project_memory_epoch", null],
|
|
15993
|
+
["cached_m0_workspace_fingerprint", null],
|
|
15987
15994
|
["cached_m0_project_user_profile_version", null],
|
|
15988
15995
|
["cached_m0_max_compartment_seq", null],
|
|
15989
15996
|
["cached_m0_max_memory_id", null],
|
|
@@ -16039,6 +16046,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16039
16046
|
"cached_m0_bytes",
|
|
16040
16047
|
"cached_m1_bytes",
|
|
16041
16048
|
"cached_m0_project_memory_epoch",
|
|
16049
|
+
"cached_m0_workspace_fingerprint",
|
|
16042
16050
|
"cached_m0_project_user_profile_version",
|
|
16043
16051
|
"cached_m0_max_compartment_seq",
|
|
16044
16052
|
"cached_m0_max_memory_id",
|
|
@@ -16086,6 +16094,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16086
16094
|
cachedM0Bytes: "cached_m0_bytes",
|
|
16087
16095
|
cachedM1Bytes: "cached_m1_bytes",
|
|
16088
16096
|
cachedM0ProjectMemoryEpoch: "cached_m0_project_memory_epoch",
|
|
16097
|
+
cachedM0WorkspaceFingerprint: "cached_m0_workspace_fingerprint",
|
|
16089
16098
|
cachedM0ProjectUserProfileVersion: "cached_m0_project_user_profile_version",
|
|
16090
16099
|
cachedM0MaxCompartmentSeq: "cached_m0_max_compartment_seq",
|
|
16091
16100
|
cachedM0MaxMemoryId: "cached_m0_max_memory_id",
|
|
@@ -16115,6 +16124,7 @@ var init_storage_meta_shared = __esm(() => {
|
|
|
16115
16124
|
"cachedM0Bytes",
|
|
16116
16125
|
"cachedM1Bytes",
|
|
16117
16126
|
"cachedM0ProjectMemoryEpoch",
|
|
16127
|
+
"cachedM0WorkspaceFingerprint",
|
|
16118
16128
|
"cachedM0ProjectUserProfileVersion",
|
|
16119
16129
|
"cachedM0MaxCompartmentSeq",
|
|
16120
16130
|
"cachedM0MaxMemoryId",
|
|
@@ -150826,6 +150836,35 @@ function initializeDatabase(db) {
|
|
|
150826
150836
|
);
|
|
150827
150837
|
CREATE INDEX IF NOT EXISTS idx_compartments_session ON compartments(session_id);
|
|
150828
150838
|
|
|
150839
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
150840
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
150841
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
150842
|
+
session_id TEXT NOT NULL,
|
|
150843
|
+
project_path TEXT NOT NULL,
|
|
150844
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
150845
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
150846
|
+
start_ordinal INTEGER NOT NULL,
|
|
150847
|
+
end_ordinal INTEGER NOT NULL,
|
|
150848
|
+
chunk_hash TEXT NOT NULL,
|
|
150849
|
+
model_id TEXT NOT NULL,
|
|
150850
|
+
dims INTEGER NOT NULL,
|
|
150851
|
+
vector BLOB NOT NULL,
|
|
150852
|
+
created_at INTEGER NOT NULL,
|
|
150853
|
+
UNIQUE(compartment_id, window_index)
|
|
150854
|
+
);
|
|
150855
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session ON compartment_chunk_embeddings(session_id);
|
|
150856
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model ON compartment_chunk_embeddings(project_path, model_id);
|
|
150857
|
+
|
|
150858
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
150859
|
+
session_id TEXT NOT NULL,
|
|
150860
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
150861
|
+
project_path TEXT NOT NULL,
|
|
150862
|
+
updated_at INTEGER NOT NULL,
|
|
150863
|
+
PRIMARY KEY(session_id, harness)
|
|
150864
|
+
);
|
|
150865
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
150866
|
+
ON session_projects(project_path);
|
|
150867
|
+
|
|
150829
150868
|
CREATE TABLE IF NOT EXISTS compartment_events (
|
|
150830
150869
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
150831
150870
|
session_id TEXT NOT NULL,
|
|
@@ -151011,6 +151050,25 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151011
151050
|
rekeyed_at INTEGER NOT NULL
|
|
151012
151051
|
);
|
|
151013
151052
|
|
|
151053
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
151054
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151055
|
+
name TEXT NOT NULL UNIQUE,
|
|
151056
|
+
created_at INTEGER NOT NULL,
|
|
151057
|
+
updated_at INTEGER NOT NULL,
|
|
151058
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
151059
|
+
);
|
|
151060
|
+
|
|
151061
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
151062
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
151063
|
+
project_path TEXT NOT NULL,
|
|
151064
|
+
display_name TEXT NOT NULL,
|
|
151065
|
+
display_path TEXT NOT NULL,
|
|
151066
|
+
added_at INTEGER NOT NULL,
|
|
151067
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
151068
|
+
);
|
|
151069
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
151070
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
151071
|
+
|
|
151014
151072
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
151015
151073
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151016
151074
|
table_name TEXT NOT NULL,
|
|
@@ -151122,6 +151180,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151122
151180
|
deferred_execute_state TEXT,
|
|
151123
151181
|
cached_m0_bytes BLOB,
|
|
151124
151182
|
cached_m0_project_memory_epoch INTEGER,
|
|
151183
|
+
cached_m0_workspace_fingerprint TEXT,
|
|
151125
151184
|
cached_m0_project_user_profile_version INTEGER,
|
|
151126
151185
|
cached_m0_max_compartment_seq INTEGER,
|
|
151127
151186
|
cached_m0_max_memory_id INTEGER,
|
|
@@ -151280,6 +151339,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151280
151339
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
151281
151340
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
151282
151341
|
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
151342
|
+
ensureColumn(db, "session_meta", "processed_image_stripped_ids", "TEXT DEFAULT ''");
|
|
151283
151343
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
151284
151344
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
151285
151345
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -151333,6 +151393,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151333
151393
|
ensureColumn(db, "memories", "importance", "INTEGER");
|
|
151334
151394
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
151335
151395
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
151396
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
151336
151397
|
ensureColumn(db, "session_meta", "cached_m0_project_user_profile_version", "INTEGER");
|
|
151337
151398
|
ensureColumn(db, "session_meta", "cached_m0_max_compartment_seq", "INTEGER");
|
|
151338
151399
|
ensureColumn(db, "session_meta", "cached_m0_max_memory_id", "INTEGER");
|
|
@@ -151364,6 +151425,15 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151364
151425
|
project_user_profile_version INTEGER NOT NULL DEFAULT 0,
|
|
151365
151426
|
updated_at INTEGER NOT NULL DEFAULT 0
|
|
151366
151427
|
);
|
|
151428
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
151429
|
+
session_id TEXT NOT NULL,
|
|
151430
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
151431
|
+
project_path TEXT NOT NULL,
|
|
151432
|
+
updated_at INTEGER NOT NULL,
|
|
151433
|
+
PRIMARY KEY(session_id, harness)
|
|
151434
|
+
);
|
|
151435
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
151436
|
+
ON session_projects(project_path);
|
|
151367
151437
|
CREATE TABLE IF NOT EXISTS m0_mutation_log (
|
|
151368
151438
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151369
151439
|
session_id TEXT NOT NULL,
|
|
@@ -151391,6 +151461,23 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151391
151461
|
new_project_path TEXT NOT NULL,
|
|
151392
151462
|
rekeyed_at INTEGER NOT NULL
|
|
151393
151463
|
);
|
|
151464
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
151465
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151466
|
+
name TEXT NOT NULL UNIQUE,
|
|
151467
|
+
created_at INTEGER NOT NULL,
|
|
151468
|
+
updated_at INTEGER NOT NULL,
|
|
151469
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
151470
|
+
);
|
|
151471
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
151472
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
151473
|
+
project_path TEXT NOT NULL,
|
|
151474
|
+
display_name TEXT NOT NULL,
|
|
151475
|
+
display_path TEXT NOT NULL,
|
|
151476
|
+
added_at INTEGER NOT NULL,
|
|
151477
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
151478
|
+
);
|
|
151479
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique ON workspace_members(project_path);
|
|
151480
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name ON workspace_members(workspace_id, display_name);
|
|
151394
151481
|
CREATE TABLE IF NOT EXISTS v22_backfill_failures (
|
|
151395
151482
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
151396
151483
|
table_name TEXT NOT NULL,
|
|
@@ -151412,6 +151499,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
151412
151499
|
ensureColumn(db, "recomp_compartments", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151413
151500
|
ensureColumn(db, "recomp_facts", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151414
151501
|
ensureColumn(db, "message_history_index", "harness", "TEXT NOT NULL DEFAULT 'opencode'");
|
|
151502
|
+
ensureColumn(db, "workspaces", "share_categories", `TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
151415
151503
|
}
|
|
151416
151504
|
function healAllNullColumns(db) {
|
|
151417
151505
|
healNullTextColumns(db);
|
|
@@ -151449,6 +151537,7 @@ function healNullTextColumns(db) {
|
|
|
151449
151537
|
["system_prompt_hash", ""],
|
|
151450
151538
|
["stripped_placeholder_ids", ""],
|
|
151451
151539
|
["stale_reduce_stripped_ids", ""],
|
|
151540
|
+
["processed_image_stripped_ids", ""],
|
|
151452
151541
|
["memory_block_cache", ""],
|
|
151453
151542
|
["memory_block_ids", ""],
|
|
151454
151543
|
["compaction_marker_state", ""],
|
|
@@ -151493,7 +151582,7 @@ function healNullIntegerColumns(db) {
|
|
|
151493
151582
|
}
|
|
151494
151583
|
}
|
|
151495
151584
|
function ensureColumn(db, table, column, definition) {
|
|
151496
|
-
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_'(),[\]\s]+$/i.test(definition)) {
|
|
151585
|
+
if (!/^[a-z][a-z0-9_]*$/.test(table) || !/^[a-z][a-z0-9_]*$/.test(column) || !/^[A-Z0-9_"'(),[\]\s]+$/i.test(definition)) {
|
|
151497
151586
|
throw new Error(`Unsafe schema identifier: ${table}.${column} ${definition}`);
|
|
151498
151587
|
}
|
|
151499
151588
|
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
@@ -151579,7 +151668,7 @@ function getDatabasePersistenceError(db) {
|
|
|
151579
151668
|
return null;
|
|
151580
151669
|
return persistenceErrorByDatabase.get(db) ?? null;
|
|
151581
151670
|
}
|
|
151582
|
-
var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION =
|
|
151671
|
+
var databases, persistenceByDatabase, persistenceErrorByDatabase, lastSchemaFenceRejection = null, LATEST_SUPPORTED_VERSION = 36, sqlitePragmaConfig, CHANNEL2_CLAIM_TTL_MS = 120000;
|
|
151583
151672
|
var init_storage_db = __esm(async () => {
|
|
151584
151673
|
init_data_path();
|
|
151585
151674
|
init_logger();
|
|
@@ -151599,10 +151688,302 @@ var init_storage_db = __esm(async () => {
|
|
|
151599
151688
|
};
|
|
151600
151689
|
});
|
|
151601
151690
|
|
|
151691
|
+
// src/features/magic-context/memory/constants.ts
|
|
151692
|
+
var V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
151693
|
+
var init_constants = __esm(() => {
|
|
151694
|
+
V2_MEMORY_CATEGORIES = [
|
|
151695
|
+
"PROJECT_RULES",
|
|
151696
|
+
"ARCHITECTURE",
|
|
151697
|
+
"CONSTRAINTS",
|
|
151698
|
+
"CONFIG_VALUES",
|
|
151699
|
+
"NAMING"
|
|
151700
|
+
];
|
|
151701
|
+
PROMOTABLE_CATEGORIES = [
|
|
151702
|
+
"PROJECT_RULES",
|
|
151703
|
+
"ARCHITECTURE",
|
|
151704
|
+
"CONSTRAINTS",
|
|
151705
|
+
"CONFIG_VALUES",
|
|
151706
|
+
"NAMING",
|
|
151707
|
+
"ARCHITECTURE_DECISIONS",
|
|
151708
|
+
"CONFIG_DEFAULTS",
|
|
151709
|
+
"USER_PREFERENCES",
|
|
151710
|
+
"USER_DIRECTIVES",
|
|
151711
|
+
"ENVIRONMENT",
|
|
151712
|
+
"WORKFLOW_RULES",
|
|
151713
|
+
"KNOWN_ISSUES"
|
|
151714
|
+
];
|
|
151715
|
+
CATEGORY_PRIORITY = [
|
|
151716
|
+
"PROJECT_RULES",
|
|
151717
|
+
"ARCHITECTURE",
|
|
151718
|
+
"CONSTRAINTS",
|
|
151719
|
+
"CONFIG_VALUES",
|
|
151720
|
+
"NAMING",
|
|
151721
|
+
"USER_DIRECTIVES",
|
|
151722
|
+
"USER_PREFERENCES",
|
|
151723
|
+
"CONFIG_DEFAULTS",
|
|
151724
|
+
"ARCHITECTURE_DECISIONS",
|
|
151725
|
+
"ENVIRONMENT",
|
|
151726
|
+
"WORKFLOW_RULES",
|
|
151727
|
+
"KNOWN_ISSUES"
|
|
151728
|
+
];
|
|
151729
|
+
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
151730
|
+
acc[category] = index;
|
|
151731
|
+
return acc;
|
|
151732
|
+
}, {});
|
|
151733
|
+
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
151734
|
+
CATEGORY_DEFAULT_TTL = {
|
|
151735
|
+
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
151736
|
+
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
151737
|
+
};
|
|
151738
|
+
});
|
|
151739
|
+
|
|
151740
|
+
// src/features/magic-context/project-identity.ts
|
|
151741
|
+
var init_project_identity2 = __esm(() => {
|
|
151742
|
+
init_project_identity();
|
|
151743
|
+
});
|
|
151744
|
+
|
|
151745
|
+
// src/features/magic-context/workspaces.ts
|
|
151746
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
151747
|
+
function tableExists(db, tableName) {
|
|
151748
|
+
const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name = ? LIMIT 1").get(tableName);
|
|
151749
|
+
return Boolean(row);
|
|
151750
|
+
}
|
|
151751
|
+
function columnExists(db, tableName, columnName) {
|
|
151752
|
+
const rows = db.prepare(`PRAGMA table_info(${tableName})`).all();
|
|
151753
|
+
return rows.some((row) => row.name === columnName);
|
|
151754
|
+
}
|
|
151755
|
+
function uniqueSorted(values) {
|
|
151756
|
+
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
151757
|
+
}
|
|
151758
|
+
function placeholders(values) {
|
|
151759
|
+
return values.map(() => "?").join(", ");
|
|
151760
|
+
}
|
|
151761
|
+
function normalizeShareCategories(raw) {
|
|
151762
|
+
if (raw === null || raw === undefined)
|
|
151763
|
+
return null;
|
|
151764
|
+
if (typeof raw !== "string")
|
|
151765
|
+
return null;
|
|
151766
|
+
let parsed;
|
|
151767
|
+
try {
|
|
151768
|
+
parsed = JSON.parse(raw);
|
|
151769
|
+
} catch {
|
|
151770
|
+
return null;
|
|
151771
|
+
}
|
|
151772
|
+
if (!Array.isArray(parsed))
|
|
151773
|
+
return null;
|
|
151774
|
+
const categories = [];
|
|
151775
|
+
for (const value of parsed) {
|
|
151776
|
+
if (typeof value !== "string" || !VALID_SHARE_CATEGORIES.has(value)) {
|
|
151777
|
+
return null;
|
|
151778
|
+
}
|
|
151779
|
+
if (!categories.includes(value))
|
|
151780
|
+
categories.push(value);
|
|
151781
|
+
}
|
|
151782
|
+
return categories.sort((left, right) => left.localeCompare(right));
|
|
151783
|
+
}
|
|
151784
|
+
function selectWorkspaceShareCategories(db, identities) {
|
|
151785
|
+
const candidates = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
151786
|
+
if (candidates.length === 0 || !tableExists(db, "workspace_members") || !tableExists(db, "workspaces") || !columnExists(db, "workspaces", "share_categories")) {
|
|
151787
|
+
return null;
|
|
151788
|
+
}
|
|
151789
|
+
const row = db.prepare(`SELECT workspace.share_categories AS shareCategories
|
|
151790
|
+
FROM workspace_members AS member
|
|
151791
|
+
JOIN workspaces AS workspace ON workspace.id = member.workspace_id
|
|
151792
|
+
WHERE member.project_path IN (${placeholders(candidates)})
|
|
151793
|
+
ORDER BY workspace.id ASC
|
|
151794
|
+
LIMIT 1`).get(...candidates);
|
|
151795
|
+
return normalizeShareCategories(row?.shareCategories ?? null);
|
|
151796
|
+
}
|
|
151797
|
+
function resolveWorkspaceShareCategories(db, projectIdentity) {
|
|
151798
|
+
return selectWorkspaceShareCategories(db, [projectIdentity]);
|
|
151799
|
+
}
|
|
151800
|
+
function resolveWorkspaceIdentitySet(db, projectIdentity) {
|
|
151801
|
+
if (!tableExists(db, "workspace_members")) {
|
|
151802
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
151803
|
+
}
|
|
151804
|
+
const rows = db.prepare(`SELECT member.project_path AS identity, member.display_name AS displayName
|
|
151805
|
+
FROM workspace_members AS anchor
|
|
151806
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
151807
|
+
WHERE anchor.project_path = ?
|
|
151808
|
+
ORDER BY member.display_name ASC, member.project_path ASC`).all(projectIdentity);
|
|
151809
|
+
if (rows.length === 0) {
|
|
151810
|
+
return { identities: [projectIdentity], namesByIdentity: new Map };
|
|
151811
|
+
}
|
|
151812
|
+
const namesByIdentity = new Map;
|
|
151813
|
+
const identities = [];
|
|
151814
|
+
for (const row of rows) {
|
|
151815
|
+
if (typeof row.identity !== "string" || row.identity.length === 0)
|
|
151816
|
+
continue;
|
|
151817
|
+
if (identities.includes(row.identity))
|
|
151818
|
+
continue;
|
|
151819
|
+
identities.push(row.identity);
|
|
151820
|
+
if (typeof row.displayName === "string" && row.displayName.length > 0) {
|
|
151821
|
+
namesByIdentity.set(row.identity, row.displayName);
|
|
151822
|
+
}
|
|
151823
|
+
}
|
|
151824
|
+
return identities.length > 0 ? { identities, namesByIdentity } : { identities: [projectIdentity], namesByIdentity: new Map };
|
|
151825
|
+
}
|
|
151826
|
+
function expandWorkspaceIdentitySetWithAliases(db, identities) {
|
|
151827
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
151828
|
+
const expanded = new Set(canonical);
|
|
151829
|
+
const canonicalIdentityByStoredPath = new Map;
|
|
151830
|
+
for (const identity of canonical) {
|
|
151831
|
+
canonicalIdentityByStoredPath.set(identity, identity);
|
|
151832
|
+
}
|
|
151833
|
+
if (canonical.length === 0 || !tableExists(db, "v22_identity_rekey_map")) {
|
|
151834
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
151835
|
+
}
|
|
151836
|
+
const rows = db.prepare(`SELECT old_project_path AS oldProjectPath, new_project_path AS newProjectPath
|
|
151837
|
+
FROM v22_identity_rekey_map
|
|
151838
|
+
WHERE new_project_path IN (${placeholders(canonical)})
|
|
151839
|
+
ORDER BY old_project_path ASC`).all(...canonical);
|
|
151840
|
+
for (const row of rows) {
|
|
151841
|
+
if (typeof row.oldProjectPath !== "string" || typeof row.newProjectPath !== "string") {
|
|
151842
|
+
continue;
|
|
151843
|
+
}
|
|
151844
|
+
if (!canonicalIdentityByStoredPath.has(row.newProjectPath))
|
|
151845
|
+
continue;
|
|
151846
|
+
expanded.add(row.oldProjectPath);
|
|
151847
|
+
canonicalIdentityByStoredPath.set(row.oldProjectPath, row.newProjectPath);
|
|
151848
|
+
}
|
|
151849
|
+
return { expandedIdentities: [...expanded], canonicalIdentityByStoredPath };
|
|
151850
|
+
}
|
|
151851
|
+
function resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) {
|
|
151852
|
+
const direct = canonicalIdentityByStoredPath.get(storedProjectPath);
|
|
151853
|
+
if (direct)
|
|
151854
|
+
return direct;
|
|
151855
|
+
const normalized = normalizeStoredProjectPath(storedProjectPath);
|
|
151856
|
+
const normalizedDirect = canonicalIdentityByStoredPath.get(normalized);
|
|
151857
|
+
if (normalizedDirect)
|
|
151858
|
+
return normalizedDirect;
|
|
151859
|
+
if (memberIdentities.includes(normalized))
|
|
151860
|
+
return normalized;
|
|
151861
|
+
for (const identity of memberIdentities) {
|
|
151862
|
+
if (storedPathBelongsToIdentity(storedProjectPath, identity)) {
|
|
151863
|
+
return identity;
|
|
151864
|
+
}
|
|
151865
|
+
}
|
|
151866
|
+
return null;
|
|
151867
|
+
}
|
|
151868
|
+
function storedPathBelongsToWorkspace(storedProjectPath, memberIdentities, expandedIdentities, canonicalIdentityByStoredPath) {
|
|
151869
|
+
if (expandedIdentities.includes(storedProjectPath))
|
|
151870
|
+
return true;
|
|
151871
|
+
return resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath) !== null;
|
|
151872
|
+
}
|
|
151873
|
+
function sourceNameForMemory(storedProjectPath, ownIdentity, memberIdentities, namesByIdentity, canonicalIdentityByStoredPath) {
|
|
151874
|
+
const canonicalIdentity = resolveStoredPathWorkspaceIdentity(storedProjectPath, memberIdentities, canonicalIdentityByStoredPath);
|
|
151875
|
+
if (!canonicalIdentity || canonicalIdentity === ownIdentity)
|
|
151876
|
+
return;
|
|
151877
|
+
return namesByIdentity.get(canonicalIdentity);
|
|
151878
|
+
}
|
|
151879
|
+
function getEpochMap(db, identities) {
|
|
151880
|
+
if (identities.length === 0)
|
|
151881
|
+
return new Map;
|
|
151882
|
+
const rows = db.prepare(`SELECT project_path AS projectPath, project_memory_epoch AS epoch
|
|
151883
|
+
FROM project_state
|
|
151884
|
+
WHERE project_path IN (${placeholders(identities)})`).all(...identities);
|
|
151885
|
+
const epochs = new Map;
|
|
151886
|
+
for (const row of rows) {
|
|
151887
|
+
if (typeof row.projectPath !== "string" || typeof row.epoch !== "number")
|
|
151888
|
+
continue;
|
|
151889
|
+
epochs.set(row.projectPath, row.epoch);
|
|
151890
|
+
}
|
|
151891
|
+
return epochs;
|
|
151892
|
+
}
|
|
151893
|
+
function computeWorkspaceEpochFingerprint(db, identities) {
|
|
151894
|
+
const canonical = uniqueSorted(identities.filter((identity) => identity.length > 0));
|
|
151895
|
+
const epochs = getEpochMap(db, canonical);
|
|
151896
|
+
const shareCategories = selectWorkspaceShareCategories(db, canonical);
|
|
151897
|
+
const hash2 = createHash4("sha256");
|
|
151898
|
+
hash2.update("share_categories", "utf8");
|
|
151899
|
+
hash2.update("\x00");
|
|
151900
|
+
hash2.update(shareCategories === null ? "ALL" : JSON.stringify(shareCategories), "utf8");
|
|
151901
|
+
hash2.update(`
|
|
151902
|
+
`);
|
|
151903
|
+
for (const identity of canonical) {
|
|
151904
|
+
hash2.update(identity, "utf8");
|
|
151905
|
+
hash2.update("\x00");
|
|
151906
|
+
hash2.update(String(epochs.get(identity) ?? 0), "utf8");
|
|
151907
|
+
hash2.update(`
|
|
151908
|
+
`);
|
|
151909
|
+
}
|
|
151910
|
+
return hash2.digest("hex");
|
|
151911
|
+
}
|
|
151912
|
+
function isInTransaction(db) {
|
|
151913
|
+
const candidate = db;
|
|
151914
|
+
return candidate.inTransaction === true || candidate.isTransaction === true;
|
|
151915
|
+
}
|
|
151916
|
+
function workspaceMembersForIdentity(db, identity) {
|
|
151917
|
+
if (!tableExists(db, "workspace_members"))
|
|
151918
|
+
return [identity];
|
|
151919
|
+
const rows = db.prepare(`SELECT member.project_path AS identity
|
|
151920
|
+
FROM workspace_members AS anchor
|
|
151921
|
+
JOIN workspace_members AS member ON member.workspace_id = anchor.workspace_id
|
|
151922
|
+
WHERE anchor.project_path = ?
|
|
151923
|
+
ORDER BY member.project_path ASC`).all(identity);
|
|
151924
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((value) => value.length > 0);
|
|
151925
|
+
return identities.length > 0 ? uniqueSorted(identities) : [identity];
|
|
151926
|
+
}
|
|
151927
|
+
function bumpEpochRows(db, identities, now) {
|
|
151928
|
+
const stmt = db.prepare(`INSERT INTO project_state
|
|
151929
|
+
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
151930
|
+
VALUES (?, 1, 0, ?)
|
|
151931
|
+
ON CONFLICT(project_path) DO UPDATE SET
|
|
151932
|
+
project_memory_epoch = project_memory_epoch + 1,
|
|
151933
|
+
updated_at = excluded.updated_at`);
|
|
151934
|
+
for (const identity of uniqueSorted(identities)) {
|
|
151935
|
+
stmt.run(identity, now);
|
|
151936
|
+
}
|
|
151937
|
+
}
|
|
151938
|
+
function bumpEpochsForWorkspaceMembers(db, identity, now = Date.now()) {
|
|
151939
|
+
const run = () => bumpEpochRows(db, workspaceMembersForIdentity(db, identity), now);
|
|
151940
|
+
if (isInTransaction(db)) {
|
|
151941
|
+
run();
|
|
151942
|
+
return;
|
|
151943
|
+
}
|
|
151944
|
+
db.exec("BEGIN IMMEDIATE");
|
|
151945
|
+
try {
|
|
151946
|
+
run();
|
|
151947
|
+
db.exec("COMMIT");
|
|
151948
|
+
} catch (error51) {
|
|
151949
|
+
try {
|
|
151950
|
+
db.exec("ROLLBACK");
|
|
151951
|
+
} catch {}
|
|
151952
|
+
throw error51;
|
|
151953
|
+
}
|
|
151954
|
+
}
|
|
151955
|
+
function bumpEpochsForWorkspaceMemberSet(db, identities, now = Date.now()) {
|
|
151956
|
+
const run = () => bumpEpochRows(db, identities, now);
|
|
151957
|
+
if (isInTransaction(db)) {
|
|
151958
|
+
run();
|
|
151959
|
+
return;
|
|
151960
|
+
}
|
|
151961
|
+
db.exec("BEGIN IMMEDIATE");
|
|
151962
|
+
try {
|
|
151963
|
+
run();
|
|
151964
|
+
db.exec("COMMIT");
|
|
151965
|
+
} catch (error51) {
|
|
151966
|
+
try {
|
|
151967
|
+
db.exec("ROLLBACK");
|
|
151968
|
+
} catch {}
|
|
151969
|
+
throw error51;
|
|
151970
|
+
}
|
|
151971
|
+
}
|
|
151972
|
+
var VALID_SHARE_CATEGORIES;
|
|
151973
|
+
var init_workspaces = __esm(() => {
|
|
151974
|
+
init_constants();
|
|
151975
|
+
init_project_identity2();
|
|
151976
|
+
VALID_SHARE_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
151977
|
+
});
|
|
151978
|
+
|
|
151602
151979
|
// src/features/magic-context/migrations.ts
|
|
151603
|
-
function
|
|
151980
|
+
function tableExists2(db, name2) {
|
|
151604
151981
|
return Boolean(db.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name = ?").get(name2));
|
|
151605
151982
|
}
|
|
151983
|
+
function columnExists2(db, table, column) {
|
|
151984
|
+
const rows = db.prepare(`PRAGMA table_info(${table})`).all();
|
|
151985
|
+
return rows.some((row) => row.name === column);
|
|
151986
|
+
}
|
|
151606
151987
|
function ensureMigrationsTable(db) {
|
|
151607
151988
|
db.exec(`
|
|
151608
151989
|
CREATE TABLE IF NOT EXISTS schema_migrations (
|
|
@@ -151671,6 +152052,7 @@ function runMigrations(db) {
|
|
|
151671
152052
|
var MIGRATIONS, LATEST_MIGRATION_VERSION;
|
|
151672
152053
|
var init_migrations = __esm(async () => {
|
|
151673
152054
|
init_logger();
|
|
152055
|
+
init_workspaces();
|
|
151674
152056
|
await init_storage_db();
|
|
151675
152057
|
MIGRATIONS = [
|
|
151676
152058
|
{
|
|
@@ -152130,9 +152512,9 @@ var init_migrations = __esm(async () => {
|
|
|
152130
152512
|
version: 22,
|
|
152131
152513
|
description: "v2.0 cache architecture schema foundation",
|
|
152132
152514
|
up: (db) => {
|
|
152133
|
-
const hasSessionMetaTable =
|
|
152134
|
-
const hasCompartmentsTable =
|
|
152135
|
-
const hasMemoriesTable =
|
|
152515
|
+
const hasSessionMetaTable = tableExists2(db, "session_meta");
|
|
152516
|
+
const hasCompartmentsTable = tableExists2(db, "compartments");
|
|
152517
|
+
const hasMemoriesTable = tableExists2(db, "memories");
|
|
152136
152518
|
if (hasSessionMetaTable) {
|
|
152137
152519
|
ensureColumn(db, "session_meta", "cached_m0_bytes", "BLOB");
|
|
152138
152520
|
ensureColumn(db, "session_meta", "cached_m0_project_memory_epoch", "INTEGER");
|
|
@@ -152157,7 +152539,7 @@ var init_migrations = __esm(async () => {
|
|
|
152157
152539
|
ensureColumn(db, "compartments", "p1_embedding_model_id", "TEXT");
|
|
152158
152540
|
ensureColumn(db, "compartments", "legacy", "INTEGER NOT NULL DEFAULT 0");
|
|
152159
152541
|
}
|
|
152160
|
-
const hasRecompCompartmentsTable =
|
|
152542
|
+
const hasRecompCompartmentsTable = tableExists2(db, "recomp_compartments");
|
|
152161
152543
|
if (hasRecompCompartmentsTable) {
|
|
152162
152544
|
ensureColumn(db, "recomp_compartments", "p1", "TEXT");
|
|
152163
152545
|
ensureColumn(db, "recomp_compartments", "p2", "TEXT");
|
|
@@ -152468,13 +152850,163 @@ var init_migrations = __esm(async () => {
|
|
|
152468
152850
|
db.prepare("UPDATE session_meta SET force_emergency_bypass_used = 0 WHERE force_emergency_bypass_used IS NULL").run();
|
|
152469
152851
|
db.prepare("UPDATE session_meta SET last_usage_context_limit = 0 WHERE last_usage_context_limit IS NULL").run();
|
|
152470
152852
|
}
|
|
152853
|
+
},
|
|
152854
|
+
{
|
|
152855
|
+
version: 33,
|
|
152856
|
+
description: "Compartment chunk embeddings for semantic message-history search",
|
|
152857
|
+
up: (db) => {
|
|
152858
|
+
db.exec(`
|
|
152859
|
+
CREATE TABLE IF NOT EXISTS compartment_chunk_embeddings (
|
|
152860
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152861
|
+
compartment_id INTEGER NOT NULL REFERENCES compartments(id) ON DELETE CASCADE,
|
|
152862
|
+
session_id TEXT NOT NULL,
|
|
152863
|
+
project_path TEXT NOT NULL,
|
|
152864
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
152865
|
+
window_index INTEGER NOT NULL DEFAULT 0,
|
|
152866
|
+
start_ordinal INTEGER NOT NULL,
|
|
152867
|
+
end_ordinal INTEGER NOT NULL,
|
|
152868
|
+
chunk_hash TEXT NOT NULL,
|
|
152869
|
+
model_id TEXT NOT NULL,
|
|
152870
|
+
dims INTEGER NOT NULL,
|
|
152871
|
+
vector BLOB NOT NULL,
|
|
152872
|
+
created_at INTEGER NOT NULL,
|
|
152873
|
+
UNIQUE(compartment_id, window_index)
|
|
152874
|
+
);
|
|
152875
|
+
CREATE INDEX IF NOT EXISTS idx_cce_session
|
|
152876
|
+
ON compartment_chunk_embeddings(session_id);
|
|
152877
|
+
CREATE INDEX IF NOT EXISTS idx_cce_project_model
|
|
152878
|
+
ON compartment_chunk_embeddings(project_path, model_id);
|
|
152879
|
+
`);
|
|
152880
|
+
}
|
|
152881
|
+
},
|
|
152882
|
+
{
|
|
152883
|
+
version: 34,
|
|
152884
|
+
description: "workspace tables and m[0] workspace fingerprint cache reset",
|
|
152885
|
+
up: (db) => {
|
|
152886
|
+
db.exec(`
|
|
152887
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
152888
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152889
|
+
name TEXT NOT NULL UNIQUE,
|
|
152890
|
+
created_at INTEGER NOT NULL,
|
|
152891
|
+
updated_at INTEGER NOT NULL
|
|
152892
|
+
);
|
|
152893
|
+
CREATE TABLE IF NOT EXISTS workspace_members (
|
|
152894
|
+
workspace_id INTEGER NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
|
|
152895
|
+
project_path TEXT NOT NULL,
|
|
152896
|
+
display_name TEXT NOT NULL,
|
|
152897
|
+
display_path TEXT NOT NULL,
|
|
152898
|
+
added_at INTEGER NOT NULL,
|
|
152899
|
+
PRIMARY KEY (workspace_id, project_path)
|
|
152900
|
+
);
|
|
152901
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_unique
|
|
152902
|
+
ON workspace_members(project_path);
|
|
152903
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspace_member_name
|
|
152904
|
+
ON workspace_members(workspace_id, display_name);
|
|
152905
|
+
`);
|
|
152906
|
+
const hasSessionMeta = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='session_meta' LIMIT 1").get();
|
|
152907
|
+
if (!hasSessionMeta)
|
|
152908
|
+
return;
|
|
152909
|
+
ensureColumn(db, "session_meta", "cached_m0_workspace_fingerprint", "TEXT");
|
|
152910
|
+
const columns = new Set(db.prepare("PRAGMA table_info(session_meta)").all().map((column) => column.name));
|
|
152911
|
+
const clears = [
|
|
152912
|
+
["cached_m0_bytes", null],
|
|
152913
|
+
["cached_m1_bytes", null],
|
|
152914
|
+
["cached_m0_project_memory_epoch", null],
|
|
152915
|
+
["cached_m0_workspace_fingerprint", null],
|
|
152916
|
+
["cached_m0_project_user_profile_version", null],
|
|
152917
|
+
["cached_m0_max_compartment_seq", null],
|
|
152918
|
+
["cached_m0_max_memory_id", null],
|
|
152919
|
+
["cached_m0_max_mutation_id", null],
|
|
152920
|
+
["cached_m0_max_memory_mutation_id", null],
|
|
152921
|
+
["cached_m0_project_docs_hash", null],
|
|
152922
|
+
["cached_m0_materialized_at", null],
|
|
152923
|
+
["cached_m0_session_facts_version", null],
|
|
152924
|
+
["cached_m0_upgrade_state", null],
|
|
152925
|
+
["cached_m0_system_hash", null],
|
|
152926
|
+
["cached_m0_tool_set_hash", null],
|
|
152927
|
+
["cached_m0_model_key", null],
|
|
152928
|
+
["cached_m0_last_baseline_end_message_id", null],
|
|
152929
|
+
["memory_block_cache", ""],
|
|
152930
|
+
["memory_block_ids", ""],
|
|
152931
|
+
["memory_block_count", 0]
|
|
152932
|
+
];
|
|
152933
|
+
const setClauses = [];
|
|
152934
|
+
const values = [];
|
|
152935
|
+
for (const [column, value] of clears) {
|
|
152936
|
+
if (!columns.has(column))
|
|
152937
|
+
continue;
|
|
152938
|
+
setClauses.push(`${column} = ?`);
|
|
152939
|
+
values.push(value);
|
|
152940
|
+
}
|
|
152941
|
+
if (setClauses.length > 0) {
|
|
152942
|
+
db.prepare(`UPDATE session_meta SET ${setClauses.join(", ")}`).run(...values);
|
|
152943
|
+
}
|
|
152944
|
+
}
|
|
152945
|
+
},
|
|
152946
|
+
{
|
|
152947
|
+
version: 35,
|
|
152948
|
+
description: "workspace per-category share defaults and epoch refresh",
|
|
152949
|
+
up: (db) => {
|
|
152950
|
+
db.exec(`
|
|
152951
|
+
CREATE TABLE IF NOT EXISTS workspaces (
|
|
152952
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152953
|
+
name TEXT NOT NULL UNIQUE,
|
|
152954
|
+
created_at INTEGER NOT NULL,
|
|
152955
|
+
updated_at INTEGER NOT NULL,
|
|
152956
|
+
share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'
|
|
152957
|
+
);
|
|
152958
|
+
`);
|
|
152959
|
+
if (!columnExists2(db, "workspaces", "share_categories")) {
|
|
152960
|
+
db.exec(`ALTER TABLE workspaces ADD COLUMN share_categories TEXT NOT NULL DEFAULT '["CONSTRAINTS"]'`);
|
|
152961
|
+
}
|
|
152962
|
+
db.prepare(`UPDATE workspaces
|
|
152963
|
+
SET share_categories = '["CONSTRAINTS"]'
|
|
152964
|
+
WHERE share_categories IS NULL OR share_categories = ''`).run();
|
|
152965
|
+
if (!tableExists2(db, "workspace_members"))
|
|
152966
|
+
return;
|
|
152967
|
+
const rows = db.prepare(`SELECT DISTINCT project_path AS identity
|
|
152968
|
+
FROM workspace_members
|
|
152969
|
+
WHERE project_path IS NOT NULL AND project_path <> ''
|
|
152970
|
+
ORDER BY project_path ASC`).all();
|
|
152971
|
+
const identities = rows.map((row) => typeof row.identity === "string" ? row.identity : "").filter((identity) => identity.length > 0);
|
|
152972
|
+
if (identities.length > 0) {
|
|
152973
|
+
bumpEpochsForWorkspaceMemberSet(db, identities, Date.now());
|
|
152974
|
+
}
|
|
152975
|
+
}
|
|
152976
|
+
},
|
|
152977
|
+
{
|
|
152978
|
+
version: 36,
|
|
152979
|
+
description: "session project ownership map for compartment chunk backfill scoping",
|
|
152980
|
+
up: (db) => {
|
|
152981
|
+
db.exec(`
|
|
152982
|
+
CREATE TABLE IF NOT EXISTS session_projects (
|
|
152983
|
+
session_id TEXT NOT NULL,
|
|
152984
|
+
harness TEXT NOT NULL DEFAULT 'opencode',
|
|
152985
|
+
project_path TEXT NOT NULL,
|
|
152986
|
+
updated_at INTEGER NOT NULL,
|
|
152987
|
+
PRIMARY KEY(session_id, harness)
|
|
152988
|
+
);
|
|
152989
|
+
CREATE INDEX IF NOT EXISTS idx_session_projects_project
|
|
152990
|
+
ON session_projects(project_path);
|
|
152991
|
+
`);
|
|
152992
|
+
const hasChunkTable = db.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='compartment_chunk_embeddings'").get();
|
|
152993
|
+
if (hasChunkTable) {
|
|
152994
|
+
db.exec(`
|
|
152995
|
+
INSERT OR IGNORE INTO session_projects (session_id, harness, project_path, updated_at)
|
|
152996
|
+
SELECT session_id, harness, MIN(project_path), 0
|
|
152997
|
+
FROM compartment_chunk_embeddings
|
|
152998
|
+
GROUP BY session_id, harness
|
|
152999
|
+
HAVING COUNT(DISTINCT project_path) = 1;
|
|
153000
|
+
`);
|
|
153001
|
+
}
|
|
153002
|
+
}
|
|
152471
153003
|
}
|
|
152472
153004
|
];
|
|
152473
153005
|
LATEST_MIGRATION_VERSION = MIGRATIONS.reduce((max, m) => Math.max(max, m.version), 0);
|
|
152474
153006
|
});
|
|
152475
153007
|
|
|
152476
153008
|
// src/features/magic-context/project-docs-hash.ts
|
|
152477
|
-
import { createHash as
|
|
153009
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
152478
153010
|
import { lstatSync, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
|
|
152479
153011
|
import path4 from "node:path";
|
|
152480
153012
|
function canonicalizeDocContent(raw) {
|
|
@@ -152564,7 +153096,7 @@ function hashCanonicalPieces(hashPieces) {
|
|
|
152564
153096
|
if (hashPieces.length === 0) {
|
|
152565
153097
|
return "";
|
|
152566
153098
|
}
|
|
152567
|
-
return
|
|
153099
|
+
return createHash5("sha256").update(hashPieces.join(PROJECT_DOCS_DELIMITER), "utf8").digest("hex");
|
|
152568
153100
|
}
|
|
152569
153101
|
function readProjectDocsCanonical(projectDirectory) {
|
|
152570
153102
|
const canonicalDirectory = path4.resolve(projectDirectory);
|
|
@@ -152602,11 +153134,6 @@ var init_project_docs_hash = __esm(() => {
|
|
|
152602
153134
|
MAX_PROJECT_DOC_BYTES = 256 * 1024;
|
|
152603
153135
|
docsCache = new Map;
|
|
152604
153136
|
});
|
|
152605
|
-
|
|
152606
|
-
// src/features/magic-context/project-identity.ts
|
|
152607
|
-
var init_project_identity2 = __esm(() => {
|
|
152608
|
-
init_project_identity();
|
|
152609
|
-
});
|
|
152610
153137
|
// src/features/magic-context/storage-m0-mutation-log.ts
|
|
152611
153138
|
function assertMutationType(mutationType) {
|
|
152612
153139
|
if (!M0_MUTATION_TYPES.has(mutationType)) {
|
|
@@ -152691,18 +153218,13 @@ function getMemoryMutation(db, id) {
|
|
|
152691
153218
|
WHERE id = ?`).get(id);
|
|
152692
153219
|
return row ? toMemoryMutation(row) : null;
|
|
152693
153220
|
}
|
|
152694
|
-
function
|
|
152695
|
-
|
|
152696
|
-
|
|
152697
|
-
|
|
152698
|
-
|
|
152699
|
-
|
|
152700
|
-
|
|
152701
|
-
FROM memory_mutation_log
|
|
152702
|
-
WHERE project_path = ?
|
|
152703
|
-
AND id > ?
|
|
152704
|
-
AND target_memory_id IN (${placeholders})
|
|
152705
|
-
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
153221
|
+
function uniqueProjectPaths(projectPaths) {
|
|
153222
|
+
return [...new Set(projectPaths.filter((path5) => path5.length > 0))];
|
|
153223
|
+
}
|
|
153224
|
+
function placeholders2(values) {
|
|
153225
|
+
return values.map(() => "?").join(", ");
|
|
153226
|
+
}
|
|
153227
|
+
function coalesceMutations(rows) {
|
|
152706
153228
|
const chosenByTarget = new Map;
|
|
152707
153229
|
for (const dbRow of rows) {
|
|
152708
153230
|
const candidate = toMemoryMutation(dbRow);
|
|
@@ -152723,10 +153245,54 @@ function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds
|
|
|
152723
153245
|
}
|
|
152724
153246
|
return [...chosenByTarget.values()].sort((left, right) => left.id - right.id);
|
|
152725
153247
|
}
|
|
153248
|
+
function getMemoryMutationsForRender(db, projectPath, afterId, renderedMemoryIds) {
|
|
153249
|
+
if (renderedMemoryIds.length === 0)
|
|
153250
|
+
return [];
|
|
153251
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
153252
|
+
const placeholders3 = uniqueIds.map(() => "?").join(", ");
|
|
153253
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
153254
|
+
superseded_by_id, category, new_content, queued_at
|
|
153255
|
+
FROM memory_mutation_log
|
|
153256
|
+
WHERE project_path = ?
|
|
153257
|
+
AND id > ?
|
|
153258
|
+
AND target_memory_id IN (${placeholders3})
|
|
153259
|
+
ORDER BY id ASC`).all(projectPath, afterId ?? 0, ...uniqueIds);
|
|
153260
|
+
return coalesceMutations(rows);
|
|
153261
|
+
}
|
|
153262
|
+
function getMemoryMutationsForRenderByProjects(db, projectPaths, afterId, renderedMemoryIds) {
|
|
153263
|
+
if (renderedMemoryIds.length === 0)
|
|
153264
|
+
return [];
|
|
153265
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
153266
|
+
if (identities.length === 0)
|
|
153267
|
+
return [];
|
|
153268
|
+
if (identities.length === 1) {
|
|
153269
|
+
return getMemoryMutationsForRender(db, identities[0], afterId, renderedMemoryIds);
|
|
153270
|
+
}
|
|
153271
|
+
const uniqueIds = [...new Set(renderedMemoryIds)].sort((left, right) => left - right);
|
|
153272
|
+
const rows = db.prepare(`SELECT id, project_path, mutation_type, target_memory_id,
|
|
153273
|
+
superseded_by_id, category, new_content, queued_at
|
|
153274
|
+
FROM memory_mutation_log
|
|
153275
|
+
WHERE project_path IN (${placeholders2(identities)})
|
|
153276
|
+
AND id > ?
|
|
153277
|
+
AND target_memory_id IN (${placeholders2(uniqueIds)})
|
|
153278
|
+
ORDER BY id ASC`).all(...identities, afterId ?? 0, ...uniqueIds);
|
|
153279
|
+
return coalesceMutations(rows);
|
|
153280
|
+
}
|
|
152726
153281
|
function getMaxMemoryMutationId(db, projectPath) {
|
|
152727
153282
|
const row = db.prepare("SELECT MAX(id) AS max_id FROM memory_mutation_log WHERE project_path = ?").get(projectPath);
|
|
152728
153283
|
return row?.max_id ?? null;
|
|
152729
153284
|
}
|
|
153285
|
+
function getMaxMemoryMutationIdForProjects(db, projectPaths) {
|
|
153286
|
+
const identities = uniqueProjectPaths(projectPaths);
|
|
153287
|
+
if (identities.length === 0)
|
|
153288
|
+
return null;
|
|
153289
|
+
if (identities.length === 1)
|
|
153290
|
+
return getMaxMemoryMutationId(db, identities[0]);
|
|
153291
|
+
const row = db.prepare(`SELECT MAX(id) AS max_id
|
|
153292
|
+
FROM memory_mutation_log
|
|
153293
|
+
WHERE project_path IN (${placeholders2(identities)})`).get(...identities);
|
|
153294
|
+
return row?.max_id ?? null;
|
|
153295
|
+
}
|
|
152730
153296
|
var MEMORY_MUTATION_TYPES, TERMINAL_MUTATION_TYPES;
|
|
152731
153297
|
var init_storage_memory_mutation_log = __esm(() => {
|
|
152732
153298
|
MEMORY_MUTATION_TYPES = new Set(["archive", "delete", "update", "superseded"]);
|
|
@@ -153419,6 +153985,36 @@ function addStaleReduceStrippedIds(db, sessionId, ids) {
|
|
|
153419
153985
|
sessionLog(sessionId, `stale_reduce_stripped_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
153420
153986
|
return false;
|
|
153421
153987
|
}
|
|
153988
|
+
function getProcessedImageStrippedIds(db, sessionId) {
|
|
153989
|
+
const row = db.prepare("SELECT processed_image_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
153990
|
+
return new Set(parseStrippedBlob(row?.processed_image_stripped_ids));
|
|
153991
|
+
}
|
|
153992
|
+
function addProcessedImageStrippedIds(db, sessionId, ids) {
|
|
153993
|
+
const add = [...ids];
|
|
153994
|
+
if (add.length === 0)
|
|
153995
|
+
return true;
|
|
153996
|
+
ensureSessionMetaRow(db, sessionId);
|
|
153997
|
+
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
153998
|
+
const row = db.prepare("SELECT processed_image_stripped_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
153999
|
+
const rawStored = row ? row.processed_image_stripped_ids ?? null : null;
|
|
154000
|
+
const current = new Set(parseStrippedBlob(rawStored));
|
|
154001
|
+
let changed = false;
|
|
154002
|
+
for (const id of add) {
|
|
154003
|
+
if (!current.has(id)) {
|
|
154004
|
+
current.add(id);
|
|
154005
|
+
changed = true;
|
|
154006
|
+
}
|
|
154007
|
+
}
|
|
154008
|
+
if (!changed)
|
|
154009
|
+
return true;
|
|
154010
|
+
const nextBlob = JSON.stringify([...current]);
|
|
154011
|
+
const result = db.prepare("UPDATE session_meta SET processed_image_stripped_ids = ? WHERE session_id = ? AND processed_image_stripped_ids IS ?").run(nextBlob, sessionId, rawStored);
|
|
154012
|
+
if (result.changes > 0)
|
|
154013
|
+
return true;
|
|
154014
|
+
}
|
|
154015
|
+
sessionLog(sessionId, `processed_image_stripped_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
154016
|
+
return false;
|
|
154017
|
+
}
|
|
153422
154018
|
function isPendingCompactionMarker(value) {
|
|
153423
154019
|
return typeof value === "object" && value !== null && typeof value.ordinal === "number" && typeof value.endMessageId === "string" && typeof value.publishedAt === "number";
|
|
153424
154020
|
}
|
|
@@ -153597,6 +154193,8 @@ function clearSession(db, sessionId) {
|
|
|
153597
154193
|
db.prepare("DELETE FROM source_contents WHERE session_id = ?").run(sessionId);
|
|
153598
154194
|
db.prepare("DELETE FROM tags WHERE session_id = ?").run(sessionId);
|
|
153599
154195
|
db.prepare("DELETE FROM session_meta WHERE session_id = ?").run(sessionId);
|
|
154196
|
+
db.prepare("DELETE FROM session_projects WHERE session_id = ?").run(sessionId);
|
|
154197
|
+
db.prepare("DELETE FROM compartment_chunk_embeddings WHERE session_id = ?").run(sessionId);
|
|
153600
154198
|
db.prepare("DELETE FROM compartments WHERE session_id = ?").run(sessionId);
|
|
153601
154199
|
clearCompressionDepth(db, sessionId);
|
|
153602
154200
|
db.prepare("DELETE FROM session_facts WHERE session_id = ?").run(sessionId);
|
|
@@ -153703,9 +154301,9 @@ function buildStatusClause(status) {
|
|
|
153703
154301
|
if (statuses.length === 0) {
|
|
153704
154302
|
return null;
|
|
153705
154303
|
}
|
|
153706
|
-
const
|
|
154304
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
153707
154305
|
return {
|
|
153708
|
-
sql: `status IN (${
|
|
154306
|
+
sql: `status IN (${placeholders3})`,
|
|
153709
154307
|
params: statuses
|
|
153710
154308
|
};
|
|
153711
154309
|
}
|
|
@@ -153911,19 +154509,6 @@ function getProjectState(db, projectPath) {
|
|
|
153911
154509
|
WHERE project_path = ?`).get(projectPath);
|
|
153912
154510
|
return row ? toProjectState(row) : null;
|
|
153913
154511
|
}
|
|
153914
|
-
function bumpProjectMemoryEpoch(db, projectPath, now = Date.now()) {
|
|
153915
|
-
db.prepare(`INSERT INTO project_state
|
|
153916
|
-
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
153917
|
-
VALUES (?, 1, 0, ?)
|
|
153918
|
-
ON CONFLICT(project_path) DO UPDATE SET
|
|
153919
|
-
project_memory_epoch = project_memory_epoch + 1,
|
|
153920
|
-
updated_at = excluded.updated_at`).run(projectPath, now);
|
|
153921
|
-
const state = getProjectState(db, projectPath);
|
|
153922
|
-
if (!state) {
|
|
153923
|
-
throw new Error(`Failed to bump project memory epoch for ${projectPath}`);
|
|
153924
|
-
}
|
|
153925
|
-
return state;
|
|
153926
|
-
}
|
|
153927
154512
|
function bumpProjectUserProfileVersion(db, projectPath = GLOBAL_USER_PROFILE_PROJECT_PATH, now = Date.now()) {
|
|
153928
154513
|
db.prepare(`INSERT INTO project_state
|
|
153929
154514
|
(project_path, project_memory_epoch, project_user_profile_version, updated_at)
|
|
@@ -153959,8 +154544,8 @@ function getSourceContents(db, sessionId, tagIds) {
|
|
|
153959
154544
|
if (tagIds.length === 0) {
|
|
153960
154545
|
return new Map;
|
|
153961
154546
|
}
|
|
153962
|
-
const
|
|
153963
|
-
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${
|
|
154547
|
+
const placeholders3 = tagIds.map(() => "?").join(", ");
|
|
154548
|
+
const rows = db.prepare(`SELECT tag_id, content FROM source_contents WHERE session_id = ? AND tag_id IN (${placeholders3})`).all(sessionId, ...tagIds).filter(isSourceContentRow);
|
|
153964
154549
|
const sources = new Map;
|
|
153965
154550
|
for (const row of rows) {
|
|
153966
154551
|
sources.set(row.tag_id, row.content);
|
|
@@ -154024,15 +154609,22 @@ function ownerMessageIdForTagRow(row) {
|
|
|
154024
154609
|
}
|
|
154025
154610
|
return row.message_id.replace(CONTENT_ID_SUFFIX, "");
|
|
154026
154611
|
}
|
|
154027
|
-
function getActiveTagTokenAggregate(db, sessionId) {
|
|
154028
|
-
const
|
|
154612
|
+
function getActiveTagTokenAggregate(db, sessionId, protectedTags = 0) {
|
|
154613
|
+
const toolOutputExpr = protectedTags > 0 ? `COALESCE(SUM(CASE WHEN type = 'tool' AND tag_number < (
|
|
154614
|
+
SELECT tag_number FROM tags
|
|
154615
|
+
WHERE session_id = ? AND status = 'active'
|
|
154616
|
+
ORDER BY tag_number DESC LIMIT 1 OFFSET ?
|
|
154617
|
+
) THEN COALESCE(token_count, 0) ELSE 0 END), 0)` : `COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0)`;
|
|
154618
|
+
const sql = `SELECT
|
|
154029
154619
|
COALESCE(SUM(CASE WHEN type != 'tool' THEN COALESCE(token_count, 0) ELSE 0 END), 0)
|
|
154030
154620
|
+ COALESCE(SUM(COALESCE(reasoning_token_count, 0)), 0) AS conversation,
|
|
154031
154621
|
COALESCE(SUM(CASE WHEN type = 'tool' THEN COALESCE(token_count, 0) + COALESCE(input_token_count, 0) ELSE 0 END), 0) AS tool_call,
|
|
154032
|
-
|
|
154622
|
+
${toolOutputExpr} AS tool_output,
|
|
154033
154623
|
COALESCE(SUM(CASE WHEN token_count IS NULL THEN 1 ELSE 0 END), 0) AS null_count
|
|
154034
154624
|
FROM tags
|
|
154035
|
-
WHERE session_id = ? AND status = 'active'
|
|
154625
|
+
WHERE session_id = ? AND status = 'active'`;
|
|
154626
|
+
const params = protectedTags > 0 ? [sessionId, protectedTags - 1, sessionId] : [sessionId];
|
|
154627
|
+
const row = db.prepare(sql).get(...params);
|
|
154036
154628
|
return {
|
|
154037
154629
|
conversation: row?.conversation ?? 0,
|
|
154038
154630
|
toolCall: row?.tool_call ?? 0,
|
|
@@ -154270,8 +154862,8 @@ function getTagsByNumbers(db, sessionId, tagNumbers) {
|
|
|
154270
154862
|
}
|
|
154271
154863
|
return all;
|
|
154272
154864
|
}
|
|
154273
|
-
const
|
|
154274
|
-
const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${
|
|
154865
|
+
const placeholders3 = tagNumbers.map(() => "?").join(",");
|
|
154866
|
+
const rows = db.prepare(`SELECT ${TAG_SELECT_COLUMNS} FROM tags WHERE session_id = ? AND tag_number IN (${placeholders3}) ORDER BY tag_number ASC, id ASC`).all(sessionId, ...tagNumbers).filter(isTagRow);
|
|
154275
154867
|
return rows.map(toTagEntry);
|
|
154276
154868
|
}
|
|
154277
154869
|
function getMaxDroppedTagNumber(db, sessionId) {
|
|
@@ -154424,6 +155016,7 @@ var init_storage = __esm(async () => {
|
|
|
154424
155016
|
init_storage_source();
|
|
154425
155017
|
init_storage_tags();
|
|
154426
155018
|
init_storage_v22_backfill_failures();
|
|
155019
|
+
init_workspaces();
|
|
154427
155020
|
await __promiseAll([
|
|
154428
155021
|
init_message_index(),
|
|
154429
155022
|
init_migrations(),
|
|
@@ -163875,7 +164468,7 @@ function isEmbeddingRow(row) {
|
|
|
163875
164468
|
if (row === null || typeof row !== "object")
|
|
163876
164469
|
return false;
|
|
163877
164470
|
const candidate = row;
|
|
163878
|
-
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding);
|
|
164471
|
+
return typeof candidate.memoryId === "number" && isEmbeddingBlob(candidate.embedding) && (candidate.modelId === null || typeof candidate.modelId === "string");
|
|
163879
164472
|
}
|
|
163880
164473
|
function toFloat32Array(blob) {
|
|
163881
164474
|
if (blob instanceof Uint8Array) {
|
|
@@ -163895,7 +164488,7 @@ function getSaveEmbeddingStatement(db) {
|
|
|
163895
164488
|
function getLoadAllEmbeddingsStatement(db) {
|
|
163896
164489
|
let stmt = loadAllEmbeddingsStatements.get(db);
|
|
163897
164490
|
if (!stmt) {
|
|
163898
|
-
stmt = db.prepare("SELECT memory_embeddings.memory_id AS memoryId, memory_embeddings.embedding AS embedding FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? ORDER BY memory_embeddings.memory_id ASC");
|
|
164491
|
+
stmt = db.prepare("SELECT memory_embeddings.memory_id AS memoryId, memory_embeddings.embedding AS embedding, memory_embeddings.model_id AS modelId FROM memory_embeddings INNER JOIN memories ON memories.id = memory_embeddings.memory_id WHERE memories.project_path = ? ORDER BY memory_embeddings.memory_id ASC");
|
|
163899
164492
|
loadAllEmbeddingsStatements.set(db, stmt);
|
|
163900
164493
|
}
|
|
163901
164494
|
return stmt;
|
|
@@ -163924,7 +164517,10 @@ function loadAllEmbeddings(db, projectPath) {
|
|
|
163924
164517
|
const rows = getLoadAllEmbeddingsStatement(db).all(projectPath).filter(isEmbeddingRow);
|
|
163925
164518
|
const embeddings = new Map;
|
|
163926
164519
|
for (const row of rows) {
|
|
163927
|
-
embeddings.set(row.memoryId,
|
|
164520
|
+
embeddings.set(row.memoryId, {
|
|
164521
|
+
embedding: toFloat32Array(row.embedding),
|
|
164522
|
+
modelId: row.modelId
|
|
164523
|
+
});
|
|
163928
164524
|
}
|
|
163929
164525
|
return embeddings;
|
|
163930
164526
|
}
|
|
@@ -163987,13 +164583,13 @@ var init_embedding_cache = __esm(() => {
|
|
|
163987
164583
|
});
|
|
163988
164584
|
|
|
163989
164585
|
// src/features/magic-context/memory/normalize-hash.ts
|
|
163990
|
-
import { createHash as
|
|
164586
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
163991
164587
|
function normalizeMemoryContent(content) {
|
|
163992
164588
|
return content.toLowerCase().replace(/\s+/g, " ").trim();
|
|
163993
164589
|
}
|
|
163994
164590
|
function computeNormalizedHash(content) {
|
|
163995
164591
|
const normalized = normalizeMemoryContent(content);
|
|
163996
|
-
return
|
|
164592
|
+
return createHash7("md5").update(normalized).digest("hex");
|
|
163997
164593
|
}
|
|
163998
164594
|
var init_normalize_hash = () => {};
|
|
163999
164595
|
|
|
@@ -164107,8 +164703,8 @@ function getMemoriesByProjectStatement(db, statuses) {
|
|
|
164107
164703
|
}
|
|
164108
164704
|
let stmt = statements.get(db);
|
|
164109
164705
|
if (!stmt) {
|
|
164110
|
-
const
|
|
164111
|
-
stmt = db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories WHERE project_path = ? AND status IN (${
|
|
164706
|
+
const placeholders3 = statuses.map(() => "?").join(", ");
|
|
164707
|
+
stmt = db.prepare(`SELECT ${getMemorySelectColumns(db)} FROM memories WHERE project_path = ? AND status IN (${placeholders3}) AND (expires_at IS NULL OR expires_at > ?) ORDER BY category ASC, updated_at DESC, id ASC`);
|
|
164112
164708
|
statements.set(db, stmt);
|
|
164113
164709
|
}
|
|
164114
164710
|
return stmt;
|
|
@@ -164229,6 +164825,97 @@ function getMemoriesByProject(db, projectPath, statuses = ["active", "permanent"
|
|
|
164229
164825
|
const rows = getMemoriesByProjectStatement(db, statuses).all(projectPath, ...statuses, expiryCutoff).filter(isMemoryRow);
|
|
164230
164826
|
return rows.map(toMemory);
|
|
164231
164827
|
}
|
|
164828
|
+
function sqlPlaceholders(values) {
|
|
164829
|
+
return values.map(() => "?").join(", ");
|
|
164830
|
+
}
|
|
164831
|
+
function uniqueValues(values) {
|
|
164832
|
+
return [...new Set(values.filter((value) => value.length > 0))];
|
|
164833
|
+
}
|
|
164834
|
+
function buildWorkspaceMemorySqlFilter(args) {
|
|
164835
|
+
if (args.shareCategories === null || args.shareCategories === undefined) {
|
|
164836
|
+
return { clause: "", params: [], active: false };
|
|
164837
|
+
}
|
|
164838
|
+
const identities = uniqueValues(args.identities);
|
|
164839
|
+
const identitySet = new Set(identities);
|
|
164840
|
+
const ownSet = new Set(uniqueValues(args.ownIdentities ?? []).filter((identity) => identitySet.has(identity)));
|
|
164841
|
+
const foreignIdentities = identities.filter((identity) => !ownSet.has(identity));
|
|
164842
|
+
if (foreignIdentities.length === 0) {
|
|
164843
|
+
return { clause: "", params: [], active: false };
|
|
164844
|
+
}
|
|
164845
|
+
const ownIdentities = identities.filter((identity) => ownSet.has(identity));
|
|
164846
|
+
const shareCategories = uniqueValues([...args.shareCategories]);
|
|
164847
|
+
const qualifier = args.tableName ? `${args.tableName}.` : "";
|
|
164848
|
+
const predicates = [];
|
|
164849
|
+
const params = [];
|
|
164850
|
+
if (ownIdentities.length > 0) {
|
|
164851
|
+
predicates.push(`${qualifier}project_path IN (${sqlPlaceholders(ownIdentities)})`);
|
|
164852
|
+
params.push(...ownIdentities);
|
|
164853
|
+
}
|
|
164854
|
+
if (foreignIdentities.length > 0 && shareCategories.length > 0) {
|
|
164855
|
+
predicates.push(`(${qualifier}project_path IN (${sqlPlaceholders(foreignIdentities)}) AND ${qualifier}category IN (${sqlPlaceholders(shareCategories)}))`);
|
|
164856
|
+
params.push(...foreignIdentities, ...shareCategories);
|
|
164857
|
+
}
|
|
164858
|
+
if (predicates.length === 0) {
|
|
164859
|
+
return { clause: " AND 0 = 1", params: [], active: true };
|
|
164860
|
+
}
|
|
164861
|
+
return { clause: ` AND (${predicates.join(" OR ")})`, params, active: true };
|
|
164862
|
+
}
|
|
164863
|
+
function getMemoriesByProjects(db, projectPaths, statuses = ["active", "permanent"], expiryCutoff = Date.now(), ownIdentities, shareCategories) {
|
|
164864
|
+
const identities = uniqueValues(projectPaths);
|
|
164865
|
+
if (identities.length === 0 || statuses.length === 0)
|
|
164866
|
+
return [];
|
|
164867
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
164868
|
+
identities,
|
|
164869
|
+
ownIdentities,
|
|
164870
|
+
shareCategories
|
|
164871
|
+
});
|
|
164872
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
164873
|
+
return getMemoriesByProject(db, identities[0], statuses, expiryCutoff);
|
|
164874
|
+
}
|
|
164875
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
164876
|
+
FROM memories
|
|
164877
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
164878
|
+
AND status IN (${sqlPlaceholders(statuses)})
|
|
164879
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
164880
|
+
ORDER BY category ASC, updated_at DESC, id ASC`).all(...identities, ...statuses, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
164881
|
+
return rows.map(toMemory);
|
|
164882
|
+
}
|
|
164883
|
+
function getMaxMemoryIdForProjects(db, projectPaths, ownIdentities, shareCategories) {
|
|
164884
|
+
const identities = uniqueValues(projectPaths);
|
|
164885
|
+
if (identities.length === 0)
|
|
164886
|
+
return 0;
|
|
164887
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
164888
|
+
identities,
|
|
164889
|
+
ownIdentities,
|
|
164890
|
+
shareCategories
|
|
164891
|
+
});
|
|
164892
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
164893
|
+
const row2 = db.prepare("SELECT COALESCE(MAX(id), 0) AS max_id FROM memories WHERE project_path = ?").get(identities[0]);
|
|
164894
|
+
return typeof row2?.max_id === "number" ? row2.max_id : 0;
|
|
164895
|
+
}
|
|
164896
|
+
const row = db.prepare(`SELECT COALESCE(MAX(id), 0) AS max_id
|
|
164897
|
+
FROM memories
|
|
164898
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})${sharingFilter.clause}`).get(...identities, ...sharingFilter.params);
|
|
164899
|
+
return typeof row?.max_id === "number" ? row.max_id : 0;
|
|
164900
|
+
}
|
|
164901
|
+
function readNewMemoriesForM1Union(db, projectPaths, afterId, expiryCutoff, ownIdentities, shareCategories) {
|
|
164902
|
+
const identities = uniqueValues(projectPaths);
|
|
164903
|
+
if (identities.length === 0)
|
|
164904
|
+
return [];
|
|
164905
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
164906
|
+
identities,
|
|
164907
|
+
ownIdentities,
|
|
164908
|
+
shareCategories
|
|
164909
|
+
});
|
|
164910
|
+
const rows = db.prepare(`SELECT ${getMemorySelectColumns(db)}
|
|
164911
|
+
FROM memories
|
|
164912
|
+
WHERE project_path IN (${sqlPlaceholders(identities)})
|
|
164913
|
+
AND id > ?
|
|
164914
|
+
AND status IN ('active', 'permanent')
|
|
164915
|
+
AND (expires_at IS NULL OR expires_at > ?)${sharingFilter.clause}
|
|
164916
|
+
ORDER BY ${MEMORY_CATEGORY_ORDER_SQL}, id ASC`).all(...identities, afterId, expiryCutoff, ...sharingFilter.params).filter(isMemoryRow);
|
|
164917
|
+
return rows.map(toMemory);
|
|
164918
|
+
}
|
|
164232
164919
|
function getAllActiveMemoriesForMigration(db, projectPath) {
|
|
164233
164920
|
const rows = getActiveMemoriesNoExpiryStatement(db).all(projectPath).filter(isMemoryRow);
|
|
164234
164921
|
return rows.map(toMemory);
|
|
@@ -164326,6 +165013,7 @@ function getMemoryCountsByStatus(db, projectPath) {
|
|
|
164326
165013
|
}
|
|
164327
165014
|
var COLUMN_MAP, MEMORY_CATEGORY_LOOKUP, MEMORY_STATUS_LOOKUP, MEMORY_SOURCE_TYPE_LOOKUP, VERIFICATION_STATUS_LOOKUP, insertMemoryStatements, getMemoryByHashStatements, getMemoryByIdStatements, activeMemoriesNoExpiryStatements, updateMemorySeenCountStatements, updateMemoryRetrievalCountStatements, updateMemoryStatusStatements, updateArchivedMemoryStatements, updateMemoryVerificationStatements, updateMemoryContentStatements, supersededMemoryStatements, mergeMemoryStatsStatements, deleteMemoryStatements, deleteMemoryEmbeddingStatements, deleteEmbeddingOnContentUpdateStatements, getMemoryCountStatements, getMemoryCountByProjectStatements, getMemoryCountsByStatusStatements, memoriesByProjectStatements, memoryImportanceColumnCache;
|
|
164328
165015
|
var init_storage_memory = __esm(() => {
|
|
165016
|
+
init_constants();
|
|
164329
165017
|
init_embedding_cache();
|
|
164330
165018
|
init_normalize_hash();
|
|
164331
165019
|
COLUMN_MAP = {
|
|
@@ -164431,8 +165119,8 @@ function getUserMemoryCandidates(db) {
|
|
|
164431
165119
|
function deleteUserMemoryCandidates(db, ids) {
|
|
164432
165120
|
if (ids.length === 0)
|
|
164433
165121
|
return;
|
|
164434
|
-
const
|
|
164435
|
-
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${
|
|
165122
|
+
const placeholders3 = ids.map(() => "?").join(",");
|
|
165123
|
+
db.prepare(`DELETE FROM user_memory_candidates WHERE id IN (${placeholders3})`).run(...ids);
|
|
164436
165124
|
}
|
|
164437
165125
|
function insertUserMemory(db, content, sourceCandidateIds) {
|
|
164438
165126
|
const now = Date.now();
|
|
@@ -164465,6 +165153,445 @@ function parseUserMemoryRow(row) {
|
|
|
164465
165153
|
};
|
|
164466
165154
|
}
|
|
164467
165155
|
|
|
165156
|
+
// src/features/magic-context/compartment-chunk-embedding.ts
|
|
165157
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
165158
|
+
function getLoadFtsRowsStatement(db) {
|
|
165159
|
+
let stmt = loadFtsRowsStatements.get(db);
|
|
165160
|
+
if (!stmt) {
|
|
165161
|
+
stmt = db.prepare(`SELECT message_ordinal AS messageOrdinal, role, content
|
|
165162
|
+
FROM message_history_fts
|
|
165163
|
+
WHERE session_id = ?
|
|
165164
|
+
AND message_ordinal >= ?
|
|
165165
|
+
AND message_ordinal <= ?
|
|
165166
|
+
AND role IN ('user', 'assistant')
|
|
165167
|
+
ORDER BY message_ordinal ASC`);
|
|
165168
|
+
loadFtsRowsStatements.set(db, stmt);
|
|
165169
|
+
}
|
|
165170
|
+
return stmt;
|
|
165171
|
+
}
|
|
165172
|
+
function getExistingHashStatement(db, scopedToProject) {
|
|
165173
|
+
const map2 = scopedToProject ? existingHashByProjectStatements : existingHashStatements;
|
|
165174
|
+
let stmt = map2.get(db);
|
|
165175
|
+
if (!stmt) {
|
|
165176
|
+
stmt = db.prepare(`SELECT window_index AS windowIndex, chunk_hash AS chunkHash
|
|
165177
|
+
FROM compartment_chunk_embeddings
|
|
165178
|
+
WHERE compartment_id = ?
|
|
165179
|
+
AND model_id = ?
|
|
165180
|
+
${scopedToProject ? "AND project_path = ?" : ""}
|
|
165181
|
+
ORDER BY window_index ASC`);
|
|
165182
|
+
map2.set(db, stmt);
|
|
165183
|
+
}
|
|
165184
|
+
return stmt;
|
|
165185
|
+
}
|
|
165186
|
+
function getDeleteByCompartmentStatement(db) {
|
|
165187
|
+
let stmt = deleteByCompartmentStatements.get(db);
|
|
165188
|
+
if (!stmt) {
|
|
165189
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE compartment_id = ?");
|
|
165190
|
+
deleteByCompartmentStatements.set(db, stmt);
|
|
165191
|
+
}
|
|
165192
|
+
return stmt;
|
|
165193
|
+
}
|
|
165194
|
+
function getInsertEmbeddingStatement(db) {
|
|
165195
|
+
let stmt = insertEmbeddingStatements.get(db);
|
|
165196
|
+
if (!stmt) {
|
|
165197
|
+
stmt = db.prepare(`INSERT INTO compartment_chunk_embeddings (
|
|
165198
|
+
compartment_id, session_id, project_path, harness, window_index,
|
|
165199
|
+
start_ordinal, end_ordinal, chunk_hash, model_id, dims, vector, created_at
|
|
165200
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
165201
|
+
insertEmbeddingStatements.set(db, stmt);
|
|
165202
|
+
}
|
|
165203
|
+
return stmt;
|
|
165204
|
+
}
|
|
165205
|
+
function getDistinctModelStatement(db) {
|
|
165206
|
+
let stmt = distinctModelStatements.get(db);
|
|
165207
|
+
if (!stmt) {
|
|
165208
|
+
stmt = db.prepare(`SELECT DISTINCT model_id AS modelId
|
|
165209
|
+
FROM compartment_chunk_embeddings
|
|
165210
|
+
WHERE project_path = ?`);
|
|
165211
|
+
distinctModelStatements.set(db, stmt);
|
|
165212
|
+
}
|
|
165213
|
+
return stmt;
|
|
165214
|
+
}
|
|
165215
|
+
function getClearProjectStatement(db) {
|
|
165216
|
+
let stmt = clearProjectStatements.get(db);
|
|
165217
|
+
if (!stmt) {
|
|
165218
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ?");
|
|
165219
|
+
clearProjectStatements.set(db, stmt);
|
|
165220
|
+
}
|
|
165221
|
+
return stmt;
|
|
165222
|
+
}
|
|
165223
|
+
function getClearProjectModelStatement(db) {
|
|
165224
|
+
let stmt = clearProjectModelStatements.get(db);
|
|
165225
|
+
if (!stmt) {
|
|
165226
|
+
stmt = db.prepare("DELETE FROM compartment_chunk_embeddings WHERE project_path = ? AND model_id = ?");
|
|
165227
|
+
clearProjectModelStatements.set(db, stmt);
|
|
165228
|
+
}
|
|
165229
|
+
return stmt;
|
|
165230
|
+
}
|
|
165231
|
+
function getSearchRowsStatement(db, withModel) {
|
|
165232
|
+
const map2 = withModel ? searchRowsByModelStatements : searchRowsStatements;
|
|
165233
|
+
let stmt = map2.get(db);
|
|
165234
|
+
if (!stmt) {
|
|
165235
|
+
stmt = db.prepare(`SELECT e.compartment_id AS compartmentId,
|
|
165236
|
+
e.session_id AS sessionId,
|
|
165237
|
+
c.title AS title,
|
|
165238
|
+
c.start_message AS compartmentStart,
|
|
165239
|
+
c.end_message AS compartmentEnd,
|
|
165240
|
+
e.window_index AS windowIndex,
|
|
165241
|
+
e.start_ordinal AS windowStart,
|
|
165242
|
+
e.end_ordinal AS windowEnd,
|
|
165243
|
+
e.chunk_hash AS chunkHash,
|
|
165244
|
+
e.model_id AS modelId,
|
|
165245
|
+
e.dims AS dims,
|
|
165246
|
+
e.vector AS vector
|
|
165247
|
+
FROM compartment_chunk_embeddings e
|
|
165248
|
+
JOIN compartments c ON c.id = e.compartment_id
|
|
165249
|
+
WHERE e.session_id = ?
|
|
165250
|
+
AND e.project_path = ?
|
|
165251
|
+
${withModel ? "AND e.model_id = ?" : ""}
|
|
165252
|
+
ORDER BY e.compartment_id ASC, e.window_index ASC`);
|
|
165253
|
+
map2.set(db, stmt);
|
|
165254
|
+
}
|
|
165255
|
+
return stmt;
|
|
165256
|
+
}
|
|
165257
|
+
function isFinitePositiveInteger(value) {
|
|
165258
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
165259
|
+
}
|
|
165260
|
+
function normalizeCompartmentChunkMaxInputTokens(value) {
|
|
165261
|
+
if (!isFinitePositiveInteger(value)) {
|
|
165262
|
+
return DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS;
|
|
165263
|
+
}
|
|
165264
|
+
return Math.max(1, Math.floor(value));
|
|
165265
|
+
}
|
|
165266
|
+
function normalizeContent(text) {
|
|
165267
|
+
return text.replace(/\s+/g, " ").trim();
|
|
165268
|
+
}
|
|
165269
|
+
function formatOrdinalRange(start, end) {
|
|
165270
|
+
return start === end ? `[${start}]` : `[${start}-${end}]`;
|
|
165271
|
+
}
|
|
165272
|
+
function rolePrefix(role) {
|
|
165273
|
+
if (role === "user")
|
|
165274
|
+
return "U";
|
|
165275
|
+
if (role === "assistant")
|
|
165276
|
+
return "A";
|
|
165277
|
+
return null;
|
|
165278
|
+
}
|
|
165279
|
+
function parseOrdinal(value) {
|
|
165280
|
+
const parsed = typeof value === "number" ? value : Number.parseInt(String(value ?? ""), 10);
|
|
165281
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : null;
|
|
165282
|
+
}
|
|
165283
|
+
function parseCanonicalLineRange(line) {
|
|
165284
|
+
const match = /^\[(\d+)(?:-(\d+))?\]\s+[UA]:/.exec(line.trim());
|
|
165285
|
+
if (!match)
|
|
165286
|
+
return null;
|
|
165287
|
+
const start = Number.parseInt(match[1], 10);
|
|
165288
|
+
const end = match[2] ? Number.parseInt(match[2], 10) : start;
|
|
165289
|
+
if (!Number.isFinite(start) || !Number.isFinite(end))
|
|
165290
|
+
return null;
|
|
165291
|
+
return { start, end };
|
|
165292
|
+
}
|
|
165293
|
+
function hashChunkText(text) {
|
|
165294
|
+
return createHash8("sha256").update(text).digest("hex");
|
|
165295
|
+
}
|
|
165296
|
+
function vectorBlob(vector) {
|
|
165297
|
+
return new Uint8Array(vector.buffer, vector.byteOffset, vector.byteLength);
|
|
165298
|
+
}
|
|
165299
|
+
function toFloat32Array2(blob) {
|
|
165300
|
+
if (blob instanceof Uint8Array) {
|
|
165301
|
+
const buffer2 = blob.buffer.slice(blob.byteOffset, blob.byteOffset + blob.byteLength);
|
|
165302
|
+
return new Float32Array(buffer2);
|
|
165303
|
+
}
|
|
165304
|
+
return new Float32Array(blob.slice(0));
|
|
165305
|
+
}
|
|
165306
|
+
function buildCanonicalChunkTextFromFts(db, sessionId, startOrdinal, endOrdinal) {
|
|
165307
|
+
if (endOrdinal < startOrdinal)
|
|
165308
|
+
return "";
|
|
165309
|
+
const rows = getLoadFtsRowsStatement(db).all(sessionId, startOrdinal, endOrdinal).map((row) => row);
|
|
165310
|
+
const lines = [];
|
|
165311
|
+
let current = null;
|
|
165312
|
+
const flush2 = () => {
|
|
165313
|
+
if (!current || current.parts.length === 0)
|
|
165314
|
+
return;
|
|
165315
|
+
lines.push(`${formatOrdinalRange(current.start, current.end)} ${current.role}: ${current.parts.join(" / ")}`);
|
|
165316
|
+
current = null;
|
|
165317
|
+
};
|
|
165318
|
+
for (const row of rows) {
|
|
165319
|
+
const ordinal = parseOrdinal(row.messageOrdinal);
|
|
165320
|
+
const prefix = rolePrefix(row.role);
|
|
165321
|
+
const content = typeof row.content === "string" ? normalizeContent(row.content) : "";
|
|
165322
|
+
if (ordinal === null || prefix === null || content.length === 0)
|
|
165323
|
+
continue;
|
|
165324
|
+
if (current && current.role === prefix) {
|
|
165325
|
+
current.end = ordinal;
|
|
165326
|
+
current.parts.push(content);
|
|
165327
|
+
continue;
|
|
165328
|
+
}
|
|
165329
|
+
flush2();
|
|
165330
|
+
current = { role: prefix, start: ordinal, end: ordinal, parts: [content] };
|
|
165331
|
+
}
|
|
165332
|
+
flush2();
|
|
165333
|
+
return lines.join(`
|
|
165334
|
+
`);
|
|
165335
|
+
}
|
|
165336
|
+
function canonicalizeInMemoryChunkTextForEmbedding(chunkText, startOrdinal, endOrdinal) {
|
|
165337
|
+
const lines = [];
|
|
165338
|
+
for (const rawLine of chunkText.split(/\r?\n/)) {
|
|
165339
|
+
const line = rawLine.trim();
|
|
165340
|
+
const match = /^(\[(\d+)(?:-(\d+))?\]\s+[UA]:)\s*(.*)$/.exec(line);
|
|
165341
|
+
if (!match)
|
|
165342
|
+
continue;
|
|
165343
|
+
const lineStart = Number.parseInt(match[2], 10);
|
|
165344
|
+
const lineEnd = match[3] ? Number.parseInt(match[3], 10) : lineStart;
|
|
165345
|
+
if (startOrdinal != null && lineEnd < startOrdinal)
|
|
165346
|
+
continue;
|
|
165347
|
+
if (endOrdinal != null && lineStart > endOrdinal)
|
|
165348
|
+
continue;
|
|
165349
|
+
const rawParts = match[4].split(" / ").map((part) => normalizeContent(part)).filter((part) => part.length > 0);
|
|
165350
|
+
const ordinalSpan = lineEnd - lineStart + 1;
|
|
165351
|
+
const roleLabel = match[1].slice(match[1].indexOf("]") + 2);
|
|
165352
|
+
if (ordinalSpan === rawParts.length) {
|
|
165353
|
+
const retained = rawParts.map((part, index) => ({ ordinal: lineStart + index, part })).filter(({ ordinal, part }) => {
|
|
165354
|
+
if (part.startsWith("TC:"))
|
|
165355
|
+
return false;
|
|
165356
|
+
if (startOrdinal != null && ordinal < startOrdinal)
|
|
165357
|
+
return false;
|
|
165358
|
+
if (endOrdinal != null && ordinal > endOrdinal)
|
|
165359
|
+
return false;
|
|
165360
|
+
return true;
|
|
165361
|
+
});
|
|
165362
|
+
if (retained.length === 0)
|
|
165363
|
+
continue;
|
|
165364
|
+
const retainedStart = retained[0].ordinal;
|
|
165365
|
+
const retainedEnd = retained[retained.length - 1].ordinal;
|
|
165366
|
+
lines.push(`${formatOrdinalRange(retainedStart, retainedEnd)} ${roleLabel} ${retained.map(({ part }) => part).join(" / ")}`);
|
|
165367
|
+
continue;
|
|
165368
|
+
}
|
|
165369
|
+
const parts = rawParts.filter((part) => !part.startsWith("TC:"));
|
|
165370
|
+
if (parts.length === 0)
|
|
165371
|
+
continue;
|
|
165372
|
+
lines.push(`${match[1]} ${parts.join(" / ")}`);
|
|
165373
|
+
}
|
|
165374
|
+
return lines.join(`
|
|
165375
|
+
`);
|
|
165376
|
+
}
|
|
165377
|
+
function chunkCanonicalText(canonicalText, startOrdinal, endOrdinal, maxInputTokens) {
|
|
165378
|
+
const lines = canonicalText.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
|
|
165379
|
+
if (lines.length === 0 || endOrdinal < startOrdinal)
|
|
165380
|
+
return [];
|
|
165381
|
+
const normalizedMax = normalizeCompartmentChunkMaxInputTokens(maxInputTokens);
|
|
165382
|
+
const effectiveMax = Math.max(1, Math.floor(normalizedMax * CHUNK_WINDOW_SAFETY_RATIO));
|
|
165383
|
+
const fullText = lines.join(`
|
|
165384
|
+
`);
|
|
165385
|
+
if (estimateTokens(fullText) <= effectiveMax) {
|
|
165386
|
+
return [
|
|
165387
|
+
{
|
|
165388
|
+
windowIndex: 0,
|
|
165389
|
+
startOrdinal,
|
|
165390
|
+
endOrdinal,
|
|
165391
|
+
text: fullText,
|
|
165392
|
+
chunkHash: hashChunkText(fullText)
|
|
165393
|
+
}
|
|
165394
|
+
];
|
|
165395
|
+
}
|
|
165396
|
+
const windows = [];
|
|
165397
|
+
let currentLines = [];
|
|
165398
|
+
let currentStart = null;
|
|
165399
|
+
let currentEnd = null;
|
|
165400
|
+
let currentTokens = 0;
|
|
165401
|
+
const flush2 = () => {
|
|
165402
|
+
if (currentLines.length === 0 || currentStart === null || currentEnd === null)
|
|
165403
|
+
return;
|
|
165404
|
+
const text = currentLines.join(`
|
|
165405
|
+
`);
|
|
165406
|
+
windows.push({
|
|
165407
|
+
windowIndex: windows.length + 1,
|
|
165408
|
+
startOrdinal: currentStart,
|
|
165409
|
+
endOrdinal: currentEnd,
|
|
165410
|
+
text,
|
|
165411
|
+
chunkHash: hashChunkText(text)
|
|
165412
|
+
});
|
|
165413
|
+
currentLines = [];
|
|
165414
|
+
currentStart = null;
|
|
165415
|
+
currentEnd = null;
|
|
165416
|
+
currentTokens = 0;
|
|
165417
|
+
};
|
|
165418
|
+
for (const line of lines) {
|
|
165419
|
+
const range = parseCanonicalLineRange(line);
|
|
165420
|
+
const lineStart = range?.start ?? startOrdinal;
|
|
165421
|
+
const lineEnd = range?.end ?? lineStart;
|
|
165422
|
+
const lineTokens = estimateTokens(line);
|
|
165423
|
+
if (currentLines.length > 0 && currentTokens + lineTokens > effectiveMax) {
|
|
165424
|
+
flush2();
|
|
165425
|
+
}
|
|
165426
|
+
if (currentLines.length === 0) {
|
|
165427
|
+
currentStart = lineStart;
|
|
165428
|
+
}
|
|
165429
|
+
currentLines.push(line);
|
|
165430
|
+
currentEnd = lineEnd;
|
|
165431
|
+
currentTokens += lineTokens;
|
|
165432
|
+
}
|
|
165433
|
+
flush2();
|
|
165434
|
+
return windows;
|
|
165435
|
+
}
|
|
165436
|
+
function getExistingChunkHashes(db, compartmentId, modelId, projectPath) {
|
|
165437
|
+
const scoped = typeof projectPath === "string" && projectPath.length > 0;
|
|
165438
|
+
const rows = scoped ? getExistingHashStatement(db, true).all(compartmentId, modelId, projectPath) : getExistingHashStatement(db, false).all(compartmentId, modelId);
|
|
165439
|
+
return new Map(rows.filter((row) => typeof row.windowIndex === "number" && typeof row.chunkHash === "string").map((row) => [row.windowIndex, row.chunkHash]));
|
|
165440
|
+
}
|
|
165441
|
+
function chunkEmbeddingWindowsAreCurrent(db, compartmentId, modelId, windows, projectPath) {
|
|
165442
|
+
const existing = getExistingChunkHashes(db, compartmentId, modelId, projectPath);
|
|
165443
|
+
if (existing.size !== windows.length)
|
|
165444
|
+
return false;
|
|
165445
|
+
return windows.every((window) => existing.get(window.windowIndex) === window.chunkHash);
|
|
165446
|
+
}
|
|
165447
|
+
function replaceCompartmentChunkEmbeddings(db, rows) {
|
|
165448
|
+
if (rows.length === 0)
|
|
165449
|
+
return;
|
|
165450
|
+
const compartmentId = rows[0].compartmentId;
|
|
165451
|
+
const now = Date.now();
|
|
165452
|
+
db.transaction(() => {
|
|
165453
|
+
getDeleteByCompartmentStatement(db).run(compartmentId);
|
|
165454
|
+
const insert = getInsertEmbeddingStatement(db);
|
|
165455
|
+
for (const row of rows) {
|
|
165456
|
+
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);
|
|
165457
|
+
}
|
|
165458
|
+
})();
|
|
165459
|
+
}
|
|
165460
|
+
function getDistinctChunkEmbeddingModelIds(db, projectPath) {
|
|
165461
|
+
const rows = getDistinctModelStatement(db).all(projectPath);
|
|
165462
|
+
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
165463
|
+
}
|
|
165464
|
+
function clearChunkEmbeddingsForProject(db, projectPath, modelId) {
|
|
165465
|
+
if (modelId) {
|
|
165466
|
+
return getClearProjectModelStatement(db).run(projectPath, modelId).changes;
|
|
165467
|
+
}
|
|
165468
|
+
return getClearProjectStatement(db).run(projectPath).changes;
|
|
165469
|
+
}
|
|
165470
|
+
function loadCompartmentChunkEmbeddingsForSearch(db, sessionId, projectPath, modelId) {
|
|
165471
|
+
const rows = modelId ? getSearchRowsStatement(db, true).all(sessionId, projectPath, modelId) : getSearchRowsStatement(db, false).all(sessionId, projectPath);
|
|
165472
|
+
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) => ({
|
|
165473
|
+
compartmentId: row.compartmentId,
|
|
165474
|
+
sessionId: row.sessionId,
|
|
165475
|
+
title: row.title,
|
|
165476
|
+
startOrdinal: row.compartmentStart,
|
|
165477
|
+
endOrdinal: row.compartmentEnd,
|
|
165478
|
+
windowIndex: row.windowIndex,
|
|
165479
|
+
windowStartOrdinal: row.windowStart,
|
|
165480
|
+
windowEndOrdinal: row.windowEnd,
|
|
165481
|
+
chunkHash: row.chunkHash,
|
|
165482
|
+
modelId: row.modelId,
|
|
165483
|
+
dims: row.dims,
|
|
165484
|
+
vector: toFloat32Array2(row.vector)
|
|
165485
|
+
}));
|
|
165486
|
+
}
|
|
165487
|
+
function mapBackfillCandidateRows(rows) {
|
|
165488
|
+
return rows.filter((row) => {
|
|
165489
|
+
if (row === null || typeof row !== "object")
|
|
165490
|
+
return false;
|
|
165491
|
+
const candidate = row;
|
|
165492
|
+
return typeof candidate.id === "number" && typeof candidate.sessionId === "string" && typeof candidate.startMessage === "number" && typeof candidate.endMessage === "number" && typeof candidate.title === "string";
|
|
165493
|
+
}).map((row) => ({
|
|
165494
|
+
id: row.id,
|
|
165495
|
+
sessionId: row.sessionId,
|
|
165496
|
+
startMessage: row.startMessage,
|
|
165497
|
+
endMessage: row.endMessage,
|
|
165498
|
+
title: row.title
|
|
165499
|
+
}));
|
|
165500
|
+
}
|
|
165501
|
+
function loadUnembeddedSessionChunkCandidates(db, projectPath, sessionId, modelId, limit, excludeIds) {
|
|
165502
|
+
if (excludeIds && excludeIds.length > 0) {
|
|
165503
|
+
const placeholders3 = excludeIds.map(() => "?").join(", ");
|
|
165504
|
+
const stmt2 = db.prepare(`SELECT c.id AS id,
|
|
165505
|
+
c.session_id AS sessionId,
|
|
165506
|
+
c.start_message AS startMessage,
|
|
165507
|
+
c.end_message AS endMessage,
|
|
165508
|
+
c.title AS title
|
|
165509
|
+
FROM compartments c
|
|
165510
|
+
JOIN session_projects sp
|
|
165511
|
+
ON sp.session_id = c.session_id
|
|
165512
|
+
AND sp.harness = c.harness
|
|
165513
|
+
AND sp.project_path = ?
|
|
165514
|
+
WHERE c.session_id = ?
|
|
165515
|
+
AND c.start_message IS NOT NULL
|
|
165516
|
+
AND c.end_message IS NOT NULL
|
|
165517
|
+
AND c.id NOT IN (${placeholders3})
|
|
165518
|
+
AND NOT EXISTS (
|
|
165519
|
+
SELECT 1
|
|
165520
|
+
FROM compartment_chunk_embeddings current
|
|
165521
|
+
WHERE current.compartment_id = c.id
|
|
165522
|
+
AND current.project_path = ?
|
|
165523
|
+
AND current.model_id = ?
|
|
165524
|
+
)
|
|
165525
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
165526
|
+
LIMIT ?`);
|
|
165527
|
+
const rows2 = stmt2.all(projectPath, sessionId, ...excludeIds, projectPath, modelId, Math.max(1, limit));
|
|
165528
|
+
return mapBackfillCandidateRows(rows2);
|
|
165529
|
+
}
|
|
165530
|
+
let stmt = sessionBackfillCandidateStatements.get(db);
|
|
165531
|
+
if (!stmt) {
|
|
165532
|
+
stmt = db.prepare(`SELECT c.id AS id,
|
|
165533
|
+
c.session_id AS sessionId,
|
|
165534
|
+
c.start_message AS startMessage,
|
|
165535
|
+
c.end_message AS endMessage,
|
|
165536
|
+
c.title AS title
|
|
165537
|
+
FROM compartments c
|
|
165538
|
+
JOIN session_projects sp
|
|
165539
|
+
ON sp.session_id = c.session_id
|
|
165540
|
+
AND sp.harness = c.harness
|
|
165541
|
+
AND sp.project_path = ?
|
|
165542
|
+
WHERE c.session_id = ?
|
|
165543
|
+
AND c.start_message IS NOT NULL
|
|
165544
|
+
AND c.end_message IS NOT NULL
|
|
165545
|
+
AND NOT EXISTS (
|
|
165546
|
+
SELECT 1
|
|
165547
|
+
FROM compartment_chunk_embeddings current
|
|
165548
|
+
WHERE current.compartment_id = c.id
|
|
165549
|
+
AND current.project_path = ?
|
|
165550
|
+
AND current.model_id = ?
|
|
165551
|
+
)
|
|
165552
|
+
ORDER BY c.start_message ASC, c.id ASC
|
|
165553
|
+
LIMIT ?`);
|
|
165554
|
+
sessionBackfillCandidateStatements.set(db, stmt);
|
|
165555
|
+
}
|
|
165556
|
+
const rows = stmt.all(projectPath, sessionId, projectPath, modelId, Math.max(1, limit));
|
|
165557
|
+
return mapBackfillCandidateRows(rows);
|
|
165558
|
+
}
|
|
165559
|
+
function countUnembeddedSessionCompartments(db, projectPath, sessionId, modelId) {
|
|
165560
|
+
const row = db.prepare(`SELECT COUNT(*) AS n
|
|
165561
|
+
FROM compartments c
|
|
165562
|
+
JOIN session_projects sp
|
|
165563
|
+
ON sp.session_id = c.session_id
|
|
165564
|
+
AND sp.harness = c.harness
|
|
165565
|
+
AND sp.project_path = ?
|
|
165566
|
+
WHERE c.session_id = ?
|
|
165567
|
+
AND c.start_message IS NOT NULL
|
|
165568
|
+
AND c.end_message IS NOT NULL
|
|
165569
|
+
AND NOT EXISTS (
|
|
165570
|
+
SELECT 1
|
|
165571
|
+
FROM compartment_chunk_embeddings current
|
|
165572
|
+
WHERE current.compartment_id = c.id
|
|
165573
|
+
AND current.project_path = ?
|
|
165574
|
+
AND current.model_id = ?
|
|
165575
|
+
)`).get(projectPath, sessionId, projectPath, modelId);
|
|
165576
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
165577
|
+
}
|
|
165578
|
+
var DEFAULT_COMPARTMENT_CHUNK_MAX_INPUT_TOKENS = 512, CHUNK_WINDOW_SAFETY_RATIO = 0.9, loadFtsRowsStatements, existingHashStatements, existingHashByProjectStatements, deleteByCompartmentStatements, insertEmbeddingStatements, distinctModelStatements, clearProjectStatements, clearProjectModelStatements, searchRowsStatements, searchRowsByModelStatements, backfillCandidateStatements, sessionBackfillCandidateStatements;
|
|
165579
|
+
var init_compartment_chunk_embedding = __esm(() => {
|
|
165580
|
+
init_read_session_formatting();
|
|
165581
|
+
loadFtsRowsStatements = new WeakMap;
|
|
165582
|
+
existingHashStatements = new WeakMap;
|
|
165583
|
+
existingHashByProjectStatements = new WeakMap;
|
|
165584
|
+
deleteByCompartmentStatements = new WeakMap;
|
|
165585
|
+
insertEmbeddingStatements = new WeakMap;
|
|
165586
|
+
distinctModelStatements = new WeakMap;
|
|
165587
|
+
clearProjectStatements = new WeakMap;
|
|
165588
|
+
clearProjectModelStatements = new WeakMap;
|
|
165589
|
+
searchRowsStatements = new WeakMap;
|
|
165590
|
+
searchRowsByModelStatements = new WeakMap;
|
|
165591
|
+
backfillCandidateStatements = new WeakMap;
|
|
165592
|
+
sessionBackfillCandidateStatements = new WeakMap;
|
|
165593
|
+
});
|
|
165594
|
+
|
|
164468
165595
|
// src/features/magic-context/memory/cosine-similarity.ts
|
|
164469
165596
|
function cosineSimilarity(a, b) {
|
|
164470
165597
|
if (a.length !== b.length) {
|
|
@@ -164622,19 +165749,19 @@ function isArrayLikeNumber(value) {
|
|
|
164622
165749
|
}
|
|
164623
165750
|
return arr.length === 0 || typeof arr[0] === "number";
|
|
164624
165751
|
}
|
|
164625
|
-
function
|
|
165752
|
+
function toFloat32Array3(values) {
|
|
164626
165753
|
return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
|
|
164627
165754
|
}
|
|
164628
165755
|
function extractBatchEmbeddings(result, expectedCount) {
|
|
164629
165756
|
const { data } = result;
|
|
164630
165757
|
if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
|
|
164631
|
-
return data.map((entry) =>
|
|
165758
|
+
return data.map((entry) => toFloat32Array3(entry));
|
|
164632
165759
|
}
|
|
164633
165760
|
if (!isArrayLikeNumber(data)) {
|
|
164634
165761
|
log("[magic-context] embedding batch returned unexpected data shape");
|
|
164635
165762
|
return Array.from({ length: expectedCount }, () => null);
|
|
164636
165763
|
}
|
|
164637
|
-
const flatData =
|
|
165764
|
+
const flatData = toFloat32Array3(data);
|
|
164638
165765
|
const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
|
|
164639
165766
|
if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
|
|
164640
165767
|
log("[magic-context] embedding batch returned invalid dimensions");
|
|
@@ -164649,6 +165776,7 @@ function extractBatchEmbeddings(result, expectedCount) {
|
|
|
164649
165776
|
|
|
164650
165777
|
class LocalEmbeddingProvider {
|
|
164651
165778
|
modelId;
|
|
165779
|
+
maxInputTokens;
|
|
164652
165780
|
model;
|
|
164653
165781
|
pipeline = null;
|
|
164654
165782
|
initPromise = null;
|
|
@@ -164656,8 +165784,9 @@ class LocalEmbeddingProvider {
|
|
|
164656
165784
|
disposing = false;
|
|
164657
165785
|
disposePromise = null;
|
|
164658
165786
|
inFlightWaiters = [];
|
|
164659
|
-
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL) {
|
|
165787
|
+
constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512) {
|
|
164660
165788
|
this.model = model;
|
|
165789
|
+
this.maxInputTokens = maxInputTokens;
|
|
164661
165790
|
this.modelId = getEmbeddingProviderIdentity({ provider: "local", model });
|
|
164662
165791
|
}
|
|
164663
165792
|
async initialize() {
|
|
@@ -164914,9 +166043,17 @@ var init_embedding_ssrf = __esm(() => {
|
|
|
164914
166043
|
function normalizeEndpoint3(endpoint) {
|
|
164915
166044
|
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
164916
166045
|
}
|
|
166046
|
+
function embeddingModelsMatch(served, requested) {
|
|
166047
|
+
const a = served.trim().toLowerCase();
|
|
166048
|
+
const b = requested.trim().toLowerCase();
|
|
166049
|
+
if (a.length === 0 || b.length === 0)
|
|
166050
|
+
return true;
|
|
166051
|
+
return a === b || a.includes(b) || b.includes(a);
|
|
166052
|
+
}
|
|
164917
166053
|
|
|
164918
166054
|
class OpenAICompatibleEmbeddingProvider {
|
|
164919
166055
|
modelId;
|
|
166056
|
+
maxInputTokens;
|
|
164920
166057
|
endpoint;
|
|
164921
166058
|
model;
|
|
164922
166059
|
apiKey;
|
|
@@ -164926,6 +166063,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164926
166063
|
failureTimes = [];
|
|
164927
166064
|
circuitOpenUntil = 0;
|
|
164928
166065
|
openLogged = false;
|
|
166066
|
+
modelMismatchLogged = false;
|
|
164929
166067
|
halfOpenProbeInFlight = false;
|
|
164930
166068
|
constructor(options) {
|
|
164931
166069
|
this.endpoint = normalizeEndpoint3(options.endpoint);
|
|
@@ -164933,11 +166071,13 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
164933
166071
|
this.apiKey = options.apiKey?.trim() ?? "";
|
|
164934
166072
|
this.inputType = options.inputType?.trim() ?? "";
|
|
164935
166073
|
this.truncate = options.truncate?.trim() ?? "";
|
|
166074
|
+
this.maxInputTokens = typeof options.maxInputTokens === "number" && Number.isFinite(options.maxInputTokens) ? Math.max(1, Math.floor(options.maxInputTokens)) : 512;
|
|
164936
166075
|
this.modelId = getEmbeddingProviderIdentity({
|
|
164937
166076
|
provider: "openai-compatible",
|
|
164938
166077
|
endpoint: this.endpoint,
|
|
164939
166078
|
model: this.model,
|
|
164940
|
-
...this.apiKey ? { api_key: this.apiKey } : {}
|
|
166079
|
+
...this.apiKey ? { api_key: this.apiKey } : {},
|
|
166080
|
+
...this.inputType ? { input_type: this.inputType } : {}
|
|
164941
166081
|
});
|
|
164942
166082
|
}
|
|
164943
166083
|
async initialize() {
|
|
@@ -165022,6 +166162,15 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
165022
166162
|
this.recordFailure(isProbe);
|
|
165023
166163
|
return Array.from({ length: texts.length }, () => null);
|
|
165024
166164
|
}
|
|
166165
|
+
const servedModel = typeof body.model === "string" ? body.model : "";
|
|
166166
|
+
if (this.model && servedModel && !embeddingModelsMatch(servedModel, this.model)) {
|
|
166167
|
+
if (!this.modelMismatchLogged) {
|
|
166168
|
+
log(`[magic-context] embedding endpoint served a DIFFERENT model than requested — refusing the substituted vectors (they have the wrong dimensions/space). requested="${this.model}" served="${servedModel}". The endpoint likely substituted a loaded model; load/select "${this.model}" on the endpoint, or set embedding.model to the served model.`);
|
|
166169
|
+
this.modelMismatchLogged = true;
|
|
166170
|
+
}
|
|
166171
|
+
this.recordFailure(isProbe);
|
|
166172
|
+
return Array.from({ length: texts.length }, () => null);
|
|
166173
|
+
}
|
|
165025
166174
|
const items = Array.isArray(body.data) ? body.data : [];
|
|
165026
166175
|
const results = Array.from({ length: texts.length }, (_, index) => {
|
|
165027
166176
|
const embedding = items[index]?.embedding;
|
|
@@ -165181,12 +166330,12 @@ function getCountEmbeddedStatement(db) {
|
|
|
165181
166330
|
}
|
|
165182
166331
|
return stmt;
|
|
165183
166332
|
}
|
|
165184
|
-
function
|
|
165185
|
-
let stmt =
|
|
166333
|
+
function getClearProjectStatement2(db) {
|
|
166334
|
+
let stmt = clearProjectStatements2.get(db);
|
|
165186
166335
|
if (!stmt) {
|
|
165187
166336
|
stmt = db.prepare(`DELETE FROM git_commit_embeddings
|
|
165188
166337
|
WHERE sha IN (SELECT sha FROM git_commits WHERE project_path = ?)`);
|
|
165189
|
-
|
|
166338
|
+
clearProjectStatements2.set(db, stmt);
|
|
165190
166339
|
}
|
|
165191
166340
|
return stmt;
|
|
165192
166341
|
}
|
|
@@ -165222,19 +166371,19 @@ function countEmbeddedCommits(db, projectPath) {
|
|
|
165222
166371
|
return row?.count ?? 0;
|
|
165223
166372
|
}
|
|
165224
166373
|
function clearProjectCommitEmbeddings(db, projectPath) {
|
|
165225
|
-
return
|
|
166374
|
+
return getClearProjectStatement2(db).run(projectPath).changes;
|
|
165226
166375
|
}
|
|
165227
166376
|
function getDistinctCommitEmbeddingModelIds(db, projectPath) {
|
|
165228
166377
|
const rows = getDistinctModelIdStatement(db).all(projectPath);
|
|
165229
166378
|
return new Set(rows.map((row) => typeof row.modelId === "string" ? row.modelId : null));
|
|
165230
166379
|
}
|
|
165231
|
-
var saveStatements, loadProjectStatements, loadUnembeddedStatements, countEmbeddedStatements,
|
|
166380
|
+
var saveStatements, loadProjectStatements, loadUnembeddedStatements, countEmbeddedStatements, clearProjectStatements2, distinctModelIdStatements;
|
|
165232
166381
|
var init_storage_git_commit_embeddings = __esm(() => {
|
|
165233
166382
|
saveStatements = new WeakMap;
|
|
165234
166383
|
loadProjectStatements = new WeakMap;
|
|
165235
166384
|
loadUnembeddedStatements = new WeakMap;
|
|
165236
166385
|
countEmbeddedStatements = new WeakMap;
|
|
165237
|
-
|
|
166386
|
+
clearProjectStatements2 = new WeakMap;
|
|
165238
166387
|
distinctModelIdStatements = new WeakMap;
|
|
165239
166388
|
});
|
|
165240
166389
|
|
|
@@ -165360,13 +166509,90 @@ var init_sweep_coordinator = __esm(() => {
|
|
|
165360
166509
|
GIT_SWEEP_LEASE_RENEWAL_MS = 60 * 1000;
|
|
165361
166510
|
});
|
|
165362
166511
|
|
|
166512
|
+
// src/features/magic-context/session-project-storage.ts
|
|
166513
|
+
function getUpsertSessionProjectStatement(db) {
|
|
166514
|
+
let stmt = upsertSessionProjectStatements.get(db);
|
|
166515
|
+
if (!stmt) {
|
|
166516
|
+
stmt = db.prepare(`INSERT INTO session_projects (session_id, harness, project_path, updated_at)
|
|
166517
|
+
VALUES (?, ?, ?, ?)
|
|
166518
|
+
ON CONFLICT(session_id, harness) DO UPDATE SET
|
|
166519
|
+
project_path = excluded.project_path,
|
|
166520
|
+
updated_at = excluded.updated_at
|
|
166521
|
+
WHERE session_projects.project_path <> excluded.project_path`);
|
|
166522
|
+
upsertSessionProjectStatements.set(db, stmt);
|
|
166523
|
+
}
|
|
166524
|
+
return stmt;
|
|
166525
|
+
}
|
|
166526
|
+
function getRepairSessionChunkProjectStatement(db) {
|
|
166527
|
+
let stmt = repairSessionChunkProjectStatements.get(db);
|
|
166528
|
+
if (!stmt) {
|
|
166529
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
166530
|
+
SET project_path = ?
|
|
166531
|
+
WHERE session_id = ?
|
|
166532
|
+
AND harness = ?
|
|
166533
|
+
AND project_path <> ?`);
|
|
166534
|
+
repairSessionChunkProjectStatements.set(db, stmt);
|
|
166535
|
+
}
|
|
166536
|
+
return stmt;
|
|
166537
|
+
}
|
|
166538
|
+
function getRepairProjectChunkProjectStatement(db) {
|
|
166539
|
+
let stmt = repairProjectChunkProjectStatements.get(db);
|
|
166540
|
+
if (!stmt) {
|
|
166541
|
+
stmt = db.prepare(`UPDATE compartment_chunk_embeddings
|
|
166542
|
+
SET project_path = (
|
|
166543
|
+
SELECT sp.project_path
|
|
166544
|
+
FROM session_projects sp
|
|
166545
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
166546
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
166547
|
+
LIMIT 1
|
|
166548
|
+
)
|
|
166549
|
+
WHERE EXISTS (
|
|
166550
|
+
SELECT 1
|
|
166551
|
+
FROM session_projects sp
|
|
166552
|
+
WHERE sp.session_id = compartment_chunk_embeddings.session_id
|
|
166553
|
+
AND sp.harness = compartment_chunk_embeddings.harness
|
|
166554
|
+
AND sp.project_path <> compartment_chunk_embeddings.project_path
|
|
166555
|
+
AND (
|
|
166556
|
+
sp.project_path = ?
|
|
166557
|
+
OR compartment_chunk_embeddings.project_path = ?
|
|
166558
|
+
)
|
|
166559
|
+
)`);
|
|
166560
|
+
repairProjectChunkProjectStatements.set(db, stmt);
|
|
166561
|
+
}
|
|
166562
|
+
return stmt;
|
|
166563
|
+
}
|
|
166564
|
+
function recordSessionProjectIdentity(db, sessionId, projectPath) {
|
|
166565
|
+
if (!sessionId || !projectPath)
|
|
166566
|
+
return;
|
|
166567
|
+
const harness = getHarness();
|
|
166568
|
+
const now = Date.now();
|
|
166569
|
+
db.transaction(() => {
|
|
166570
|
+
getUpsertSessionProjectStatement(db).run(sessionId, harness, projectPath, now);
|
|
166571
|
+
getRepairSessionChunkProjectStatement(db).run(projectPath, sessionId, harness, projectPath);
|
|
166572
|
+
})();
|
|
166573
|
+
}
|
|
166574
|
+
function repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectPath) {
|
|
166575
|
+
if (!projectPath)
|
|
166576
|
+
return 0;
|
|
166577
|
+
return getRepairProjectChunkProjectStatement(db).run(projectPath, projectPath).changes;
|
|
166578
|
+
}
|
|
166579
|
+
var upsertSessionProjectStatements, repairSessionChunkProjectStatements, repairProjectChunkProjectStatements;
|
|
166580
|
+
var init_session_project_storage = __esm(() => {
|
|
166581
|
+
upsertSessionProjectStatements = new WeakMap;
|
|
166582
|
+
repairSessionChunkProjectStatements = new WeakMap;
|
|
166583
|
+
repairProjectChunkProjectStatements = new WeakMap;
|
|
166584
|
+
});
|
|
166585
|
+
|
|
165363
166586
|
// src/features/magic-context/project-embedding-registry.ts
|
|
165364
|
-
import { createHash as
|
|
166587
|
+
import { createHash as createHash9, randomUUID } from "node:crypto";
|
|
165365
166588
|
function resolveEmbeddingConfig(config2) {
|
|
165366
166589
|
if (!config2 || config2.provider === "local") {
|
|
165367
166590
|
return {
|
|
165368
166591
|
provider: "local",
|
|
165369
|
-
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL
|
|
166592
|
+
model: config2?.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
|
|
166593
|
+
...config2?.max_input_tokens ? {
|
|
166594
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
166595
|
+
} : {}
|
|
165370
166596
|
};
|
|
165371
166597
|
}
|
|
165372
166598
|
if (config2.provider === "openai-compatible") {
|
|
@@ -165379,7 +166605,10 @@ function resolveEmbeddingConfig(config2) {
|
|
|
165379
166605
|
endpoint: config2.endpoint.trim(),
|
|
165380
166606
|
...apiKey ? { api_key: apiKey } : {},
|
|
165381
166607
|
...inputType ? { input_type: inputType } : {},
|
|
165382
|
-
...truncate ? { truncate } : {}
|
|
166608
|
+
...truncate ? { truncate } : {},
|
|
166609
|
+
...config2.max_input_tokens ? {
|
|
166610
|
+
max_input_tokens: normalizeCompartmentChunkMaxInputTokens(config2.max_input_tokens)
|
|
166611
|
+
} : {}
|
|
165383
166612
|
};
|
|
165384
166613
|
}
|
|
165385
166614
|
return { provider: "off" };
|
|
@@ -165397,10 +166626,11 @@ function createProvider(config2) {
|
|
|
165397
166626
|
model: config2.model,
|
|
165398
166627
|
apiKey: config2.api_key,
|
|
165399
166628
|
inputType: config2.input_type,
|
|
165400
|
-
truncate: config2.truncate
|
|
166629
|
+
truncate: config2.truncate,
|
|
166630
|
+
maxInputTokens: config2.max_input_tokens
|
|
165401
166631
|
});
|
|
165402
166632
|
}
|
|
165403
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
166633
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
165404
166634
|
}
|
|
165405
166635
|
function stableStringify2(value) {
|
|
165406
166636
|
if (Array.isArray(value)) {
|
|
@@ -165413,7 +166643,7 @@ function stableStringify2(value) {
|
|
|
165413
166643
|
return JSON.stringify(value);
|
|
165414
166644
|
}
|
|
165415
166645
|
function sha256Prefix(value, length = 16) {
|
|
165416
|
-
return
|
|
166646
|
+
return createHash9("sha256").update(value).digest("hex").slice(0, length);
|
|
165417
166647
|
}
|
|
165418
166648
|
function getRuntimeFingerprint(config2) {
|
|
165419
166649
|
if (config2.provider === "off") {
|
|
@@ -165421,6 +166651,18 @@ function getRuntimeFingerprint(config2) {
|
|
|
165421
166651
|
}
|
|
165422
166652
|
return `${getEmbeddingProviderIdentity(config2)}:${sha256Prefix(stableStringify2(config2))}`;
|
|
165423
166653
|
}
|
|
166654
|
+
function getChunkEmbeddingModelId(config2, providerIdentity) {
|
|
166655
|
+
if (config2.provider === "off") {
|
|
166656
|
+
return OFF_PROVIDER_IDENTITY;
|
|
166657
|
+
}
|
|
166658
|
+
const chunkIdentity = {
|
|
166659
|
+
providerIdentity,
|
|
166660
|
+
chunkerVersion: 2,
|
|
166661
|
+
maxInputTokens: normalizeCompartmentChunkMaxInputTokens("max_input_tokens" in config2 ? config2.max_input_tokens : undefined),
|
|
166662
|
+
truncate: config2.provider === "openai-compatible" ? config2.truncate ?? "" : ""
|
|
166663
|
+
};
|
|
166664
|
+
return `${providerIdentity}:chunk:${sha256Prefix(stableStringify2(chunkIdentity))}`;
|
|
166665
|
+
}
|
|
165424
166666
|
function sameFeatures(a, b) {
|
|
165425
166667
|
return a.memoryEnabled === b.memoryEnabled && a.gitCommitEnabled === b.gitCommitEnabled;
|
|
165426
166668
|
}
|
|
@@ -165437,7 +166679,8 @@ function snapshotFor(registration) {
|
|
|
165437
166679
|
features: { ...registration.features },
|
|
165438
166680
|
enabled,
|
|
165439
166681
|
gitCommitEnabled,
|
|
165440
|
-
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId
|
|
166682
|
+
modelId: registration.observationMode || !providerIsOn ? "off" : registration.modelId,
|
|
166683
|
+
chunkModelId: registration.observationMode || !providerIsOn ? "off" : registration.chunkModelId
|
|
165441
166684
|
};
|
|
165442
166685
|
}
|
|
165443
166686
|
function disposeProvider(provider) {
|
|
@@ -165457,7 +166700,7 @@ function anyStoredModelIdIsStale(storedIds, currentId) {
|
|
|
165457
166700
|
}
|
|
165458
166701
|
return false;
|
|
165459
166702
|
}
|
|
165460
|
-
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, features) {
|
|
166703
|
+
function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity, currentChunkIdentity, features) {
|
|
165461
166704
|
if (currentProviderIdentity === OFF_PROVIDER_IDENTITY) {
|
|
165462
166705
|
return false;
|
|
165463
166706
|
}
|
|
@@ -165478,6 +166721,14 @@ function maybeWipeStaleEmbeddings(db, projectIdentity, currentProviderIdentity,
|
|
|
165478
166721
|
wiped = true;
|
|
165479
166722
|
}
|
|
165480
166723
|
}
|
|
166724
|
+
if (features.memoryEnabled) {
|
|
166725
|
+
repairMisScopedCompartmentChunkEmbeddingsForProject(db, projectIdentity);
|
|
166726
|
+
const chunkIds = getDistinctChunkEmbeddingModelIds(db, projectIdentity);
|
|
166727
|
+
if (anyStoredModelIdIsStale(chunkIds, currentChunkIdentity)) {
|
|
166728
|
+
clearChunkEmbeddingsForProject(db, projectIdentity);
|
|
166729
|
+
wiped = true;
|
|
166730
|
+
}
|
|
166731
|
+
}
|
|
165481
166732
|
})();
|
|
165482
166733
|
return wiped;
|
|
165483
166734
|
}
|
|
@@ -165485,10 +166736,11 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
165485
166736
|
const resolvedConfig = resolveEmbeddingConfig(config2);
|
|
165486
166737
|
const providerIdentity = getEmbeddingProviderIdentity(resolvedConfig);
|
|
165487
166738
|
const runtimeFingerprint = getRuntimeFingerprint(resolvedConfig);
|
|
166739
|
+
const chunkModelId = getChunkEmbeddingModelId(resolvedConfig, providerIdentity);
|
|
165488
166740
|
const prior = projectRegistrations.get(projectIdentity);
|
|
165489
166741
|
const canReuseProvider = prior !== undefined && !prior.observationMode && prior.runtimeFingerprint === runtimeFingerprint && prior.providerIdentity === providerIdentity;
|
|
165490
|
-
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, features);
|
|
165491
|
-
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || !sameFeatures(prior.features, features) || wiped;
|
|
166742
|
+
const wiped = maybeWipeStaleEmbeddings(db, projectIdentity, providerIdentity, chunkModelId, features);
|
|
166743
|
+
const generationChanged = prior === undefined || prior.observationMode || prior.runtimeFingerprint !== runtimeFingerprint || prior.chunkModelId !== chunkModelId || !sameFeatures(prior.features, features) || wiped;
|
|
165492
166744
|
const generation = generationChanged ? ++globalRegistrationGeneration : prior.generation;
|
|
165493
166745
|
const registration = {
|
|
165494
166746
|
projectIdentity,
|
|
@@ -165500,6 +166752,7 @@ function registerProjectEmbeddingAndMaybeWipe(db, projectIdentity, config2, feat
|
|
|
165500
166752
|
generation,
|
|
165501
166753
|
features: { ...features },
|
|
165502
166754
|
modelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : providerIdentity,
|
|
166755
|
+
chunkModelId: providerIdentity === OFF_PROVIDER_IDENTITY ? "off" : chunkModelId,
|
|
165503
166756
|
observationMode: false
|
|
165504
166757
|
};
|
|
165505
166758
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -165522,6 +166775,7 @@ function registerProjectInObservationMode(db, projectIdentity, sourceDirectory,
|
|
|
165522
166775
|
generation,
|
|
165523
166776
|
features: { memoryEnabled: false, gitCommitEnabled: false },
|
|
165524
166777
|
modelId: "off",
|
|
166778
|
+
chunkModelId: "off",
|
|
165525
166779
|
observationMode: true
|
|
165526
166780
|
};
|
|
165527
166781
|
projectRegistrations.set(projectIdentity, registration);
|
|
@@ -165532,6 +166786,15 @@ function getProjectEmbeddingSnapshot(projectIdentity) {
|
|
|
165532
166786
|
const registration = projectRegistrations.get(projectIdentity);
|
|
165533
166787
|
return registration ? snapshotFor(registration) : null;
|
|
165534
166788
|
}
|
|
166789
|
+
function getProjectChunkEmbeddingModelId(projectIdentity) {
|
|
166790
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
166791
|
+
return registration && !registration.observationMode ? registration.chunkModelId : "off";
|
|
166792
|
+
}
|
|
166793
|
+
function getProjectEmbeddingMaxInputTokens(projectIdentity) {
|
|
166794
|
+
const registration = projectRegistrations.get(projectIdentity);
|
|
166795
|
+
const configMax = registration?.config && "max_input_tokens" in registration.config ? registration.config.max_input_tokens : undefined;
|
|
166796
|
+
return normalizeCompartmentChunkMaxInputTokens(registration?.provider?.maxInputTokens ?? configMax);
|
|
166797
|
+
}
|
|
165535
166798
|
function getOrCreateProjectProvider(registration) {
|
|
165536
166799
|
if (registration.providerIdentity === OFF_PROVIDER_IDENTITY || registration.observationMode) {
|
|
165537
166800
|
return null;
|
|
@@ -165626,10 +166889,136 @@ async function embedUnembeddedMemoriesForProject(db, projectIdentity, batchSize
|
|
|
165626
166889
|
return 0;
|
|
165627
166890
|
}
|
|
165628
166891
|
}
|
|
165629
|
-
|
|
166892
|
+
async function embedCandidateChunkBatch(db, projectIdentity, modelId, candidates, signal) {
|
|
166893
|
+
const noWork = [];
|
|
166894
|
+
if (candidates.length === 0)
|
|
166895
|
+
return { embedded: 0, noWork };
|
|
166896
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectIdentity);
|
|
166897
|
+
const prepared = [];
|
|
166898
|
+
for (const candidate of candidates) {
|
|
166899
|
+
const canonicalText = buildCanonicalChunkTextFromFts(db, candidate.sessionId, candidate.startMessage, candidate.endMessage);
|
|
166900
|
+
if (canonicalText.length === 0) {
|
|
166901
|
+
noWork.push(candidate.id);
|
|
166902
|
+
continue;
|
|
166903
|
+
}
|
|
166904
|
+
const windows = chunkCanonicalText(canonicalText, candidate.startMessage, candidate.endMessage, maxInputTokens);
|
|
166905
|
+
if (windows.length === 0 || chunkEmbeddingWindowsAreCurrent(db, candidate.id, modelId, windows, projectIdentity)) {
|
|
166906
|
+
noWork.push(candidate.id);
|
|
166907
|
+
continue;
|
|
166908
|
+
}
|
|
166909
|
+
prepared.push({ candidate, windows });
|
|
166910
|
+
}
|
|
166911
|
+
if (prepared.length === 0)
|
|
166912
|
+
return { embedded: 0, noWork };
|
|
166913
|
+
let embedded = 0;
|
|
166914
|
+
let i = 0;
|
|
166915
|
+
while (i < prepared.length) {
|
|
166916
|
+
if (signal?.aborted)
|
|
166917
|
+
break;
|
|
166918
|
+
const slice = [];
|
|
166919
|
+
let windowCount = 0;
|
|
166920
|
+
do {
|
|
166921
|
+
const item = prepared[i];
|
|
166922
|
+
slice.push(item);
|
|
166923
|
+
windowCount += item.windows.length;
|
|
166924
|
+
i += 1;
|
|
166925
|
+
} while (i < prepared.length && windowCount + prepared[i].windows.length <= MAX_WINDOWS_PER_EMBED_CALL);
|
|
166926
|
+
const texts = [];
|
|
166927
|
+
for (const item of slice)
|
|
166928
|
+
texts.push(...item.windows.map((w) => w.text));
|
|
166929
|
+
try {
|
|
166930
|
+
const result = await embedBatchForProject(projectIdentity, texts, signal);
|
|
166931
|
+
if (!result)
|
|
166932
|
+
continue;
|
|
166933
|
+
if (signal?.aborted)
|
|
166934
|
+
break;
|
|
166935
|
+
let offset = 0;
|
|
166936
|
+
for (const item of slice) {
|
|
166937
|
+
const vectors = result.vectors.slice(offset, offset + item.windows.length);
|
|
166938
|
+
offset += item.windows.length;
|
|
166939
|
+
if (vectors.length !== item.windows.length || vectors.some((v) => !v)) {
|
|
166940
|
+
continue;
|
|
166941
|
+
}
|
|
166942
|
+
const rows = item.windows.map((window, index) => ({
|
|
166943
|
+
compartmentId: item.candidate.id,
|
|
166944
|
+
sessionId: item.candidate.sessionId,
|
|
166945
|
+
projectPath: projectIdentity,
|
|
166946
|
+
window,
|
|
166947
|
+
modelId,
|
|
166948
|
+
vector: vectors[index]
|
|
166949
|
+
}));
|
|
166950
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
166951
|
+
embedded += 1;
|
|
166952
|
+
}
|
|
166953
|
+
} catch (error51) {
|
|
166954
|
+
log("[magic-context] failed to proactively embed compartment chunks:", error51);
|
|
166955
|
+
}
|
|
166956
|
+
}
|
|
166957
|
+
return { embedded, noWork };
|
|
166958
|
+
}
|
|
166959
|
+
async function embedSessionCompartmentChunks(db, projectIdentity, sessionId, options) {
|
|
166960
|
+
const snapshot = getProjectEmbeddingSnapshot(projectIdentity);
|
|
166961
|
+
if (!snapshot?.enabled || snapshot.chunkModelId === "off") {
|
|
166962
|
+
return { status: "disabled", embedded: 0, total: 0 };
|
|
166963
|
+
}
|
|
166964
|
+
recordSessionProjectIdentity(db, sessionId, projectIdentity);
|
|
166965
|
+
const total = countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId);
|
|
166966
|
+
if (total === 0)
|
|
166967
|
+
return { status: "nothing", embedded: 0, total: 0 };
|
|
166968
|
+
const holderId = `session-embed-${randomUUID()}`;
|
|
166969
|
+
const lease2 = acquireGitSweepLease(db, projectIdentity, holderId, { ignoreCooldown: true });
|
|
166970
|
+
if (!lease2.acquired)
|
|
166971
|
+
return { status: "busy", embedded: 0, total };
|
|
166972
|
+
const renewal = setInterval(() => {
|
|
166973
|
+
try {
|
|
166974
|
+
renewGitSweepLease(db, projectIdentity, holderId);
|
|
166975
|
+
} catch {}
|
|
166976
|
+
}, SESSION_EMBED_LEASE_RENEWAL_MS);
|
|
166977
|
+
renewal.unref?.();
|
|
166978
|
+
const batchSize = Math.max(1, options?.batchSize ?? CHUNK_DRAIN_BATCH_SIZE);
|
|
166979
|
+
const skipIds = [];
|
|
166980
|
+
let embedded = 0;
|
|
166981
|
+
let aborted2 = false;
|
|
166982
|
+
let providerStalled = false;
|
|
166983
|
+
try {
|
|
166984
|
+
options?.onProgress?.({ embedded, total });
|
|
166985
|
+
for (;; ) {
|
|
166986
|
+
if (options?.signal?.aborted) {
|
|
166987
|
+
aborted2 = true;
|
|
166988
|
+
break;
|
|
166989
|
+
}
|
|
166990
|
+
const candidates = loadUnembeddedSessionChunkCandidates(db, projectIdentity, sessionId, snapshot.chunkModelId, batchSize, skipIds);
|
|
166991
|
+
if (candidates.length === 0)
|
|
166992
|
+
break;
|
|
166993
|
+
const { embedded: n, noWork } = await embedCandidateChunkBatch(db, projectIdentity, snapshot.chunkModelId, candidates, options?.signal);
|
|
166994
|
+
for (const id of noWork)
|
|
166995
|
+
skipIds.push(id);
|
|
166996
|
+
if (n === 0 && noWork.length === 0) {
|
|
166997
|
+
providerStalled = true;
|
|
166998
|
+
break;
|
|
166999
|
+
}
|
|
167000
|
+
embedded += n;
|
|
167001
|
+
options?.onProgress?.({ embedded: Math.min(embedded, total), total });
|
|
167002
|
+
await new Promise((resolve6) => setTimeout(resolve6, 0));
|
|
167003
|
+
}
|
|
167004
|
+
} finally {
|
|
167005
|
+
clearInterval(renewal);
|
|
167006
|
+
releaseGitSweepLease(db, projectIdentity, holderId);
|
|
167007
|
+
}
|
|
167008
|
+
if (aborted2)
|
|
167009
|
+
return { status: "aborted", embedded, total };
|
|
167010
|
+
if (providerStalled) {
|
|
167011
|
+
const remaining = Math.max(0, countUnembeddedSessionCompartments(db, projectIdentity, sessionId, snapshot.chunkModelId) - skipIds.length);
|
|
167012
|
+
if (remaining > 0)
|
|
167013
|
+
return { status: "stalled", embedded, total, remaining };
|
|
167014
|
+
}
|
|
167015
|
+
return { status: "done", embedded, total };
|
|
167016
|
+
}
|
|
167017
|
+
var OFF_PROVIDER_IDENTITY = "embedding-provider:off", SWEEP_MAX_WALL_CLOCK_MS, CHUNK_DRAIN_BATCH_SIZE = 8, MAX_WINDOWS_PER_EMBED_CALL = 16, SESSION_EMBED_LEASE_RENEWAL_MS, projectRegistrations, loadUnembeddedMemoriesStatements, globalRegistrationGeneration = 0, testProviderFactory = null;
|
|
165630
167018
|
var init_project_embedding_registry = __esm(() => {
|
|
165631
167019
|
init_magic_context();
|
|
165632
167020
|
init_logger();
|
|
167021
|
+
init_compartment_chunk_embedding();
|
|
165633
167022
|
init_storage_git_commit_embeddings();
|
|
165634
167023
|
init_sweep_coordinator();
|
|
165635
167024
|
init_embedding_cache();
|
|
@@ -165637,7 +167026,9 @@ var init_project_embedding_registry = __esm(() => {
|
|
|
165637
167026
|
init_embedding_local();
|
|
165638
167027
|
init_embedding_openai();
|
|
165639
167028
|
init_storage_memory_embeddings();
|
|
167029
|
+
init_session_project_storage();
|
|
165640
167030
|
SWEEP_MAX_WALL_CLOCK_MS = 10 * 60 * 1000;
|
|
167031
|
+
SESSION_EMBED_LEASE_RENEWAL_MS = 60 * 1000;
|
|
165641
167032
|
projectRegistrations = new Map;
|
|
165642
167033
|
loadUnembeddedMemoriesStatements = new WeakMap;
|
|
165643
167034
|
});
|
|
@@ -165653,10 +167044,11 @@ function createProvider2(config2) {
|
|
|
165653
167044
|
model: config2.model,
|
|
165654
167045
|
apiKey: config2.api_key,
|
|
165655
167046
|
inputType: config2.input_type,
|
|
165656
|
-
truncate: config2.truncate
|
|
167047
|
+
truncate: config2.truncate,
|
|
167048
|
+
maxInputTokens: config2.max_input_tokens
|
|
165657
167049
|
});
|
|
165658
167050
|
}
|
|
165659
|
-
return new LocalEmbeddingProvider(config2.model);
|
|
167051
|
+
return new LocalEmbeddingProvider(config2.model, config2.max_input_tokens);
|
|
165660
167052
|
}
|
|
165661
167053
|
function getOrCreateProvider() {
|
|
165662
167054
|
if (provider) {
|
|
@@ -165682,6 +167074,7 @@ var DEFAULT_EMBEDDING_CONFIG, embeddingConfig, provider = null, loadUnembeddedMe
|
|
|
165682
167074
|
var init_embedding = __esm(() => {
|
|
165683
167075
|
init_magic_context();
|
|
165684
167076
|
init_logger();
|
|
167077
|
+
init_compartment_chunk_embedding();
|
|
165685
167078
|
init_embedding_identity();
|
|
165686
167079
|
init_embedding_local();
|
|
165687
167080
|
init_embedding_openai();
|
|
@@ -165705,6 +167098,23 @@ function getSearchStatement(db) {
|
|
|
165705
167098
|
}
|
|
165706
167099
|
return stmt;
|
|
165707
167100
|
}
|
|
167101
|
+
function getUnionSearchStatement(db, arity) {
|
|
167102
|
+
let statements = unionSearchStatements.get(arity);
|
|
167103
|
+
if (!statements) {
|
|
167104
|
+
statements = new WeakMap;
|
|
167105
|
+
unionSearchStatements.set(arity, statements);
|
|
167106
|
+
}
|
|
167107
|
+
let stmt = statements.get(db);
|
|
167108
|
+
if (!stmt) {
|
|
167109
|
+
const placeholders3 = Array.from({ length: arity }, () => "?").join(", ");
|
|
167110
|
+
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 ?`);
|
|
167111
|
+
statements.set(db, stmt);
|
|
167112
|
+
}
|
|
167113
|
+
return stmt;
|
|
167114
|
+
}
|
|
167115
|
+
function uniqueProjectPaths2(projectPaths) {
|
|
167116
|
+
return [...new Set(projectPaths.filter((path6) => path6.length > 0))];
|
|
167117
|
+
}
|
|
165708
167118
|
function sanitizeFtsQuery(query) {
|
|
165709
167119
|
const tokens = query.split(/\s+/).filter((token) => token.length > 0);
|
|
165710
167120
|
if (tokens.length === 0)
|
|
@@ -165723,10 +167133,33 @@ function searchMemoriesFTS(db, projectPath, query, limit = DEFAULT_SEARCH_LIMIT)
|
|
|
165723
167133
|
const rows = getSearchStatement(db).all(projectPath, Date.now(), sanitized, limit).filter(isMemoryRow);
|
|
165724
167134
|
return rows.map(toMemory);
|
|
165725
167135
|
}
|
|
165726
|
-
|
|
167136
|
+
function searchMemoriesFTSUnion(db, projectPaths, query, limit = DEFAULT_SEARCH_LIMIT, ownIdentities, shareCategories) {
|
|
167137
|
+
const identities = uniqueProjectPaths2(projectPaths);
|
|
167138
|
+
if (identities.length === 0)
|
|
167139
|
+
return [];
|
|
167140
|
+
const sharingFilter = buildWorkspaceMemorySqlFilter({
|
|
167141
|
+
identities,
|
|
167142
|
+
ownIdentities,
|
|
167143
|
+
shareCategories,
|
|
167144
|
+
tableName: "memories"
|
|
167145
|
+
});
|
|
167146
|
+
if (identities.length === 1 && !sharingFilter.active) {
|
|
167147
|
+
return searchMemoriesFTS(db, identities[0], query, limit);
|
|
167148
|
+
}
|
|
167149
|
+
const trimmedQuery = query.trim();
|
|
167150
|
+
if (trimmedQuery.length === 0 || limit <= 0)
|
|
167151
|
+
return [];
|
|
167152
|
+
const sanitized = sanitizeFtsQuery(trimmedQuery);
|
|
167153
|
+
if (sanitized.length === 0)
|
|
167154
|
+
return [];
|
|
167155
|
+
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);
|
|
167156
|
+
return rows.map(toMemory);
|
|
167157
|
+
}
|
|
167158
|
+
var DEFAULT_SEARCH_LIMIT = 10, searchStatements, unionSearchStatements;
|
|
165727
167159
|
var init_storage_memory_fts = __esm(() => {
|
|
165728
167160
|
init_storage_memory();
|
|
165729
167161
|
searchStatements = new WeakMap;
|
|
167162
|
+
unionSearchStatements = new Map;
|
|
165730
167163
|
});
|
|
165731
167164
|
|
|
165732
167165
|
// src/shared/models-dev-cache.ts
|
|
@@ -165920,26 +167353,54 @@ var init_rpc_notifications = __esm(() => {
|
|
|
165920
167353
|
});
|
|
165921
167354
|
|
|
165922
167355
|
// src/features/magic-context/compartment-embedding.ts
|
|
165923
|
-
async function
|
|
167356
|
+
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
165924
167357
|
if (compartments.length === 0)
|
|
165925
167358
|
return;
|
|
165926
|
-
const
|
|
165927
|
-
for (const
|
|
165928
|
-
if (!c.p1 || c.p1.length === 0)
|
|
165929
|
-
continue;
|
|
167359
|
+
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
167360
|
+
for (const compartment of compartments) {
|
|
165930
167361
|
try {
|
|
165931
|
-
const
|
|
165932
|
-
|
|
165933
|
-
|
|
165934
|
-
|
|
167362
|
+
const fromMemory = compartment.sourceChunkText ? canonicalizeInMemoryChunkTextForEmbedding(compartment.sourceChunkText, compartment.startMessage, compartment.endMessage) : "";
|
|
167363
|
+
const canonicalText = fromMemory || buildCanonicalChunkTextFromFts(db, sessionId, compartment.startMessage, compartment.endMessage);
|
|
167364
|
+
if (canonicalText.length === 0)
|
|
167365
|
+
continue;
|
|
167366
|
+
const windows = chunkCanonicalText(canonicalText, compartment.startMessage, compartment.endMessage, maxInputTokens);
|
|
167367
|
+
if (windows.length === 0)
|
|
167368
|
+
continue;
|
|
167369
|
+
const currentModelId = getProjectChunkEmbeddingModelId(projectPath);
|
|
167370
|
+
if (currentModelId !== "off" && chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
167371
|
+
continue;
|
|
167372
|
+
}
|
|
167373
|
+
const result = await embedBatchForProject(projectPath, windows.map((window) => window.text));
|
|
167374
|
+
if (!result)
|
|
167375
|
+
continue;
|
|
167376
|
+
if (chunkEmbeddingWindowsAreCurrent(db, compartment.id, currentModelId, windows, projectPath)) {
|
|
167377
|
+
continue;
|
|
167378
|
+
}
|
|
167379
|
+
const rows = [];
|
|
167380
|
+
for (const [index, window] of windows.entries()) {
|
|
167381
|
+
const vector = result.vectors[index];
|
|
167382
|
+
if (!vector)
|
|
167383
|
+
continue;
|
|
167384
|
+
rows.push({
|
|
167385
|
+
compartmentId: compartment.id,
|
|
167386
|
+
sessionId,
|
|
167387
|
+
projectPath,
|
|
167388
|
+
window,
|
|
167389
|
+
modelId: currentModelId,
|
|
167390
|
+
vector
|
|
167391
|
+
});
|
|
167392
|
+
}
|
|
167393
|
+
if (rows.length === windows.length) {
|
|
167394
|
+
replaceCompartmentChunkEmbeddings(db, rows);
|
|
165935
167395
|
}
|
|
165936
167396
|
} catch (error51) {
|
|
165937
|
-
sessionLog(sessionId, `compartment embedding failed for compartment ${
|
|
167397
|
+
sessionLog(sessionId, `compartment chunk embedding failed for compartment ${compartment.id}:`, error51);
|
|
165938
167398
|
}
|
|
165939
167399
|
}
|
|
165940
167400
|
}
|
|
165941
167401
|
var init_compartment_embedding = __esm(() => {
|
|
165942
167402
|
init_logger();
|
|
167403
|
+
init_compartment_chunk_embedding();
|
|
165943
167404
|
init_project_embedding_registry();
|
|
165944
167405
|
});
|
|
165945
167406
|
|
|
@@ -167053,55 +168514,6 @@ var init_historian_state_file = __esm(() => {
|
|
|
167053
168514
|
init_data_path();
|
|
167054
168515
|
});
|
|
167055
168516
|
|
|
167056
|
-
// src/features/magic-context/memory/constants.ts
|
|
167057
|
-
var V2_MEMORY_CATEGORIES, PROMOTABLE_CATEGORIES, CATEGORY_PRIORITY, MEMORY_CATEGORY_ORDER_UNKNOWN = 99, MEMORY_CATEGORY_ORDER_PRIORITY, MEMORY_CATEGORY_ORDER_SQL, CATEGORY_DEFAULT_TTL;
|
|
167058
|
-
var init_constants = __esm(() => {
|
|
167059
|
-
V2_MEMORY_CATEGORIES = [
|
|
167060
|
-
"PROJECT_RULES",
|
|
167061
|
-
"ARCHITECTURE",
|
|
167062
|
-
"CONSTRAINTS",
|
|
167063
|
-
"CONFIG_VALUES",
|
|
167064
|
-
"NAMING"
|
|
167065
|
-
];
|
|
167066
|
-
PROMOTABLE_CATEGORIES = [
|
|
167067
|
-
"PROJECT_RULES",
|
|
167068
|
-
"ARCHITECTURE",
|
|
167069
|
-
"CONSTRAINTS",
|
|
167070
|
-
"CONFIG_VALUES",
|
|
167071
|
-
"NAMING",
|
|
167072
|
-
"ARCHITECTURE_DECISIONS",
|
|
167073
|
-
"CONFIG_DEFAULTS",
|
|
167074
|
-
"USER_PREFERENCES",
|
|
167075
|
-
"USER_DIRECTIVES",
|
|
167076
|
-
"ENVIRONMENT",
|
|
167077
|
-
"WORKFLOW_RULES",
|
|
167078
|
-
"KNOWN_ISSUES"
|
|
167079
|
-
];
|
|
167080
|
-
CATEGORY_PRIORITY = [
|
|
167081
|
-
"PROJECT_RULES",
|
|
167082
|
-
"ARCHITECTURE",
|
|
167083
|
-
"CONSTRAINTS",
|
|
167084
|
-
"CONFIG_VALUES",
|
|
167085
|
-
"NAMING",
|
|
167086
|
-
"USER_DIRECTIVES",
|
|
167087
|
-
"USER_PREFERENCES",
|
|
167088
|
-
"CONFIG_DEFAULTS",
|
|
167089
|
-
"ARCHITECTURE_DECISIONS",
|
|
167090
|
-
"ENVIRONMENT",
|
|
167091
|
-
"WORKFLOW_RULES",
|
|
167092
|
-
"KNOWN_ISSUES"
|
|
167093
|
-
];
|
|
167094
|
-
MEMORY_CATEGORY_ORDER_PRIORITY = CATEGORY_PRIORITY.reduce((acc, category, index) => {
|
|
167095
|
-
acc[category] = index;
|
|
167096
|
-
return acc;
|
|
167097
|
-
}, {});
|
|
167098
|
-
MEMORY_CATEGORY_ORDER_SQL = `CASE category ${CATEGORY_PRIORITY.map((category, index) => `WHEN '${category}' THEN ${index}`).join(" ")} ELSE ${MEMORY_CATEGORY_ORDER_UNKNOWN} END`;
|
|
167099
|
-
CATEGORY_DEFAULT_TTL = {
|
|
167100
|
-
WORKFLOW_RULES: 90 * 24 * 60 * 60 * 1000,
|
|
167101
|
-
KNOWN_ISSUES: 30 * 24 * 60 * 60 * 1000
|
|
167102
|
-
};
|
|
167103
|
-
});
|
|
167104
|
-
|
|
167105
168517
|
// src/features/magic-context/memory/embedding-backfill.ts
|
|
167106
168518
|
async function ensureMemoryEmbeddings(args) {
|
|
167107
168519
|
const snapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -167125,7 +168537,7 @@ async function ensureMemoryEmbeddings(args) {
|
|
|
167125
168537
|
continue;
|
|
167126
168538
|
}
|
|
167127
168539
|
saveEmbedding(args.db, memory.id, embedding, result.modelId);
|
|
167128
|
-
staged.set(memory.id, embedding);
|
|
168540
|
+
staged.set(memory.id, { embedding, modelId: result.modelId });
|
|
167129
168541
|
}
|
|
167130
168542
|
})();
|
|
167131
168543
|
const currentSnapshot = getProjectEmbeddingSnapshot(args.projectIdentity);
|
|
@@ -167884,7 +169296,7 @@ ${prepared.block}
|
|
|
167884
169296
|
if (!firstMessage || !textPart || isDroppedPlaceholder(textPart.text)) {
|
|
167885
169297
|
messages.unshift({
|
|
167886
169298
|
info: { role: "user", sessionID: sessionId },
|
|
167887
|
-
parts: [{ type: "text", text: historyBlock }]
|
|
169299
|
+
parts: [{ type: "text", text: historyBlock, synthetic: true }]
|
|
167888
169300
|
});
|
|
167889
169301
|
} else {
|
|
167890
169302
|
textPart.text = `${historyBlock}
|
|
@@ -167922,6 +169334,71 @@ function lastCompartmentBoundaryId(compartments) {
|
|
|
167922
169334
|
const last = compartments.at(-1);
|
|
167923
169335
|
return last?.endMessageId && last.endMessageId.length > 0 ? last.endMessageId : null;
|
|
167924
169336
|
}
|
|
169337
|
+
function resolveWorkspaceRenderContext(args) {
|
|
169338
|
+
if (!args.projectPath) {
|
|
169339
|
+
return {
|
|
169340
|
+
identities: [],
|
|
169341
|
+
expandedIdentities: [],
|
|
169342
|
+
ownIdentities: [],
|
|
169343
|
+
shareCategories: null,
|
|
169344
|
+
namesByIdentity: new Map,
|
|
169345
|
+
canonicalIdentityByStoredPath: new Map,
|
|
169346
|
+
isWorkspaced: false
|
|
169347
|
+
};
|
|
169348
|
+
}
|
|
169349
|
+
const identitySet = args.workspaceIdentitySet ?? resolveWorkspaceIdentitySet(args.db, args.projectPath);
|
|
169350
|
+
const isWorkspaced = identitySet.identities.length > 1;
|
|
169351
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(args.db, identitySet.identities);
|
|
169352
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : identitySet.identities;
|
|
169353
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(identitySet.identities.map((identity) => [identity, identity]));
|
|
169354
|
+
let ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === args.projectPath);
|
|
169355
|
+
if (ownIdentities.length === 0 && expandedIdentities.includes(args.projectPath)) {
|
|
169356
|
+
ownIdentities = [args.projectPath];
|
|
169357
|
+
}
|
|
169358
|
+
return {
|
|
169359
|
+
identities: identitySet.identities,
|
|
169360
|
+
expandedIdentities,
|
|
169361
|
+
ownIdentities,
|
|
169362
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(args.db, args.projectPath) : null,
|
|
169363
|
+
namesByIdentity: identitySet.namesByIdentity,
|
|
169364
|
+
canonicalIdentityByStoredPath,
|
|
169365
|
+
isWorkspaced
|
|
169366
|
+
};
|
|
169367
|
+
}
|
|
169368
|
+
function sourceNamesForMemories(args) {
|
|
169369
|
+
if (!args.projectPath || !args.workspace.isWorkspaced)
|
|
169370
|
+
return;
|
|
169371
|
+
const names = new Map;
|
|
169372
|
+
for (const memory of args.memories) {
|
|
169373
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
169374
|
+
if (source)
|
|
169375
|
+
names.set(memory.id, source);
|
|
169376
|
+
}
|
|
169377
|
+
return names.size > 0 ? names : undefined;
|
|
169378
|
+
}
|
|
169379
|
+
function memoryCanonicalIdentity(memory, workspace) {
|
|
169380
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
169381
|
+
}
|
|
169382
|
+
function memorySelectionOrder(left, right) {
|
|
169383
|
+
if (left.status === "permanent" && right.status !== "permanent")
|
|
169384
|
+
return -1;
|
|
169385
|
+
if (right.status === "permanent" && left.status !== "permanent")
|
|
169386
|
+
return 1;
|
|
169387
|
+
const leftImportance = left.importance ?? Number.NEGATIVE_INFINITY;
|
|
169388
|
+
const rightImportance = right.importance ?? Number.NEGATIVE_INFINITY;
|
|
169389
|
+
const importanceDiff = rightImportance - leftImportance;
|
|
169390
|
+
if (importanceDiff !== 0)
|
|
169391
|
+
return importanceDiff;
|
|
169392
|
+
return left.id - right.id;
|
|
169393
|
+
}
|
|
169394
|
+
function memoryRenderOrder(left, right) {
|
|
169395
|
+
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[left.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
169396
|
+
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[right.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
169397
|
+
const categoryDiff = aPriority - bPriority;
|
|
169398
|
+
if (categoryDiff !== 0)
|
|
169399
|
+
return categoryDiff;
|
|
169400
|
+
return left.id - right.id;
|
|
169401
|
+
}
|
|
167925
169402
|
function cachedStatement(cache, db, sql) {
|
|
167926
169403
|
let stmt = cache.get(db);
|
|
167927
169404
|
if (!stmt) {
|
|
@@ -167964,13 +169441,19 @@ function getGlobalUserProfileVersion(db) {
|
|
|
167964
169441
|
function readCurrentM0SnapshotMarkers(args) {
|
|
167965
169442
|
const projectDirectory = args.projectDirectory ?? args.projectPath ?? "";
|
|
167966
169443
|
const hard = args.hardSignals ?? EMPTY_HARD_SIGNALS;
|
|
169444
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
169445
|
+
db: args.db,
|
|
169446
|
+
projectPath: args.projectPath,
|
|
169447
|
+
workspaceIdentitySet: args.workspaceIdentitySet
|
|
169448
|
+
});
|
|
167967
169449
|
return {
|
|
167968
169450
|
projectMemoryEpoch: getProjectMemoryEpoch(args.db, args.projectPath),
|
|
169451
|
+
workspaceFingerprint: workspace.isWorkspaced ? computeWorkspaceEpochFingerprint(args.db, workspace.identities) : null,
|
|
167969
169452
|
projectUserProfileVersion: getGlobalUserProfileVersion(args.db),
|
|
167970
169453
|
maxCompartmentSeq: getMaxCompartmentSeq(args.db, args.sessionId),
|
|
167971
|
-
maxMemoryId: getMaxMemoryId(args.db, args.projectPath),
|
|
169454
|
+
maxMemoryId: workspace.isWorkspaced ? getMaxMemoryIdForProjects(args.db, workspace.expandedIdentities, workspace.ownIdentities, workspace.shareCategories) : getMaxMemoryId(args.db, args.projectPath),
|
|
167972
169455
|
maxMutationId: getMaxM0MutationId(args.db, args.sessionId) ?? 0,
|
|
167973
|
-
maxMemoryMutationId: args.projectPath ? getMaxMemoryMutationId(args.db, args.projectPath) ?? 0 : 0,
|
|
169456
|
+
maxMemoryMutationId: workspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(args.db, workspace.expandedIdentities) ?? 0 : args.projectPath ? getMaxMemoryMutationId(args.db, args.projectPath) ?? 0 : 0,
|
|
167974
169457
|
projectDocsHash: projectDirectory ? computeProjectDocsHash(projectDirectory) : "",
|
|
167975
169458
|
materializedAt: Date.now(),
|
|
167976
169459
|
sessionFactsVersion: getSessionFactsVersion(args.db, args.sessionId),
|
|
@@ -167998,6 +169481,7 @@ function snapshotMarkersFromCachedM0(state) {
|
|
|
167998
169481
|
return null;
|
|
167999
169482
|
return {
|
|
168000
169483
|
projectMemoryEpoch: state.cachedM0ProjectMemoryEpoch,
|
|
169484
|
+
workspaceFingerprint: state.cachedM0WorkspaceFingerprint,
|
|
168001
169485
|
projectUserProfileVersion: state.cachedM0ProjectUserProfileVersion,
|
|
168002
169486
|
maxCompartmentSeq: state.cachedM0MaxCompartmentSeq,
|
|
168003
169487
|
maxMemoryId: state.cachedM0MaxMemoryId,
|
|
@@ -168027,35 +169511,27 @@ function mustMaterialize(args) {
|
|
|
168027
169511
|
if (hard.cacheExpired && hard.lastResponseTime > 0 && hard.lastResponseTime > (args.state.cachedM0MaterializedAt ?? 0)) {
|
|
168028
169512
|
return { value: true, reason: "ttl_idle" };
|
|
168029
169513
|
}
|
|
168030
|
-
if (args.state.
|
|
169514
|
+
if (current.workspaceFingerprint !== null || (args.state.cachedM0WorkspaceFingerprint ?? null) !== null) {
|
|
169515
|
+
if ((args.state.cachedM0WorkspaceFingerprint ?? null) !== current.workspaceFingerprint) {
|
|
169516
|
+
return { value: true, reason: "project_memory_epoch" };
|
|
169517
|
+
}
|
|
169518
|
+
} else if (args.state.cachedM0ProjectMemoryEpoch !== current.projectMemoryEpoch) {
|
|
168031
169519
|
return { value: true, reason: "project_memory_epoch" };
|
|
168032
169520
|
}
|
|
168033
169521
|
if (args.state.cachedM0MaxMutationId !== current.maxMutationId) {
|
|
168034
169522
|
return { value: true, reason: "max_mutation_id" };
|
|
168035
169523
|
}
|
|
168036
|
-
if ((args.state.cachedM0ProjectDocsHash ?? "") !== current.projectDocsHash) {
|
|
168037
|
-
return { value: true, reason: "project_docs_hash" };
|
|
168038
|
-
}
|
|
168039
169524
|
if ((args.state.cachedM0UpgradeState ?? null) !== current.upgradeState) {
|
|
168040
169525
|
return { value: true, reason: "upgrade_state" };
|
|
168041
169526
|
}
|
|
168042
169527
|
return { value: false, reason: null };
|
|
168043
169528
|
}
|
|
168044
|
-
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
168045
|
-
const selectionOrder = [...memories].sort(
|
|
168046
|
-
if (a.status === "permanent" && b.status !== "permanent")
|
|
168047
|
-
return -1;
|
|
168048
|
-
if (b.status === "permanent" && a.status !== "permanent")
|
|
168049
|
-
return 1;
|
|
168050
|
-
const importanceDiff = (b.importance ?? 50) - (a.importance ?? 50);
|
|
168051
|
-
if (importanceDiff !== 0)
|
|
168052
|
-
return importanceDiff;
|
|
168053
|
-
return a.id - b.id;
|
|
168054
|
-
});
|
|
169529
|
+
function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions = {}) {
|
|
169530
|
+
const selectionOrder = [...memories].sort(memorySelectionOrder);
|
|
168055
169531
|
const selected = [];
|
|
168056
169532
|
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
168057
169533
|
for (const memory of selectionOrder) {
|
|
168058
|
-
const memoryTokens = estimateTokens(renderMemoryLineV2(memory));
|
|
169534
|
+
const memoryTokens = estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
168059
169535
|
if (usedTokens + memoryTokens > budgetTokens)
|
|
168060
169536
|
continue;
|
|
168061
169537
|
selected.push(memory);
|
|
@@ -168064,16 +169540,70 @@ function trimMemoriesToBudgetV2(sessionId, memories, budgetTokens) {
|
|
|
168064
169540
|
if (selected.length < memories.length) {
|
|
168065
169541
|
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
168066
169542
|
}
|
|
168067
|
-
const renderOrder = [...selected].sort(
|
|
168068
|
-
const aPriority = MEMORY_CATEGORY_ORDER_PRIORITY[a.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
168069
|
-
const bPriority = MEMORY_CATEGORY_ORDER_PRIORITY[b.category] ?? MEMORY_CATEGORY_ORDER_UNKNOWN;
|
|
168070
|
-
const categoryDiff = aPriority - bPriority;
|
|
168071
|
-
if (categoryDiff !== 0)
|
|
168072
|
-
return categoryDiff;
|
|
168073
|
-
return a.id - b.id;
|
|
168074
|
-
});
|
|
169543
|
+
const renderOrder = [...selected].sort(memoryRenderOrder);
|
|
168075
169544
|
return { selected, renderOrder };
|
|
168076
169545
|
}
|
|
169546
|
+
function trimWorkspaceMemoriesToBudgetV2(sessionId, memories, budgetTokens, workspace, renderOptions = {}) {
|
|
169547
|
+
if (!workspace.isWorkspaced) {
|
|
169548
|
+
return trimMemoriesToBudgetV2(sessionId, memories, budgetTokens, renderOptions);
|
|
169549
|
+
}
|
|
169550
|
+
const selected = [];
|
|
169551
|
+
const selectedIds = new Set;
|
|
169552
|
+
let usedTokens = MEMORY_BLOCK_WRAPPER_TOKENS;
|
|
169553
|
+
const tokenCost = (memory) => estimateTokens(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
169554
|
+
const trySelect = (memory) => {
|
|
169555
|
+
if (selectedIds.has(memory.id))
|
|
169556
|
+
return false;
|
|
169557
|
+
const tokens = tokenCost(memory);
|
|
169558
|
+
if (usedTokens + tokens > budgetTokens)
|
|
169559
|
+
return false;
|
|
169560
|
+
selected.push(memory);
|
|
169561
|
+
selectedIds.add(memory.id);
|
|
169562
|
+
usedTokens += tokens;
|
|
169563
|
+
return true;
|
|
169564
|
+
};
|
|
169565
|
+
for (const memory of memories.filter((candidate) => candidate.status === "permanent").sort(memorySelectionOrder)) {
|
|
169566
|
+
trySelect(memory);
|
|
169567
|
+
}
|
|
169568
|
+
const remainingAfterPermanent = Math.max(0, budgetTokens - usedTokens);
|
|
169569
|
+
const floorTokens = remainingAfterPermanent / Math.max(1, workspace.identities.length);
|
|
169570
|
+
const byIdentity = new Map;
|
|
169571
|
+
for (const memory of memories) {
|
|
169572
|
+
if (memory.status === "permanent")
|
|
169573
|
+
continue;
|
|
169574
|
+
const identity = memoryCanonicalIdentity(memory, workspace);
|
|
169575
|
+
if (!identity)
|
|
169576
|
+
continue;
|
|
169577
|
+
const list = byIdentity.get(identity) ?? [];
|
|
169578
|
+
list.push(memory);
|
|
169579
|
+
byIdentity.set(identity, list);
|
|
169580
|
+
}
|
|
169581
|
+
for (const identity of workspace.identities) {
|
|
169582
|
+
let memberTokens = 0;
|
|
169583
|
+
const candidates = (byIdentity.get(identity) ?? []).sort(memorySelectionOrder);
|
|
169584
|
+
for (const memory of candidates) {
|
|
169585
|
+
if (selectedIds.has(memory.id))
|
|
169586
|
+
continue;
|
|
169587
|
+
const tokens = tokenCost(memory);
|
|
169588
|
+
if (memberTokens + tokens > floorTokens)
|
|
169589
|
+
continue;
|
|
169590
|
+
if (usedTokens + tokens > budgetTokens)
|
|
169591
|
+
continue;
|
|
169592
|
+
selected.push(memory);
|
|
169593
|
+
selectedIds.add(memory.id);
|
|
169594
|
+
usedTokens += tokens;
|
|
169595
|
+
memberTokens += tokens;
|
|
169596
|
+
}
|
|
169597
|
+
}
|
|
169598
|
+
const remaining = memories.filter((memory) => !selectedIds.has(memory.id)).sort(memorySelectionOrder);
|
|
169599
|
+
for (const memory of remaining) {
|
|
169600
|
+
trySelect(memory);
|
|
169601
|
+
}
|
|
169602
|
+
if (selected.length < memories.length) {
|
|
169603
|
+
sessionLog(sessionId, `v2 trimmed memories from ${memories.length} to ${selected.length} to fit injection budget of ${budgetTokens} tokens`);
|
|
169604
|
+
}
|
|
169605
|
+
return { selected, renderOrder: [...selected].sort(memoryRenderOrder) };
|
|
169606
|
+
}
|
|
168077
169607
|
function safeGetActiveUserMemories(db) {
|
|
168078
169608
|
try {
|
|
168079
169609
|
return getActiveUserMemories(db);
|
|
@@ -168149,15 +169679,16 @@ function readNewMemoriesForM1(db, projectPath, afterId, expiryCutoff) {
|
|
|
168149
169679
|
ORDER BY ${MEMORY_CATEGORY_ORDER_SQL}, id ASC`).all(projectPath, afterId, expiryCutoff).filter(isMemoryRow);
|
|
168150
169680
|
return rows.map((row) => ({ ...row }));
|
|
168151
169681
|
}
|
|
168152
|
-
function renderMemoryLineV2(memory) {
|
|
168153
|
-
|
|
169682
|
+
function renderMemoryLineV2(memory, sourceName) {
|
|
169683
|
+
const sourceAttr = sourceName ? ` source="${escapeXmlAttr(sourceName)}"` : "";
|
|
169684
|
+
return ` <memory id="${memory.id}" category="${escapeXmlAttr(memory.category)}"${sourceAttr} importance="${memory.importance ?? 50}">${escapeXmlContent(memory.content)}</memory>`;
|
|
168154
169685
|
}
|
|
168155
|
-
function renderMemoryBlockV2(memories, wrapper = "project-memory") {
|
|
169686
|
+
function renderMemoryBlockV2(memories, wrapper = "project-memory", renderOptions = {}) {
|
|
168156
169687
|
if (memories.length === 0)
|
|
168157
169688
|
return "";
|
|
168158
169689
|
const lines = [`<${wrapper}>`];
|
|
168159
169690
|
for (const memory of memories) {
|
|
168160
|
-
lines.push(renderMemoryLineV2(memory));
|
|
169691
|
+
lines.push(renderMemoryLineV2(memory, renderOptions.sourceNameByMemoryId?.get(memory.id)));
|
|
168161
169692
|
}
|
|
168162
169693
|
lines.push(`</${wrapper}>`);
|
|
168163
169694
|
return lines.join(`
|
|
@@ -168196,7 +169727,7 @@ function renderM0(args) {
|
|
|
168196
169727
|
sections.push(sessionHistory.length > 0 ? `<session-history>
|
|
168197
169728
|
${sessionHistory}
|
|
168198
169729
|
</session-history>` : M0_EMPTY_BODY);
|
|
168199
|
-
const memoriesBlock = renderMemoryBlockV2(args.memories);
|
|
169730
|
+
const memoriesBlock = renderMemoryBlockV2(args.memories, "project-memory", args.memoryRenderOptions);
|
|
168200
169731
|
if (memoriesBlock)
|
|
168201
169732
|
sections.push(memoriesBlock);
|
|
168202
169733
|
return sections.join(`
|
|
@@ -168208,6 +169739,7 @@ function applyMarkersToState(state, m0Bytes, markers, m1Bytes) {
|
|
|
168208
169739
|
if (m1Bytes)
|
|
168209
169740
|
state.cachedM1Bytes = m1Bytes;
|
|
168210
169741
|
state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
|
|
169742
|
+
state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
|
|
168211
169743
|
state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
|
|
168212
169744
|
state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
|
|
168213
169745
|
state.cachedM0MaxMemoryId = markers.maxMemoryId;
|
|
@@ -168233,24 +169765,38 @@ function materializeM0(options) {
|
|
|
168233
169765
|
let facts = [];
|
|
168234
169766
|
let memories = [];
|
|
168235
169767
|
let userMemories = [];
|
|
169768
|
+
let workspace = resolveWorkspaceRenderContext({
|
|
169769
|
+
db: options.db,
|
|
169770
|
+
projectPath,
|
|
169771
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169772
|
+
});
|
|
168236
169773
|
let docs = {
|
|
168237
169774
|
renderedBlock: "",
|
|
168238
169775
|
canonicalHash: ""
|
|
168239
169776
|
};
|
|
168240
169777
|
options.db.exec("BEGIN");
|
|
168241
169778
|
try {
|
|
169779
|
+
workspace = resolveWorkspaceRenderContext({
|
|
169780
|
+
db: options.db,
|
|
169781
|
+
projectPath,
|
|
169782
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169783
|
+
});
|
|
168242
169784
|
snapshotMarkers = readCurrentM0SnapshotMarkers({
|
|
168243
169785
|
db: options.db,
|
|
168244
169786
|
sessionId: options.sessionId,
|
|
168245
169787
|
projectPath,
|
|
168246
169788
|
projectDirectory,
|
|
168247
|
-
hardSignals: options.hardSignals
|
|
169789
|
+
hardSignals: options.hardSignals,
|
|
169790
|
+
workspaceIdentitySet: {
|
|
169791
|
+
identities: workspace.identities,
|
|
169792
|
+
namesByIdentity: workspace.namesByIdentity
|
|
169793
|
+
}
|
|
168248
169794
|
});
|
|
168249
169795
|
docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
|
|
168250
169796
|
snapshotMarkers.projectDocsHash = docs.canonicalHash;
|
|
168251
169797
|
compartments = readM0Compartments(options.db, options.sessionId);
|
|
168252
169798
|
facts = [];
|
|
168253
|
-
memories = projectPath ? getMemoriesByProject(options.db, projectPath, ["active", "permanent"]) : [];
|
|
169799
|
+
memories = projectPath ? workspace.isWorkspaced ? getMemoriesByProjects(options.db, workspace.expandedIdentities, ["active", "permanent"], Date.now(), workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(options.db, projectPath, ["active", "permanent"]) : [];
|
|
168254
169800
|
userMemories = safeGetActiveUserMemories(options.db);
|
|
168255
169801
|
options.db.exec("COMMIT");
|
|
168256
169802
|
} catch (error51) {
|
|
@@ -168260,7 +169806,14 @@ function materializeM0(options) {
|
|
|
168260
169806
|
throw error51;
|
|
168261
169807
|
}
|
|
168262
169808
|
const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
168263
|
-
const
|
|
169809
|
+
const memoryRenderOptions = {
|
|
169810
|
+
sourceNameByMemoryId: sourceNamesForMemories({
|
|
169811
|
+
memories,
|
|
169812
|
+
projectPath,
|
|
169813
|
+
workspace
|
|
169814
|
+
})
|
|
169815
|
+
};
|
|
169816
|
+
const trimmed = workspace.isWorkspaced ? trimWorkspaceMemoriesToBudgetV2(options.sessionId, memories, memoryBudget, workspace, memoryRenderOptions) : trimMemoriesToBudgetV2(options.sessionId, memories, memoryBudget);
|
|
168264
169817
|
let decayPressureMultiplier = 1;
|
|
168265
169818
|
let m0Text = renderM0({
|
|
168266
169819
|
projectDocs: docs.renderedBlock,
|
|
@@ -168268,6 +169821,7 @@ function materializeM0(options) {
|
|
|
168268
169821
|
compartments,
|
|
168269
169822
|
memories: trimmed.renderOrder,
|
|
168270
169823
|
facts,
|
|
169824
|
+
memoryRenderOptions,
|
|
168271
169825
|
historyBudgetTokens: options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS,
|
|
168272
169826
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168273
169827
|
decayPressureMultiplier
|
|
@@ -168282,6 +169836,7 @@ function materializeM0(options) {
|
|
|
168282
169836
|
compartments,
|
|
168283
169837
|
memories: trimmed.renderOrder,
|
|
168284
169838
|
facts,
|
|
169839
|
+
memoryRenderOptions,
|
|
168285
169840
|
historyBudgetTokens: budget,
|
|
168286
169841
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168287
169842
|
decayPressureMultiplier
|
|
@@ -168300,13 +169855,19 @@ function materializeM0(options) {
|
|
|
168300
169855
|
let m1Bytes = Buffer4.from(m1Text, "utf8");
|
|
168301
169856
|
options.db.exec("BEGIN IMMEDIATE");
|
|
168302
169857
|
try {
|
|
169858
|
+
const currentWorkspace = resolveWorkspaceRenderContext({
|
|
169859
|
+
db: options.db,
|
|
169860
|
+
projectPath,
|
|
169861
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169862
|
+
});
|
|
168303
169863
|
const current = {
|
|
168304
169864
|
projectMemoryEpoch: getProjectMemoryEpoch(options.db, projectPath),
|
|
169865
|
+
workspaceFingerprint: currentWorkspace.isWorkspaced ? computeWorkspaceEpochFingerprint(options.db, currentWorkspace.identities) : null,
|
|
168305
169866
|
projectUserProfileVersion: getGlobalUserProfileVersion(options.db),
|
|
168306
169867
|
maxCompartmentSeq: getMaxCompartmentSeq(options.db, options.sessionId),
|
|
168307
|
-
maxMemoryId: getMaxMemoryId(options.db, projectPath),
|
|
169868
|
+
maxMemoryId: currentWorkspace.isWorkspaced ? getMaxMemoryIdForProjects(options.db, currentWorkspace.expandedIdentities, currentWorkspace.ownIdentities, currentWorkspace.shareCategories) : getMaxMemoryId(options.db, projectPath),
|
|
168308
169869
|
maxMutationId: getMaxM0MutationId(options.db, options.sessionId) ?? 0,
|
|
168309
|
-
maxMemoryMutationId: projectPath ? getMaxMemoryMutationId(options.db, projectPath) ?? 0 : 0,
|
|
169870
|
+
maxMemoryMutationId: currentWorkspace.isWorkspaced ? getMaxMemoryMutationIdForProjects(options.db, currentWorkspace.expandedIdentities) ?? 0 : projectPath ? getMaxMemoryMutationId(options.db, projectPath) ?? 0 : 0,
|
|
168310
169871
|
projectDocsHash: phase3ProjectDocsHash,
|
|
168311
169872
|
materializedAt: Date.now(),
|
|
168312
169873
|
sessionFactsVersion: getSessionFactsVersion(options.db, options.sessionId),
|
|
@@ -168314,17 +169875,26 @@ function materializeM0(options) {
|
|
|
168314
169875
|
systemHash: snapshotMarkers.systemHash,
|
|
168315
169876
|
modelKey: snapshotMarkers.modelKey
|
|
168316
169877
|
};
|
|
168317
|
-
const
|
|
169878
|
+
const memoryEpochStale = current.workspaceFingerprint !== null || snapshotMarkers.workspaceFingerprint !== null ? current.workspaceFingerprint !== snapshotMarkers.workspaceFingerprint : current.projectMemoryEpoch !== snapshotMarkers.projectMemoryEpoch;
|
|
169879
|
+
const stale = memoryEpochStale || current.projectUserProfileVersion !== snapshotMarkers.projectUserProfileVersion || current.maxCompartmentSeq !== snapshotMarkers.maxCompartmentSeq || current.maxMutationId !== snapshotMarkers.maxMutationId || current.maxMemoryMutationId !== snapshotMarkers.maxMemoryMutationId || current.sessionFactsVersion !== snapshotMarkers.sessionFactsVersion || current.upgradeState !== snapshotMarkers.upgradeState;
|
|
168318
169880
|
if (stale) {
|
|
168319
169881
|
options.db.exec("ROLLBACK");
|
|
168320
169882
|
throw new MaterializeContentionError({ reason: "snapshot changed before Phase 3" });
|
|
168321
169883
|
}
|
|
168322
|
-
const m1Render = renderM1WithMetadata({
|
|
169884
|
+
const m1Render = renderM1WithMetadata({
|
|
169885
|
+
...options,
|
|
169886
|
+
preRenderedKeyFilesBlock,
|
|
169887
|
+
workspaceIdentitySet: {
|
|
169888
|
+
identities: workspace.identities,
|
|
169889
|
+
namesByIdentity: workspace.namesByIdentity
|
|
169890
|
+
}
|
|
169891
|
+
}, snapshotMarkers, renderedMemoryIds);
|
|
168323
169892
|
m1Text = m1Render.text;
|
|
168324
169893
|
m1Bytes = Buffer4.from(m1Text, "utf8");
|
|
168325
169894
|
persistCachedM0(options.db, options.sessionId, {
|
|
168326
169895
|
m0Bytes,
|
|
168327
169896
|
projectMemoryEpoch: snapshotMarkers.projectMemoryEpoch,
|
|
169897
|
+
workspaceFingerprint: snapshotMarkers.workspaceFingerprint,
|
|
168328
169898
|
projectUserProfileVersion: snapshotMarkers.projectUserProfileVersion,
|
|
168329
169899
|
maxCompartmentSeq: snapshotMarkers.maxCompartmentSeq,
|
|
168330
169900
|
maxMemoryId: snapshotMarkers.maxMemoryId,
|
|
@@ -168387,7 +169957,7 @@ function renderMemoryUpdatesBlock(args) {
|
|
|
168387
169957
|
return { block: "", count: 0 };
|
|
168388
169958
|
}
|
|
168389
169959
|
const renderedIds = new Set(args.renderedMemoryIds);
|
|
168390
|
-
const mutations = getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
169960
|
+
const mutations = args.workspace.isWorkspaced ? getMemoryMutationsForRenderByProjects(args.db, args.workspace.expandedIdentities, args.afterId, args.renderedMemoryIds) : getMemoryMutationsForRender(args.db, args.projectPath, args.afterId, args.renderedMemoryIds);
|
|
168391
169961
|
if (mutations.length === 0)
|
|
168392
169962
|
return { block: "", count: 0 };
|
|
168393
169963
|
const lines = ["These memories changed since the snapshot below — trust these:"];
|
|
@@ -168419,12 +169989,18 @@ function renderM1WithMetadata(options, markers, renderedMemoryIds) {
|
|
|
168419
169989
|
throw new RenderM1InvalidMarkersError(options.sessionId);
|
|
168420
169990
|
}
|
|
168421
169991
|
const blocks = [];
|
|
169992
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
169993
|
+
db: options.db,
|
|
169994
|
+
projectPath: options.projectPath,
|
|
169995
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
169996
|
+
});
|
|
168422
169997
|
const keyFiles = renderedKeyFilesBlock(options);
|
|
168423
169998
|
if (keyFiles)
|
|
168424
169999
|
blocks.push(keyFiles);
|
|
168425
170000
|
const memoryUpdates = renderMemoryUpdatesBlock({
|
|
168426
170001
|
db: options.db,
|
|
168427
170002
|
projectPath: options.projectPath,
|
|
170003
|
+
workspace,
|
|
168428
170004
|
afterId: markers.maxMemoryMutationId,
|
|
168429
170005
|
renderedMemoryIds
|
|
168430
170006
|
});
|
|
@@ -168438,9 +170014,16 @@ ${newCompartments.map((compartment) => renderCompartmentAtTier(compartment, 1)).
|
|
|
168438
170014
|
`)}
|
|
168439
170015
|
</new-compartments>`);
|
|
168440
170016
|
}
|
|
168441
|
-
const newMemories = readNewMemoriesForM1(options.db, options.projectPath, markers.maxMemoryId, markers.materializedAt);
|
|
168442
|
-
const
|
|
168443
|
-
|
|
170017
|
+
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);
|
|
170018
|
+
const newMemoryRenderOptions = {
|
|
170019
|
+
sourceNameByMemoryId: sourceNamesForMemories({
|
|
170020
|
+
memories: newMemories,
|
|
170021
|
+
projectPath: options.projectPath,
|
|
170022
|
+
workspace
|
|
170023
|
+
})
|
|
170024
|
+
};
|
|
170025
|
+
const trimmedNewMemories = trimMemoriesToBudgetV2(options.sessionId, newMemories, Math.max(1, Math.floor((options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS) * 0.25)), newMemoryRenderOptions).renderOrder;
|
|
170026
|
+
const newMemoriesBlock = renderMemoryBlockV2(trimmedNewMemories, "new-memories", newMemoryRenderOptions);
|
|
168444
170027
|
if (newMemoriesBlock)
|
|
168445
170028
|
blocks.push(newMemoriesBlock);
|
|
168446
170029
|
const currentUserProfileVersion = getGlobalUserProfileVersion(options.db);
|
|
@@ -168488,6 +170071,7 @@ function parseMemoryBlockIds(raw) {
|
|
|
168488
170071
|
function readCachedM0M1Row(db, sessionId) {
|
|
168489
170072
|
return db.prepare(`SELECT cached_m0_bytes, cached_m1_bytes,
|
|
168490
170073
|
cached_m0_project_memory_epoch,
|
|
170074
|
+
cached_m0_workspace_fingerprint,
|
|
168491
170075
|
cached_m0_project_user_profile_version,
|
|
168492
170076
|
cached_m0_max_compartment_seq,
|
|
168493
170077
|
cached_m0_max_memory_id,
|
|
@@ -168522,6 +170106,7 @@ function markersFromCachedRow(row) {
|
|
|
168522
170106
|
return null;
|
|
168523
170107
|
return {
|
|
168524
170108
|
projectMemoryEpoch: row.cached_m0_project_memory_epoch,
|
|
170109
|
+
workspaceFingerprint: row.cached_m0_workspace_fingerprint,
|
|
168525
170110
|
projectUserProfileVersion: row.cached_m0_project_user_profile_version,
|
|
168526
170111
|
maxCompartmentSeq: row.cached_m0_max_compartment_seq,
|
|
168527
170112
|
maxMemoryId: row.cached_m0_max_memory_id,
|
|
@@ -168536,7 +170121,7 @@ function markersFromCachedRow(row) {
|
|
|
168536
170121
|
};
|
|
168537
170122
|
}
|
|
168538
170123
|
function cachedRowMatchesState(row, state) {
|
|
168539
|
-
return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId &&
|
|
170124
|
+
return bufferEqualsNullable(row.cached_m0_bytes, state.cachedM0Bytes) && row.cached_m0_project_memory_epoch === state.cachedM0ProjectMemoryEpoch && (row.cached_m0_workspace_fingerprint ?? null) === (state.cachedM0WorkspaceFingerprint ?? null) && row.cached_m0_project_user_profile_version === state.cachedM0ProjectUserProfileVersion && row.cached_m0_max_compartment_seq === state.cachedM0MaxCompartmentSeq && row.cached_m0_max_memory_id === state.cachedM0MaxMemoryId && row.cached_m0_max_mutation_id === state.cachedM0MaxMutationId && row.cached_m0_max_memory_mutation_id === state.cachedM0MaxMemoryMutationId && row.cached_m0_materialized_at === state.cachedM0MaterializedAt && row.cached_m0_session_facts_version === state.cachedM0SessionFactsVersion && (row.cached_m0_upgrade_state ?? null) === (state.cachedM0UpgradeState ?? null) && (row.cached_m0_system_hash ?? "") === (state.cachedM0SystemHash ?? "") && (row.cached_m0_model_key ?? "") === (state.cachedM0ModelKey ?? "");
|
|
168540
170125
|
}
|
|
168541
170126
|
function applyCachedRowToState(state, row) {
|
|
168542
170127
|
const markers = markersFromCachedRow(row);
|
|
@@ -168546,6 +170131,7 @@ function applyCachedRowToState(state, row) {
|
|
|
168546
170131
|
state.cachedM0Bytes = toBuffer(row.cached_m0_bytes);
|
|
168547
170132
|
state.cachedM1Bytes = toBuffer(row.cached_m1_bytes);
|
|
168548
170133
|
state.cachedM0ProjectMemoryEpoch = markers.projectMemoryEpoch;
|
|
170134
|
+
state.cachedM0WorkspaceFingerprint = markers.workspaceFingerprint;
|
|
168549
170135
|
state.cachedM0ProjectUserProfileVersion = markers.projectUserProfileVersion;
|
|
168550
170136
|
state.cachedM0MaxCompartmentSeq = markers.maxCompartmentSeq;
|
|
168551
170137
|
state.cachedM0MaxMemoryId = markers.maxMemoryId;
|
|
@@ -168600,29 +170186,51 @@ function softRefreshCachedM1(options) {
|
|
|
168600
170186
|
function prependM0M1Messages(sessionId, messages, m0Text, m1Text) {
|
|
168601
170187
|
messages.unshift({
|
|
168602
170188
|
info: { role: "user", sessionID: sessionId },
|
|
168603
|
-
parts: [
|
|
170189
|
+
parts: [
|
|
170190
|
+
{
|
|
170191
|
+
type: "text",
|
|
170192
|
+
text: m0Text.length > 0 ? m0Text : M0_EMPTY_BODY,
|
|
170193
|
+
synthetic: true
|
|
170194
|
+
}
|
|
170195
|
+
]
|
|
168604
170196
|
}, {
|
|
168605
170197
|
info: { role: "user", sessionID: sessionId },
|
|
168606
|
-
parts: [{ type: "text", text: m1Text }]
|
|
170198
|
+
parts: [{ type: "text", text: m1Text, synthetic: true }]
|
|
168607
170199
|
});
|
|
168608
170200
|
}
|
|
168609
170201
|
function renderFreshM0NonPersisted(options) {
|
|
168610
170202
|
const projectPath = options.projectPath;
|
|
168611
170203
|
const projectDirectory = options.projectDirectory;
|
|
170204
|
+
const workspace = resolveWorkspaceRenderContext({
|
|
170205
|
+
db: options.db,
|
|
170206
|
+
projectPath,
|
|
170207
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
170208
|
+
});
|
|
168612
170209
|
const snapshotMarkers = readCurrentM0SnapshotMarkers({
|
|
168613
170210
|
db: options.db,
|
|
168614
170211
|
sessionId: options.sessionId,
|
|
168615
170212
|
projectPath,
|
|
168616
|
-
projectDirectory
|
|
170213
|
+
projectDirectory,
|
|
170214
|
+
workspaceIdentitySet: {
|
|
170215
|
+
identities: workspace.identities,
|
|
170216
|
+
namesByIdentity: workspace.namesByIdentity
|
|
170217
|
+
}
|
|
168617
170218
|
});
|
|
168618
170219
|
const docs = projectDirectory ? readProjectDocsCanonical(projectDirectory) : { renderedBlock: "", canonicalHash: "" };
|
|
168619
170220
|
snapshotMarkers.projectDocsHash = docs.canonicalHash;
|
|
168620
170221
|
snapshotMarkers.materializedAt = options.state.cachedM0MaterializedAt ?? 0;
|
|
168621
170222
|
const compartments = readM0Compartments(options.db, options.sessionId);
|
|
168622
|
-
const memories = projectPath ? getMemoriesByProject(options.db, projectPath, ["active", "permanent"], snapshotMarkers.materializedAt) : [];
|
|
170223
|
+
const memories = projectPath ? workspace.isWorkspaced ? getMemoriesByProjects(options.db, workspace.expandedIdentities, ["active", "permanent"], snapshotMarkers.materializedAt, workspace.ownIdentities, workspace.shareCategories) : getMemoriesByProject(options.db, projectPath, ["active", "permanent"], snapshotMarkers.materializedAt) : [];
|
|
168623
170224
|
const userMemories = safeGetActiveUserMemories(options.db);
|
|
168624
170225
|
const memoryBudget = options.memoryInjectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
168625
|
-
const
|
|
170226
|
+
const memoryRenderOptions = {
|
|
170227
|
+
sourceNameByMemoryId: sourceNamesForMemories({
|
|
170228
|
+
memories,
|
|
170229
|
+
projectPath,
|
|
170230
|
+
workspace
|
|
170231
|
+
})
|
|
170232
|
+
};
|
|
170233
|
+
const trimmed = workspace.isWorkspaced ? trimWorkspaceMemoriesToBudgetV2(options.sessionId, memories, memoryBudget, workspace, memoryRenderOptions) : trimMemoriesToBudgetV2(options.sessionId, memories, memoryBudget);
|
|
168626
170234
|
const budget = options.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
168627
170235
|
let decayPressureMultiplier = 1;
|
|
168628
170236
|
let m0Text = renderM0({
|
|
@@ -168631,6 +170239,7 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168631
170239
|
compartments,
|
|
168632
170240
|
memories: trimmed.renderOrder,
|
|
168633
170241
|
facts: [],
|
|
170242
|
+
memoryRenderOptions,
|
|
168634
170243
|
historyBudgetTokens: budget,
|
|
168635
170244
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168636
170245
|
decayPressureMultiplier
|
|
@@ -168644,6 +170253,7 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168644
170253
|
compartments,
|
|
168645
170254
|
memories: trimmed.renderOrder,
|
|
168646
170255
|
facts: [],
|
|
170256
|
+
memoryRenderOptions,
|
|
168647
170257
|
historyBudgetTokens: budget,
|
|
168648
170258
|
userProfileBudgetTokens: options.userProfileBudgetTokens,
|
|
168649
170259
|
decayPressureMultiplier
|
|
@@ -168659,6 +170269,12 @@ function renderFreshM0NonPersisted(options) {
|
|
|
168659
170269
|
};
|
|
168660
170270
|
}
|
|
168661
170271
|
function injectM0M1(options) {
|
|
170272
|
+
if (!options.workspaceIdentitySet && options.projectPath) {
|
|
170273
|
+
options = {
|
|
170274
|
+
...options,
|
|
170275
|
+
workspaceIdentitySet: resolveWorkspaceIdentitySet(options.db, options.projectPath)
|
|
170276
|
+
};
|
|
170277
|
+
}
|
|
168662
170278
|
const skipped = {
|
|
168663
170279
|
injected: false,
|
|
168664
170280
|
m0RematerializedThisPass: false,
|
|
@@ -168675,7 +170291,8 @@ function injectM0M1(options) {
|
|
|
168675
170291
|
state: options.state,
|
|
168676
170292
|
projectPath: options.projectPath,
|
|
168677
170293
|
projectDirectory: options.projectDirectory,
|
|
168678
|
-
hardSignals: options.hardSignals
|
|
170294
|
+
hardSignals: options.hardSignals,
|
|
170295
|
+
workspaceIdentitySet: options.workspaceIdentitySet
|
|
168679
170296
|
});
|
|
168680
170297
|
let rematerialized = false;
|
|
168681
170298
|
let contentionExhausted = false;
|
|
@@ -168769,6 +170386,7 @@ var init_inject_compartments = __esm(async () => {
|
|
|
168769
170386
|
init_compartment_storage();
|
|
168770
170387
|
init_constants();
|
|
168771
170388
|
init_storage_memory();
|
|
170389
|
+
init_workspaces();
|
|
168772
170390
|
init_logger();
|
|
168773
170391
|
init_decay_render();
|
|
168774
170392
|
init_key_files_block();
|
|
@@ -171908,18 +173526,38 @@ async function runCompartmentAgent(deps) {
|
|
|
171908
173526
|
return;
|
|
171909
173527
|
}
|
|
171910
173528
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
171911
|
-
|
|
173529
|
+
let boundarySnapshot = deps.boundarySnapshot ?? null;
|
|
171912
173530
|
if (!boundarySnapshot) {
|
|
171913
173531
|
telemetry.failureReason = "missing protected-tail boundary snapshot";
|
|
171914
173532
|
sessionLog(sessionId, "historian no-op: missing protected-tail boundary snapshot from trigger decision");
|
|
171915
173533
|
rollbackDrainReservation();
|
|
171916
173534
|
return;
|
|
171917
173535
|
}
|
|
171918
|
-
|
|
173536
|
+
let validation = boundarySnapshot.rawRangeFingerprint.length > 0 ? validateBoundarySnapshot({
|
|
171919
173537
|
db,
|
|
171920
173538
|
snapshot: boundarySnapshot,
|
|
171921
173539
|
currentContextLimit: deps.currentContextLimit ?? boundarySnapshot.contextLimit
|
|
171922
173540
|
}) : { ok: true };
|
|
173541
|
+
if (!validation.ok && validation.reason === "stale_snapshot") {
|
|
173542
|
+
const refreshed = resolveOpenCodeProtectedTailBoundary({
|
|
173543
|
+
db,
|
|
173544
|
+
sessionId,
|
|
173545
|
+
mode: "incremental-runner",
|
|
173546
|
+
contextLimit: deps.currentContextLimit ?? boundarySnapshot.contextLimit,
|
|
173547
|
+
executeThresholdPercentage: boundarySnapshot.executeThresholdPercentage,
|
|
173548
|
+
usage: {
|
|
173549
|
+
percentage: boundarySnapshot.usagePercentage,
|
|
173550
|
+
inputTokens: boundarySnapshot.usageInputTokens
|
|
173551
|
+
},
|
|
173552
|
+
usageSource: boundarySnapshot.usageSource,
|
|
173553
|
+
emergencyTailScale: boundarySnapshot.emergencyTailScale
|
|
173554
|
+
});
|
|
173555
|
+
if (hasRunnableCompartmentWindow(refreshed)) {
|
|
173556
|
+
sessionLog(sessionId, `historian: refreshed stale protected-tail snapshot at run time (was: ${validation.detail ?? "stale"}) — eligible head ${refreshed.offset}-${refreshed.eligibleEndOrdinal - 1}`);
|
|
173557
|
+
boundarySnapshot = refreshed;
|
|
173558
|
+
validation = { ok: true };
|
|
173559
|
+
}
|
|
173560
|
+
}
|
|
171923
173561
|
if (!validation.ok) {
|
|
171924
173562
|
sessionLog(sessionId, `historian no-op: stale protected-tail snapshot (${validation.detail ?? validation.reason ?? "unknown"})`);
|
|
171925
173563
|
telemetry.status = "noop";
|
|
@@ -171988,6 +173626,7 @@ async function runCompartmentAgent(deps) {
|
|
|
171988
173626
|
rollbackDrainReservation();
|
|
171989
173627
|
return;
|
|
171990
173628
|
}
|
|
173629
|
+
deps.onHistorianRunStarted?.();
|
|
171991
173630
|
const projectPath = resolveProjectIdentity(directory ?? process.cwd());
|
|
171992
173631
|
const memories = getMemoriesByProject(db, projectPath, ["active", "permanent"]);
|
|
171993
173632
|
const projectMemory = renderMemoryBlock(memories) ?? "";
|
|
@@ -172120,8 +173759,13 @@ ${chunkText}`,
|
|
|
172120
173759
|
}
|
|
172121
173760
|
if (embeddingActive) {
|
|
172122
173761
|
const projectIdentity = resolveProjectIdentity(promotionDirectory);
|
|
172123
|
-
const
|
|
172124
|
-
|
|
173762
|
+
const chunksToEmbed = persistedCompartments.map((c, i) => ({
|
|
173763
|
+
id: persistedIds[i],
|
|
173764
|
+
startMessage: c.startMessage,
|
|
173765
|
+
endMessage: c.endMessage,
|
|
173766
|
+
sourceChunkText: chunk.text
|
|
173767
|
+
})).filter((c) => typeof c.id === "number");
|
|
173768
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
172125
173769
|
}
|
|
172126
173770
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
172127
173771
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
@@ -172352,8 +173996,12 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
172352
173996
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172353
173997
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
172354
173998
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172355
|
-
const
|
|
172356
|
-
|
|
173999
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
174000
|
+
id: c.id,
|
|
174001
|
+
startMessage: c.startMessage,
|
|
174002
|
+
endMessage: c.endMessage
|
|
174003
|
+
}));
|
|
174004
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
172357
174005
|
}
|
|
172358
174006
|
const lastCompartmentEnd2 = promoted2.compartments[promoted2.compartments.length - 1]?.endMessage ?? 0;
|
|
172359
174007
|
if (lastCompartmentEnd2 > 0) {
|
|
@@ -172566,8 +174214,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
172566
174214
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172567
174215
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
172568
174216
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172569
|
-
const
|
|
172570
|
-
|
|
174217
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
174218
|
+
id: c.id,
|
|
174219
|
+
startMessage: c.startMessage,
|
|
174220
|
+
endMessage: c.endMessage
|
|
174221
|
+
}));
|
|
174222
|
+
embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed);
|
|
172571
174223
|
}
|
|
172572
174224
|
if (lastCompartmentEnd > 0) {
|
|
172573
174225
|
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
@@ -172748,8 +174400,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
172748
174400
|
if (deps.memoryEnabled !== false) {
|
|
172749
174401
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
172750
174402
|
const liveCompartments = getCompartments(db, sessionId);
|
|
172751
|
-
const
|
|
172752
|
-
|
|
174403
|
+
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
174404
|
+
id: c.id,
|
|
174405
|
+
startMessage: c.startMessage,
|
|
174406
|
+
endMessage: c.endMessage
|
|
174407
|
+
}));
|
|
174408
|
+
Promise.resolve(deps.ensureProjectRegistered?.(sessionDirectory, db)).then(() => embedAndStoreCompartmentChunks(db, sessionId, projectIdentity, chunksToEmbed));
|
|
172753
174409
|
}
|
|
172754
174410
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
172755
174411
|
if (lastEnd > 0) {
|
|
@@ -174971,7 +176627,14 @@ function startCompartmentAgent(deps) {
|
|
|
174971
176627
|
return;
|
|
174972
176628
|
}
|
|
174973
176629
|
const renewal = startLeaseRenewal(deps, holderId);
|
|
174974
|
-
|
|
176630
|
+
let realRunStarted = false;
|
|
176631
|
+
const runnerDeps = withPublishedCallback({
|
|
176632
|
+
...deps,
|
|
176633
|
+
compartmentLeaseHolderId: holderId,
|
|
176634
|
+
onHistorianRunStarted: () => {
|
|
176635
|
+
realRunStarted = true;
|
|
176636
|
+
}
|
|
176637
|
+
});
|
|
174975
176638
|
const promise2 = runCompartmentAgent(runnerDeps).catch((err) => {
|
|
174976
176639
|
sessionLog(deps.sessionId, "compartment agent: unhandled rejection:", err);
|
|
174977
176640
|
try {
|
|
@@ -174985,6 +176648,9 @@ function startCompartmentAgent(deps) {
|
|
|
174985
176648
|
}
|
|
174986
176649
|
});
|
|
174987
176650
|
activeRuns.set(deps.sessionId, { promise: promise2, published: false });
|
|
176651
|
+
if (!realRunStarted && activeRuns.get(deps.sessionId)?.promise === promise2) {
|
|
176652
|
+
activeRuns.delete(deps.sessionId);
|
|
176653
|
+
}
|
|
174988
176654
|
}
|
|
174989
176655
|
async function executeContextRecompWithResult(deps, options = {}) {
|
|
174990
176656
|
const { sessionId } = deps;
|
|
@@ -175119,7 +176785,7 @@ function applyMemoryMigration(db, projectPath, result) {
|
|
|
175119
176785
|
inserted++;
|
|
175120
176786
|
}
|
|
175121
176787
|
if (removed > 0 || inserted > 0) {
|
|
175122
|
-
|
|
176788
|
+
bumpEpochsForWorkspaceMembers(db, projectPath);
|
|
175123
176789
|
}
|
|
175124
176790
|
})();
|
|
175125
176791
|
return { removed, inserted };
|
|
@@ -175419,6 +177085,11 @@ async function runManagedRecomp(ctx, sessionId, options) {
|
|
|
175419
177085
|
try {
|
|
175420
177086
|
const message = await executeContextRecomp(buildRecompDeps(ctx, sessionId), options);
|
|
175421
177087
|
const terminalPhase = isRecompSkip(message) ? "skipped" : isRecompFailure(message) ? "failed" : "done";
|
|
177088
|
+
if (terminalPhase === "done") {
|
|
177089
|
+
try {
|
|
177090
|
+
clearEmergencyRecovery(ctx.db, sessionId);
|
|
177091
|
+
} catch {}
|
|
177092
|
+
}
|
|
175422
177093
|
setRecompTerminal(ctx.liveSessionState, sessionId, terminalPhase, extractRecompReason(message));
|
|
175423
177094
|
return message;
|
|
175424
177095
|
} catch (error51) {
|
|
@@ -175517,6 +177188,7 @@ var RECOMP_DONE_GRACE_MS = 30000;
|
|
|
175517
177188
|
var init_recomp_orchestrator = __esm(async () => {
|
|
175518
177189
|
init_compartment_storage();
|
|
175519
177190
|
init_project_identity2();
|
|
177191
|
+
init_storage_meta_persisted();
|
|
175520
177192
|
await __promiseAll([
|
|
175521
177193
|
init_memory_migration(),
|
|
175522
177194
|
init_compartment_runner()
|
|
@@ -175577,15 +177249,15 @@ function shouldShowAnnouncement() {
|
|
|
175577
177249
|
}
|
|
175578
177250
|
return state.version !== ANNOUNCEMENT_VERSION;
|
|
175579
177251
|
}
|
|
175580
|
-
var ANNOUNCEMENT_VERSION = "0.
|
|
177252
|
+
var ANNOUNCEMENT_VERSION = "0.24.0", ANNOUNCEMENT_FEATURES, ANNOUNCEMENT_FOOTER = "Join us on Discord: https://discord.gg/F2uWxjGnU", STATE_FILENAME = "last_announced_version";
|
|
175581
177253
|
var init_announcement = __esm(() => {
|
|
175582
177254
|
init_data_path();
|
|
175583
177255
|
ANNOUNCEMENT_FEATURES = [
|
|
175584
|
-
"
|
|
175585
|
-
"
|
|
175586
|
-
"
|
|
175587
|
-
"
|
|
175588
|
-
"
|
|
177256
|
+
"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).",
|
|
177257
|
+
"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.",
|
|
177258
|
+
"Pi: fixed sessions overflowing the model context while still showing moderate usage — Pi now sheds context before a tool-heavy turn overflows.",
|
|
177259
|
+
"Fewer prompt-cache busts: doc edits, processed screenshots, and a rebuild-then-bust-again case no longer re-bill large prompt prefixes.",
|
|
177260
|
+
"Setup wizard now lists your actual models with type-ahead instead of fixed recommendations, and explains the historian/dreamer roles (issue #144). Plus a GitHub Copilot tool-pairing fix (#135)."
|
|
175589
177261
|
];
|
|
175590
177262
|
});
|
|
175591
177263
|
// src/agents/permissions.ts
|
|
@@ -176313,6 +177985,10 @@ function getMagicContextBuiltinCommands() {
|
|
|
176313
177985
|
"ctx-dream": {
|
|
176314
177986
|
template: "ctx-dream",
|
|
176315
177987
|
description: "Run the hidden dreamer maintenance pass for this project now"
|
|
177988
|
+
},
|
|
177989
|
+
"ctx-embed-history": {
|
|
177990
|
+
template: "ctx-embed-history",
|
|
177991
|
+
description: "Embed all of this session's history compartments for semantic search, in one pass"
|
|
176316
177992
|
}
|
|
176317
177993
|
};
|
|
176318
177994
|
}
|
|
@@ -176806,7 +178482,7 @@ await init_storage_db();
|
|
|
176806
178482
|
// src/features/magic-context/v22-deferred-backfill.ts
|
|
176807
178483
|
init_logger();
|
|
176808
178484
|
init_project_identity();
|
|
176809
|
-
import { createHash as
|
|
178485
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
176810
178486
|
import { realpathSync as realpathSync2 } from "node:fs";
|
|
176811
178487
|
import path5 from "node:path";
|
|
176812
178488
|
var BATCH_SIZE = 25;
|
|
@@ -176860,7 +178536,7 @@ function computeLegacyRustDirIdentity(rawProjectPath) {
|
|
|
176860
178536
|
} catch {
|
|
176861
178537
|
canonical = path5.isAbsolute(rawProjectPath) ? rawProjectPath : path5.join(process.cwd(), rawProjectPath);
|
|
176862
178538
|
}
|
|
176863
|
-
return `dir:${
|
|
178539
|
+
return `dir:${createHash6("sha256").update(canonical, "utf8").digest("hex")}`;
|
|
176864
178540
|
}
|
|
176865
178541
|
function upsertRekeyMap(db, oldProjectPath, newProjectPath, rekeyedAt) {
|
|
176866
178542
|
db.prepare(`INSERT INTO v22_identity_rekey_map (old_project_path, new_project_path, rekeyed_at)
|
|
@@ -179401,7 +181077,7 @@ init_project_identity();
|
|
|
179401
181077
|
// src/plugin/embedding-bootstrap-helpers.ts
|
|
179402
181078
|
init_embedding();
|
|
179403
181079
|
init_logger();
|
|
179404
|
-
import { createHash as
|
|
181080
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
179405
181081
|
var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
179406
181082
|
"embedding.api_key",
|
|
179407
181083
|
"embedding.endpoint",
|
|
@@ -179422,7 +181098,7 @@ var EMBEDDING_WARNING_TERMS = [
|
|
|
179422
181098
|
];
|
|
179423
181099
|
var loggedFailureSignatures = new Map;
|
|
179424
181100
|
function sha256Prefix2(value, length = 16) {
|
|
179425
|
-
return
|
|
181101
|
+
return createHash10("sha256").update(value).digest("hex").slice(0, length);
|
|
179426
181102
|
}
|
|
179427
181103
|
function warningLooksEmbeddingRelated(message) {
|
|
179428
181104
|
const lower = message.toLowerCase();
|
|
@@ -180058,6 +181734,7 @@ function createTagger() {
|
|
|
180058
181734
|
// src/hooks/magic-context/hook.ts
|
|
180059
181735
|
init_magic_context();
|
|
180060
181736
|
init_project_identity();
|
|
181737
|
+
init_project_embedding_registry();
|
|
180061
181738
|
await init_storage();
|
|
180062
181739
|
init_logger();
|
|
180063
181740
|
init_resolve_fallbacks();
|
|
@@ -180651,6 +182328,7 @@ function createMagicContextCommandHandler(deps) {
|
|
|
180651
182328
|
const isAugCommand = (command) => command === "ctx-aug";
|
|
180652
182329
|
const isDreamCommand = (command) => command === "ctx-dream";
|
|
180653
182330
|
const isSessionUpgradeCommand = (command) => command === "ctx-session-upgrade";
|
|
182331
|
+
const isEmbedHistoryCommand = (command) => command === "ctx-embed-history";
|
|
180654
182332
|
return {
|
|
180655
182333
|
"command.execute.before": async (input, _output, _params) => {
|
|
180656
182334
|
const isStatus = isStatusCommand(input.command);
|
|
@@ -180659,7 +182337,8 @@ function createMagicContextCommandHandler(deps) {
|
|
|
180659
182337
|
const isAug = isAugCommand(input.command);
|
|
180660
182338
|
const isDream = isDreamCommand(input.command);
|
|
180661
182339
|
const isSessionUpgrade = isSessionUpgradeCommand(input.command);
|
|
180662
|
-
|
|
182340
|
+
const isEmbedHistory = isEmbedHistoryCommand(input.command);
|
|
182341
|
+
if (!isStatus && !isFlush && !isRecomp && !isAug && !isDream && !isSessionUpgrade && !isEmbedHistory) {
|
|
180663
182342
|
return;
|
|
180664
182343
|
}
|
|
180665
182344
|
const sessionId = input.sessionID;
|
|
@@ -180672,6 +182351,11 @@ function createMagicContextCommandHandler(deps) {
|
|
|
180672
182351
|
await executeDreaming(deps, sessionId);
|
|
180673
182352
|
return;
|
|
180674
182353
|
}
|
|
182354
|
+
if (isEmbedHistory) {
|
|
182355
|
+
const summary = deps.executeEmbedHistory ? await deps.executeEmbedHistory(sessionId) : "Semantic embedding is not configured for this project, so there is nothing to embed.";
|
|
182356
|
+
await deps.sendNotification(sessionId, summary, {});
|
|
182357
|
+
throwSentinel(input.command);
|
|
182358
|
+
}
|
|
180675
182359
|
if (isFlush) {
|
|
180676
182360
|
result = executeFlush(deps.db, sessionId);
|
|
180677
182361
|
clearCachedM0M1(deps.db, sessionId);
|
|
@@ -181039,8 +182723,8 @@ var CHANNEL1_SENTINEL = "<system-reminder>";
|
|
|
181039
182723
|
var TOKENS_PER_BYTE = 0.25;
|
|
181040
182724
|
var CHANNEL1_FLOOR_TOKENS = 1e4;
|
|
181041
182725
|
var CHANNEL1_REFIRE_FLOOR_TOKENS = 1e4;
|
|
181042
|
-
function channel1RefireTokens(
|
|
181043
|
-
const scaled = Math.round(0.05 * Math.max(0,
|
|
182726
|
+
function channel1RefireTokens(workingWindowTokens) {
|
|
182727
|
+
const scaled = Math.round(0.05 * Math.max(0, workingWindowTokens));
|
|
181044
182728
|
return Math.max(CHANNEL1_REFIRE_FLOOR_TOKENS, scaled);
|
|
181045
182729
|
}
|
|
181046
182730
|
var S_GENTLE = 0.2;
|
|
@@ -181110,7 +182794,7 @@ function computeTailTokenEstimate(messages) {
|
|
|
181110
182794
|
};
|
|
181111
182795
|
}
|
|
181112
182796
|
function decideChannel1(input) {
|
|
181113
|
-
const { undroppedTokens, pressure,
|
|
182797
|
+
const { undroppedTokens, pressure, workingWindowTokens, hasRecentReduce } = input;
|
|
181114
182798
|
const resetCycle = hasRecentReduce || undroppedTokens < input.lastNudgeUndropped;
|
|
181115
182799
|
const lastNudge = resetCycle ? 0 : input.lastNudgeUndropped;
|
|
181116
182800
|
const lastLevel = resetCycle ? "" : input.lastNudgeLevel;
|
|
@@ -181125,7 +182809,7 @@ function decideChannel1(input) {
|
|
|
181125
182809
|
return quiet();
|
|
181126
182810
|
if (undroppedTokens < CHANNEL1_FLOOR_TOKENS)
|
|
181127
182811
|
return quiet();
|
|
181128
|
-
const budget =
|
|
182812
|
+
const budget = workingWindowTokens > 0 ? workingWindowTokens : undroppedTokens || 1;
|
|
181129
182813
|
const severity = undroppedTokens / budget * pressure;
|
|
181130
182814
|
if (severity < S_GENTLE)
|
|
181131
182815
|
return quiet();
|
|
@@ -181137,7 +182821,7 @@ function decideChannel1(input) {
|
|
|
181137
182821
|
else
|
|
181138
182822
|
level = "gentle";
|
|
181139
182823
|
if (lastLevel === "") {
|
|
181140
|
-
if (undroppedTokens < lastNudge + channel1RefireTokens(
|
|
182824
|
+
if (undroppedTokens < lastNudge + channel1RefireTokens(workingWindowTokens)) {
|
|
181141
182825
|
return quiet();
|
|
181142
182826
|
}
|
|
181143
182827
|
} else if (LEVEL_RANK[level] <= LEVEL_RANK[lastLevel]) {
|
|
@@ -181182,13 +182866,13 @@ function buildChannel1Reminder(level, undroppedTokens) {
|
|
|
181182
182866
|
let body;
|
|
181183
182867
|
switch (level) {
|
|
181184
182868
|
case "gentle":
|
|
181185
|
-
body = `You have ~${amount} tokens of tool output you have not reduced. ` + `
|
|
182869
|
+
body = `You have ~${amount} tokens of tool output you have not reduced. ` + `When you are done with earlier outputs, dropping them with ctx_reduce keeps context lean.`;
|
|
181186
182870
|
break;
|
|
181187
182871
|
case "firm":
|
|
181188
|
-
body = `~${amount} tokens of unreduced tool output
|
|
182872
|
+
body = `~${amount} tokens of unreduced tool output has built up. ` + `At your next natural stopping point, consider dropping what you have already processed with ctx_reduce.`;
|
|
181189
182873
|
break;
|
|
181190
182874
|
case "urgent":
|
|
181191
|
-
body = `~${amount} tokens of unreduced tool output remain
|
|
182875
|
+
body = `~${amount} tokens of unreduced tool output remain, and a large span of this session will be comparted before long. ` + `Consider dropping spent outputs with ctx_reduce so the archived span is the part that matters.`;
|
|
181192
182876
|
break;
|
|
181193
182877
|
}
|
|
181194
182878
|
return `
|
|
@@ -181412,6 +183096,7 @@ await init_read_session_chunk();
|
|
|
181412
183096
|
// src/hooks/magic-context/transform.ts
|
|
181413
183097
|
init_project_identity();
|
|
181414
183098
|
import * as crypto2 from "node:crypto";
|
|
183099
|
+
init_session_project_storage();
|
|
181415
183100
|
init_storage_meta_persisted();
|
|
181416
183101
|
init_logger();
|
|
181417
183102
|
await init_storage();
|
|
@@ -182012,6 +183697,7 @@ await __promiseAll([
|
|
|
182012
183697
|
init_read_session_chunk(),
|
|
182013
183698
|
init_read_session_db()
|
|
182014
183699
|
]);
|
|
183700
|
+
|
|
182015
183701
|
// src/hooks/magic-context/sentinel.ts
|
|
182016
183702
|
var WHOLE_MESSAGE_PLACEHOLDER_TEXT = "[dropped]";
|
|
182017
183703
|
function modelAcceptsEmptyContent(providerID) {
|
|
@@ -182069,7 +183755,6 @@ function replaySentinelByMessageIds(messages, ids, providerID) {
|
|
|
182069
183755
|
missingIds.push(id);
|
|
182070
183756
|
return { replayed, missingIds };
|
|
182071
183757
|
}
|
|
182072
|
-
|
|
182073
183758
|
// src/hooks/magic-context/strip-content.ts
|
|
182074
183759
|
var DROPPED_PLACEHOLDER_PATTERN = /^\[dropped §\d+§\]$/;
|
|
182075
183760
|
var TAG_PREFIX_PATTERN = /^§\d+§\s*/;
|
|
@@ -182422,8 +184107,10 @@ function stripReasoningFromMergedAssistants(messages, providerID) {
|
|
|
182422
184107
|
}
|
|
182423
184108
|
return stripped;
|
|
182424
184109
|
}
|
|
182425
|
-
function stripProcessedImages(messages,
|
|
184110
|
+
function stripProcessedImages(messages, frozenIds, options) {
|
|
184111
|
+
const { detect, watermark, messageTagNumbers } = options;
|
|
182426
184112
|
let stripped = 0;
|
|
184113
|
+
const newlyStrippedIds = [];
|
|
182427
184114
|
let hasAssistantResponse = false;
|
|
182428
184115
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
182429
184116
|
const msg = messages[i];
|
|
@@ -182431,13 +184118,17 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
182431
184118
|
hasAssistantResponse = true;
|
|
182432
184119
|
continue;
|
|
182433
184120
|
}
|
|
182434
|
-
if (msg.info.role !== "user"
|
|
184121
|
+
if (msg.info.role !== "user") {
|
|
182435
184122
|
continue;
|
|
182436
184123
|
}
|
|
184124
|
+
const id = typeof msg.info.id === "string" ? msg.info.id : undefined;
|
|
184125
|
+
const inFrozen = id !== undefined && frozenIds.has(id);
|
|
182437
184126
|
const maxTag = messageTagNumbers.get(msg) ?? 0;
|
|
182438
|
-
|
|
184127
|
+
const isNewDetection = !inFrozen && detect && hasAssistantResponse && id !== undefined && maxTag <= watermark;
|
|
184128
|
+
if (!inFrozen && !isNewDetection) {
|
|
182439
184129
|
continue;
|
|
182440
184130
|
}
|
|
184131
|
+
let touchedThisMsg = false;
|
|
182441
184132
|
for (let j = 0;j < msg.parts.length; j++) {
|
|
182442
184133
|
const part = msg.parts[j];
|
|
182443
184134
|
if (!isRecord(part) || part.type !== "file") {
|
|
@@ -182449,10 +184140,14 @@ function stripProcessedImages(messages, watermark, messageTagNumbers) {
|
|
|
182449
184140
|
if (typeof part.url === "string" && part.url.startsWith("data:") && part.url.length > 200) {
|
|
182450
184141
|
msg.parts[j] = makeSentinel(part);
|
|
182451
184142
|
stripped++;
|
|
184143
|
+
touchedThisMsg = true;
|
|
182452
184144
|
}
|
|
182453
184145
|
}
|
|
184146
|
+
if (touchedThisMsg && isNewDetection && id !== undefined) {
|
|
184147
|
+
newlyStrippedIds.push(id);
|
|
184148
|
+
}
|
|
182454
184149
|
}
|
|
182455
|
-
return stripped;
|
|
184150
|
+
return { stripped, newlyStrippedIds };
|
|
182456
184151
|
}
|
|
182457
184152
|
|
|
182458
184153
|
// src/hooks/magic-context/transform.ts
|
|
@@ -182765,8 +184460,55 @@ function appendReminderToUserMessage(message, reminder) {
|
|
|
182765
184460
|
}
|
|
182766
184461
|
|
|
182767
184462
|
// src/hooks/magic-context/apply-operations.ts
|
|
182768
|
-
init_tag_part_guards();
|
|
182769
184463
|
await init_storage();
|
|
184464
|
+
|
|
184465
|
+
// src/hooks/magic-context/system-injection-stripper.ts
|
|
184466
|
+
var SYSTEM_INJECTION_MARKERS = [
|
|
184467
|
+
"<!-- OMO_INTERNAL_INITIATOR -->",
|
|
184468
|
+
"[SYSTEM DIRECTIVE: MAGIC-CONTEXT",
|
|
184469
|
+
"[SYSTEM DIRECTIVE: OH-MY-OPENCODE",
|
|
184470
|
+
"[Category+Skill Reminder]",
|
|
184471
|
+
"[EDIT ERROR - IMMEDIATE ACTION REQUIRED]",
|
|
184472
|
+
"[task CALL FAILED - IMMEDIATE RETRY REQUIRED]",
|
|
184473
|
+
"[EMERGENCY CONTEXT WINDOW WARNING]",
|
|
184474
|
+
"Unstable background agent appears idle",
|
|
184475
|
+
"**THE SUBAGENT JUST CLAIMED THIS TASK IS DONE."
|
|
184476
|
+
];
|
|
184477
|
+
var SYSTEM_REMINDER_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
184478
|
+
var OMO_MARKER_REGEX = /<!-- OMO_INTERNAL_INITIATOR -->/g;
|
|
184479
|
+
function stripSystemInjection(text) {
|
|
184480
|
+
let hasInjection = false;
|
|
184481
|
+
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
184482
|
+
if (text.includes(marker)) {
|
|
184483
|
+
hasInjection = true;
|
|
184484
|
+
break;
|
|
184485
|
+
}
|
|
184486
|
+
}
|
|
184487
|
+
if (SYSTEM_REMINDER_REGEX.test(text))
|
|
184488
|
+
hasInjection = true;
|
|
184489
|
+
SYSTEM_REMINDER_REGEX.lastIndex = 0;
|
|
184490
|
+
if (!hasInjection)
|
|
184491
|
+
return null;
|
|
184492
|
+
let cleaned = text;
|
|
184493
|
+
cleaned = cleaned.replace(SYSTEM_REMINDER_REGEX, "");
|
|
184494
|
+
cleaned = cleaned.replace(OMO_MARKER_REGEX, "");
|
|
184495
|
+
cleaned = cleaned.replace(/\[SYSTEM DIRECTIVE: OH-MY-(?:OPENCODE|CLAUDE)[^\]]*\][\s\S]*?(?=\n\n(?!\s*[-*])|$)/g, "");
|
|
184496
|
+
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
184497
|
+
if (marker.startsWith("<!-- ") || marker.startsWith("[SYSTEM DIRECTIVE"))
|
|
184498
|
+
continue;
|
|
184499
|
+
const idx = cleaned.indexOf(marker);
|
|
184500
|
+
if (idx === -1)
|
|
184501
|
+
continue;
|
|
184502
|
+
const blockEnd = cleaned.indexOf(`
|
|
184503
|
+
|
|
184504
|
+
`, idx + marker.length);
|
|
184505
|
+
cleaned = blockEnd !== -1 ? cleaned.slice(0, idx) + cleaned.slice(blockEnd) : cleaned.slice(0, idx);
|
|
184506
|
+
}
|
|
184507
|
+
return cleaned.trim();
|
|
184508
|
+
}
|
|
184509
|
+
|
|
184510
|
+
// src/hooks/magic-context/apply-operations.ts
|
|
184511
|
+
init_tag_part_guards();
|
|
182770
184512
|
var USER_DROP_PREVIEW_CHARS = 250;
|
|
182771
184513
|
var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
182772
184514
|
function buildReplacementContent(tagId, target) {
|
|
@@ -182775,6 +184517,10 @@ function buildReplacementContent(tagId, target) {
|
|
|
182775
184517
|
return `[dropped §${tagId}§]`;
|
|
182776
184518
|
}
|
|
182777
184519
|
const currentContent = target.getContent?.() ?? "";
|
|
184520
|
+
const strippedInjection = stripSystemInjection(currentContent);
|
|
184521
|
+
if (strippedInjection !== null && stripTagPrefix(strippedInjection).trim().length === 0) {
|
|
184522
|
+
return `[dropped §${tagId}§]`;
|
|
184523
|
+
}
|
|
182778
184524
|
const originalText = stripTagPrefix(currentContent);
|
|
182779
184525
|
if (originalText.length <= USER_DROP_PREVIEW_CHARS) {
|
|
182780
184526
|
return `[truncated §${tagId}§]
|
|
@@ -183395,6 +185141,7 @@ init_embedding();
|
|
|
183395
185141
|
|
|
183396
185142
|
// src/features/magic-context/search.ts
|
|
183397
185143
|
init_logger();
|
|
185144
|
+
init_compartment_chunk_embedding();
|
|
183398
185145
|
|
|
183399
185146
|
// src/features/magic-context/literal-probes.ts
|
|
183400
185147
|
var MAX_PROBES = 5;
|
|
@@ -183456,6 +185203,7 @@ function containsProbeVerbatim(text, probes) {
|
|
|
183456
185203
|
init_memory();
|
|
183457
185204
|
init_embedding();
|
|
183458
185205
|
init_storage_memory_fts();
|
|
185206
|
+
init_workspaces();
|
|
183459
185207
|
var DEFAULT_UNIFIED_SEARCH_LIMIT = 10;
|
|
183460
185208
|
var FTS_SEMANTIC_CANDIDATE_LIMIT = 50;
|
|
183461
185209
|
var SEMANTIC_WEIGHT = 0.7;
|
|
@@ -183485,6 +185233,37 @@ function previewText(text) {
|
|
|
183485
185233
|
}
|
|
183486
185234
|
return `${normalized.slice(0, RESULT_PREVIEW_LIMIT - 1).trimEnd()}…`;
|
|
183487
185235
|
}
|
|
185236
|
+
function resolveSearchWorkspaceContext(db, projectPath, identitySet) {
|
|
185237
|
+
const resolved = identitySet ?? resolveWorkspaceIdentitySet(db, projectPath);
|
|
185238
|
+
const isWorkspaced = resolved.identities.length > 1;
|
|
185239
|
+
const expanded = expandWorkspaceIdentitySetWithAliases(db, resolved.identities);
|
|
185240
|
+
const expandedIdentities = isWorkspaced ? expanded.expandedIdentities : resolved.identities;
|
|
185241
|
+
const canonicalIdentityByStoredPath = isWorkspaced ? expanded.canonicalIdentityByStoredPath : new Map(resolved.identities.map((identity) => [identity, identity]));
|
|
185242
|
+
const ownIdentities = expandedIdentities.filter((identity) => canonicalIdentityByStoredPath.get(identity) === projectPath);
|
|
185243
|
+
return {
|
|
185244
|
+
identities: resolved.identities,
|
|
185245
|
+
expandedIdentities,
|
|
185246
|
+
ownIdentities,
|
|
185247
|
+
shareCategories: isWorkspaced ? resolveWorkspaceShareCategories(db, projectPath) : null,
|
|
185248
|
+
namesByIdentity: resolved.namesByIdentity,
|
|
185249
|
+
canonicalIdentityByStoredPath,
|
|
185250
|
+
isWorkspaced
|
|
185251
|
+
};
|
|
185252
|
+
}
|
|
185253
|
+
function memoryWorkspaceIdentity(memory, workspace) {
|
|
185254
|
+
return resolveStoredPathWorkspaceIdentity(memory.projectPath, workspace.identities, workspace.canonicalIdentityByStoredPath);
|
|
185255
|
+
}
|
|
185256
|
+
function sourceNamesForSearchMemories(args) {
|
|
185257
|
+
if (!args.workspace.isWorkspaced)
|
|
185258
|
+
return;
|
|
185259
|
+
const sourceNames = new Map;
|
|
185260
|
+
for (const memory of args.memories) {
|
|
185261
|
+
const source = sourceNameForMemory(memory.projectPath, args.projectPath, args.workspace.identities, args.workspace.namesByIdentity, args.workspace.canonicalIdentityByStoredPath);
|
|
185262
|
+
if (source)
|
|
185263
|
+
sourceNames.set(memory.id, source);
|
|
185264
|
+
}
|
|
185265
|
+
return sourceNames.size > 0 ? sourceNames : undefined;
|
|
185266
|
+
}
|
|
183488
185267
|
function getMessageSearchStatement(db) {
|
|
183489
185268
|
let stmt = messageSearchStatements.get(db);
|
|
183490
185269
|
if (!stmt) {
|
|
@@ -183493,6 +185272,30 @@ function getMessageSearchStatement(db) {
|
|
|
183493
185272
|
}
|
|
183494
185273
|
return stmt;
|
|
183495
185274
|
}
|
|
185275
|
+
var ftsRowCountStatements = new WeakMap;
|
|
185276
|
+
var ftsMatchCountStatements = new WeakMap;
|
|
185277
|
+
function getSessionFtsRowCount(db, sessionId) {
|
|
185278
|
+
let stmt = ftsRowCountStatements.get(db);
|
|
185279
|
+
if (!stmt) {
|
|
185280
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ?");
|
|
185281
|
+
ftsRowCountStatements.set(db, stmt);
|
|
185282
|
+
}
|
|
185283
|
+
const row = stmt.get(sessionId);
|
|
185284
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
185285
|
+
}
|
|
185286
|
+
function countSessionFtsMatches(db, sessionId, ftsQuery) {
|
|
185287
|
+
let stmt = ftsMatchCountStatements.get(db);
|
|
185288
|
+
if (!stmt) {
|
|
185289
|
+
stmt = db.prepare("SELECT COUNT(*) AS n FROM message_history_fts WHERE session_id = ? AND message_history_fts MATCH ?");
|
|
185290
|
+
ftsMatchCountStatements.set(db, stmt);
|
|
185291
|
+
}
|
|
185292
|
+
try {
|
|
185293
|
+
const row = stmt.get(sessionId, ftsQuery);
|
|
185294
|
+
return typeof row?.n === "number" ? row.n : 0;
|
|
185295
|
+
} catch {
|
|
185296
|
+
return 0;
|
|
185297
|
+
}
|
|
185298
|
+
}
|
|
183496
185299
|
function getMessageOrdinal(value) {
|
|
183497
185300
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
183498
185301
|
return value;
|
|
@@ -183508,25 +185311,63 @@ async function getSemanticScores(args) {
|
|
|
183508
185311
|
if (!args.queryEmbedding || args.memories.length === 0) {
|
|
183509
185312
|
return semanticScores;
|
|
183510
185313
|
}
|
|
183511
|
-
|
|
183512
|
-
|
|
183513
|
-
|
|
183514
|
-
|
|
183515
|
-
|
|
183516
|
-
|
|
183517
|
-
|
|
185314
|
+
if (!args.workspace?.isWorkspaced) {
|
|
185315
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
185316
|
+
const embeddings = await ensureMemoryEmbeddings({
|
|
185317
|
+
db: args.db,
|
|
185318
|
+
projectIdentity: args.projectPath,
|
|
185319
|
+
memories: args.memories,
|
|
185320
|
+
existingEmbeddings: cachedEmbeddings
|
|
185321
|
+
});
|
|
185322
|
+
for (const memory of args.memories) {
|
|
185323
|
+
const memoryEmbedding = embeddings.get(memory.id);
|
|
185324
|
+
if (!memoryEmbedding) {
|
|
185325
|
+
continue;
|
|
185326
|
+
}
|
|
185327
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
185328
|
+
}
|
|
185329
|
+
return semanticScores;
|
|
185330
|
+
}
|
|
185331
|
+
if (!args.queryModelId || args.queryModelId === "off") {
|
|
185332
|
+
return semanticScores;
|
|
185333
|
+
}
|
|
185334
|
+
const workspace = args.workspace;
|
|
185335
|
+
const memoriesByIdentity = new Map;
|
|
183518
185336
|
for (const memory of args.memories) {
|
|
183519
|
-
const
|
|
183520
|
-
if (!
|
|
185337
|
+
const identity = memoryWorkspaceIdentity(memory, workspace);
|
|
185338
|
+
if (!identity)
|
|
185339
|
+
continue;
|
|
185340
|
+
const list = memoriesByIdentity.get(identity) ?? [];
|
|
185341
|
+
list.push(memory);
|
|
185342
|
+
memoriesByIdentity.set(identity, list);
|
|
185343
|
+
}
|
|
185344
|
+
const ownMemories = memoriesByIdentity.get(args.projectPath) ?? [];
|
|
185345
|
+
if (ownMemories.length > 0) {
|
|
185346
|
+
const ownEmbeddings = getProjectEmbeddings(args.db, args.projectPath);
|
|
185347
|
+
await ensureMemoryEmbeddings({
|
|
185348
|
+
db: args.db,
|
|
185349
|
+
projectIdentity: args.projectPath,
|
|
185350
|
+
memories: ownMemories,
|
|
185351
|
+
existingEmbeddings: ownEmbeddings
|
|
185352
|
+
});
|
|
185353
|
+
}
|
|
185354
|
+
for (const identity of workspace.identities) {
|
|
185355
|
+
const memberMemories = memoriesByIdentity.get(identity) ?? [];
|
|
185356
|
+
if (memberMemories.length === 0)
|
|
183521
185357
|
continue;
|
|
185358
|
+
const cachedEmbeddings = getProjectEmbeddings(args.db, identity);
|
|
185359
|
+
for (const memory of memberMemories) {
|
|
185360
|
+
const memoryEmbedding = cachedEmbeddings.get(memory.id);
|
|
185361
|
+
if (!memoryEmbedding || memoryEmbedding.modelId !== args.queryModelId)
|
|
185362
|
+
continue;
|
|
185363
|
+
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding.embedding)));
|
|
183522
185364
|
}
|
|
183523
|
-
semanticScores.set(memory.id, normalizeCosineScore(cosineSimilarity(args.queryEmbedding, memoryEmbedding)));
|
|
183524
185365
|
}
|
|
183525
185366
|
return semanticScores;
|
|
183526
185367
|
}
|
|
183527
185368
|
function getFtsMatches(args) {
|
|
183528
185369
|
try {
|
|
183529
|
-
return searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
185370
|
+
return args.workspace?.isWorkspaced ? searchMemoriesFTSUnion(args.db, args.workspace.expandedIdentities, args.query, args.limit, args.workspace.ownIdentities, args.workspace.shareCategories) : searchMemoriesFTS(args.db, args.projectPath, args.query, args.limit);
|
|
183530
185371
|
} catch (error51) {
|
|
183531
185372
|
log(`[search] FTS query failed for "${args.query}": ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
183532
185373
|
return [];
|
|
@@ -183540,8 +185381,11 @@ function selectSemanticCandidates(args) {
|
|
|
183540
185381
|
return args.memories;
|
|
183541
185382
|
}
|
|
183542
185383
|
const candidateIds = new Set(args.ftsMatches.map((memory) => memory.id));
|
|
183543
|
-
const
|
|
183544
|
-
|
|
185384
|
+
const embeddingProjects = args.workspace?.isWorkspaced ? args.workspace.identities : [args.projectPath];
|
|
185385
|
+
for (const projectPath of embeddingProjects) {
|
|
185386
|
+
const cachedEmbeddings = peekProjectEmbeddings(projectPath);
|
|
185387
|
+
if (!cachedEmbeddings)
|
|
185388
|
+
continue;
|
|
183545
185389
|
for (const memoryId of cachedEmbeddings.keys()) {
|
|
183546
185390
|
candidateIds.add(memoryId);
|
|
183547
185391
|
}
|
|
@@ -183583,7 +185427,8 @@ function mergeMemoryResults(args) {
|
|
|
183583
185427
|
score,
|
|
183584
185428
|
memoryId: memory.id,
|
|
183585
185429
|
category: memory.category,
|
|
183586
|
-
matchType
|
|
185430
|
+
matchType,
|
|
185431
|
+
sourceName: args.sourceNameByMemoryId?.get(memory.id)
|
|
183587
185432
|
});
|
|
183588
185433
|
}
|
|
183589
185434
|
return results.sort((left, right) => {
|
|
@@ -183597,7 +185442,7 @@ async function searchMemories(args) {
|
|
|
183597
185442
|
if (!args.memoryEnabled) {
|
|
183598
185443
|
return [];
|
|
183599
185444
|
}
|
|
183600
|
-
const memories = getMemoriesByProject(args.db, args.projectPath);
|
|
185445
|
+
const memories = args.workspace?.isWorkspaced ? getMemoriesByProjects(args.db, args.workspace.expandedIdentities, ["active", "permanent"], Date.now(), args.workspace.ownIdentities, args.workspace.shareCategories) : getMemoriesByProject(args.db, args.projectPath);
|
|
183601
185446
|
if (memories.length === 0) {
|
|
183602
185447
|
return [];
|
|
183603
185448
|
}
|
|
@@ -183605,26 +185450,43 @@ async function searchMemories(args) {
|
|
|
183605
185450
|
db: args.db,
|
|
183606
185451
|
projectPath: args.projectPath,
|
|
183607
185452
|
query: args.query,
|
|
183608
|
-
limit: FTS_SEMANTIC_CANDIDATE_LIMIT
|
|
185453
|
+
limit: FTS_SEMANTIC_CANDIDATE_LIMIT,
|
|
185454
|
+
workspace: args.workspace
|
|
183609
185455
|
});
|
|
183610
185456
|
const ftsScores = getFtsScores(ftsMatches);
|
|
183611
185457
|
const semanticCandidates = selectSemanticCandidates({
|
|
183612
185458
|
memories,
|
|
183613
185459
|
projectPath: args.projectPath,
|
|
183614
|
-
ftsMatches
|
|
185460
|
+
ftsMatches,
|
|
185461
|
+
workspace: args.workspace
|
|
183615
185462
|
});
|
|
183616
185463
|
const semanticScores = await getSemanticScores({
|
|
183617
185464
|
db: args.db,
|
|
183618
185465
|
projectPath: args.projectPath,
|
|
183619
185466
|
memories: semanticCandidates,
|
|
183620
|
-
queryEmbedding: args.queryEmbedding
|
|
185467
|
+
queryEmbedding: args.queryEmbedding,
|
|
185468
|
+
queryModelId: args.queryModelId,
|
|
185469
|
+
workspace: args.workspace
|
|
183621
185470
|
});
|
|
183622
185471
|
return mergeMemoryResults({
|
|
183623
185472
|
memories,
|
|
183624
185473
|
semanticScores,
|
|
183625
185474
|
ftsScores,
|
|
183626
185475
|
limit: args.limit,
|
|
183627
|
-
visibleMemoryIds: args.visibleMemoryIds
|
|
185476
|
+
visibleMemoryIds: args.visibleMemoryIds,
|
|
185477
|
+
sourceNameByMemoryId: sourceNamesForSearchMemories({
|
|
185478
|
+
memories,
|
|
185479
|
+
projectPath: args.projectPath,
|
|
185480
|
+
workspace: args.workspace ?? {
|
|
185481
|
+
identities: [args.projectPath],
|
|
185482
|
+
expandedIdentities: [args.projectPath],
|
|
185483
|
+
namesByIdentity: new Map,
|
|
185484
|
+
canonicalIdentityByStoredPath: new Map([[args.projectPath, args.projectPath]]),
|
|
185485
|
+
ownIdentities: [args.projectPath],
|
|
185486
|
+
shareCategories: null,
|
|
185487
|
+
isWorkspaced: false
|
|
185488
|
+
}
|
|
185489
|
+
})
|
|
183628
185490
|
});
|
|
183629
185491
|
}
|
|
183630
185492
|
function linearDecayScore(rank, total) {
|
|
@@ -183655,7 +185517,13 @@ function runMessageFtsQuery(db, sessionId, ftsQuery, fetchLimit, cutoff) {
|
|
|
183655
185517
|
return result;
|
|
183656
185518
|
}
|
|
183657
185519
|
var RRF_K = 60;
|
|
183658
|
-
var
|
|
185520
|
+
var VERBATIM_RANK_BONUS = 1 / RRF_K;
|
|
185521
|
+
var IDF_FALLOFF = 100;
|
|
185522
|
+
function probeDiscriminationWeight(df, corpusSize) {
|
|
185523
|
+
if (corpusSize <= 0 || df <= 0)
|
|
185524
|
+
return 1;
|
|
185525
|
+
return 1 / (1 + IDF_FALLOFF * df / corpusSize);
|
|
185526
|
+
}
|
|
183659
185527
|
function searchMessages(args) {
|
|
183660
185528
|
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
183661
185529
|
const fetchLimit = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.limit * 3 : args.limit;
|
|
@@ -183672,20 +185540,31 @@ function searchMessages(args) {
|
|
|
183672
185540
|
role: row.role
|
|
183673
185541
|
}));
|
|
183674
185542
|
}
|
|
185543
|
+
const corpusSize = getSessionFtsRowCount(args.db, args.sessionId);
|
|
183675
185544
|
const queryLists = [];
|
|
183676
185545
|
if (baseQuery.length > 0) {
|
|
183677
|
-
queryLists.push(
|
|
185546
|
+
queryLists.push({
|
|
185547
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, baseQuery, fetchLimit, cutoff),
|
|
185548
|
+
weight: 1
|
|
185549
|
+
});
|
|
183678
185550
|
}
|
|
185551
|
+
const probeWeights = new Map;
|
|
183679
185552
|
for (const probe of probes) {
|
|
183680
185553
|
const probeQuery = sanitizeFtsQuery(probe);
|
|
183681
185554
|
if (probeQuery.length === 0)
|
|
183682
185555
|
continue;
|
|
183683
|
-
|
|
185556
|
+
const df = countSessionFtsMatches(args.db, args.sessionId, probeQuery);
|
|
185557
|
+
const weight = probeDiscriminationWeight(df, corpusSize);
|
|
185558
|
+
probeWeights.set(probe, weight);
|
|
185559
|
+
queryLists.push({
|
|
185560
|
+
rows: runMessageFtsQuery(args.db, args.sessionId, probeQuery, fetchLimit, cutoff),
|
|
185561
|
+
weight
|
|
185562
|
+
});
|
|
183684
185563
|
}
|
|
183685
185564
|
const fused = new Map;
|
|
183686
185565
|
for (const list of queryLists) {
|
|
183687
|
-
list.forEach((row, rank) => {
|
|
183688
|
-
const rrf =
|
|
185566
|
+
list.rows.forEach((row, rank) => {
|
|
185567
|
+
const rrf = list.weight / (RRF_K + rank);
|
|
183689
185568
|
const existing = fused.get(row.messageId);
|
|
183690
185569
|
if (existing) {
|
|
183691
185570
|
existing.score += rrf;
|
|
@@ -183695,26 +185574,107 @@ function searchMessages(args) {
|
|
|
183695
185574
|
});
|
|
183696
185575
|
}
|
|
183697
185576
|
for (const entry of fused.values()) {
|
|
183698
|
-
|
|
183699
|
-
|
|
185577
|
+
let best = 0;
|
|
185578
|
+
for (const probe of probes) {
|
|
185579
|
+
const weight = probeWeights.get(probe) ?? 0;
|
|
185580
|
+
if (weight > best && containsProbeVerbatim(entry.row.content, [probe])) {
|
|
185581
|
+
best = weight;
|
|
185582
|
+
}
|
|
185583
|
+
}
|
|
185584
|
+
if (best > 0) {
|
|
185585
|
+
entry.score += best * VERBATIM_RANK_BONUS;
|
|
183700
185586
|
}
|
|
183701
185587
|
}
|
|
183702
185588
|
const ranked = [...fused.values()].sort((a, b) => b.score !== a.score ? b.score - a.score : a.row.messageOrdinal - b.row.messageOrdinal).slice(0, args.limit);
|
|
183703
|
-
|
|
183704
|
-
return ranked.map((entry) => ({
|
|
185589
|
+
return ranked.map((entry, rank) => ({
|
|
183705
185590
|
source: "message",
|
|
183706
185591
|
content: previewText(entry.row.content),
|
|
183707
|
-
score:
|
|
185592
|
+
score: linearDecayScore(rank, ranked.length),
|
|
183708
185593
|
messageOrdinal: entry.row.messageOrdinal,
|
|
183709
185594
|
messageId: entry.row.messageId,
|
|
183710
185595
|
role: entry.row.role
|
|
183711
185596
|
}));
|
|
183712
185597
|
}
|
|
185598
|
+
function searchCompartmentChunks(args) {
|
|
185599
|
+
if (!args.queryEmbedding || args.limit <= 0)
|
|
185600
|
+
return [];
|
|
185601
|
+
const cutoff = args.maxOrdinal != null && args.maxOrdinal >= 0 ? args.maxOrdinal : null;
|
|
185602
|
+
const rows = loadCompartmentChunkEmbeddingsForSearch(args.db, args.sessionId, args.projectPath, args.modelId);
|
|
185603
|
+
if (rows.length === 0)
|
|
185604
|
+
return [];
|
|
185605
|
+
const byCompartment = new Map;
|
|
185606
|
+
for (const row of rows) {
|
|
185607
|
+
if (cutoff !== null && row.endOrdinal > cutoff) {
|
|
185608
|
+
continue;
|
|
185609
|
+
}
|
|
185610
|
+
const score = normalizeCosineScore(cosineSimilarity(args.queryEmbedding, row.vector));
|
|
185611
|
+
if (score <= 0)
|
|
185612
|
+
continue;
|
|
185613
|
+
const existing = byCompartment.get(row.compartmentId);
|
|
185614
|
+
if (!existing || score > existing.score) {
|
|
185615
|
+
byCompartment.set(row.compartmentId, { row, score });
|
|
185616
|
+
}
|
|
185617
|
+
}
|
|
185618
|
+
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 }) => ({
|
|
185619
|
+
source: "compartment",
|
|
185620
|
+
content: previewText(row.title),
|
|
185621
|
+
score: score * SINGLE_SOURCE_PENALTY,
|
|
185622
|
+
compartmentId: row.compartmentId,
|
|
185623
|
+
sessionId: row.sessionId,
|
|
185624
|
+
title: row.title,
|
|
185625
|
+
startOrdinal: row.startOrdinal,
|
|
185626
|
+
endOrdinal: row.endOrdinal,
|
|
185627
|
+
matchType: "semantic"
|
|
185628
|
+
}));
|
|
185629
|
+
}
|
|
185630
|
+
function mergeMessageAndCompartmentResults(args) {
|
|
185631
|
+
if (args.compartments.length === 0)
|
|
185632
|
+
return args.messages;
|
|
185633
|
+
if (args.messages.length === 0)
|
|
185634
|
+
return args.compartments;
|
|
185635
|
+
const fused = new Map;
|
|
185636
|
+
const add = (key, result, score, tieOrdinal) => {
|
|
185637
|
+
const existing = fused.get(key);
|
|
185638
|
+
if (existing) {
|
|
185639
|
+
existing.score += score;
|
|
185640
|
+
return existing;
|
|
185641
|
+
}
|
|
185642
|
+
const entry = { result, score, tieOrdinal, snippetScore: -1 };
|
|
185643
|
+
fused.set(key, entry);
|
|
185644
|
+
return entry;
|
|
185645
|
+
};
|
|
185646
|
+
args.compartments.forEach((compartment, rank) => {
|
|
185647
|
+
add(`compartment:${compartment.compartmentId}`, compartment, 1 / (RRF_K + rank), compartment.startOrdinal);
|
|
185648
|
+
});
|
|
185649
|
+
for (const [rank, message] of args.messages.entries()) {
|
|
185650
|
+
const containing = args.compartments.find((compartment) => message.messageOrdinal >= compartment.startOrdinal && message.messageOrdinal <= compartment.endOrdinal);
|
|
185651
|
+
const contribution = 1 / (RRF_K + rank);
|
|
185652
|
+
if (!containing) {
|
|
185653
|
+
add(`message:${message.messageId}`, message, contribution, message.messageOrdinal);
|
|
185654
|
+
continue;
|
|
185655
|
+
}
|
|
185656
|
+
const entry = add(`compartment:${containing.compartmentId}`, containing, contribution, containing.startOrdinal);
|
|
185657
|
+
if (message.score > entry.snippetScore && entry.result.source === "compartment") {
|
|
185658
|
+
entry.snippetScore = message.score;
|
|
185659
|
+
entry.result = {
|
|
185660
|
+
...entry.result,
|
|
185661
|
+
matchType: "hybrid",
|
|
185662
|
+
snippet: message.content
|
|
185663
|
+
};
|
|
185664
|
+
}
|
|
185665
|
+
}
|
|
185666
|
+
const ranked = [...fused.values()].sort((left, right) => right.score !== left.score ? right.score - left.score : left.tieOrdinal - right.tieOrdinal).slice(0, args.limit);
|
|
185667
|
+
return ranked.map((entry, rank) => ({
|
|
185668
|
+
...entry.result,
|
|
185669
|
+
score: linearDecayScore(rank, ranked.length)
|
|
185670
|
+
}));
|
|
185671
|
+
}
|
|
183713
185672
|
function getSourceBoost(result) {
|
|
183714
185673
|
switch (result.source) {
|
|
183715
185674
|
case "memory":
|
|
183716
185675
|
return MEMORY_SOURCE_BOOST;
|
|
183717
185676
|
case "message":
|
|
185677
|
+
case "compartment":
|
|
183718
185678
|
return MESSAGE_SOURCE_BOOST;
|
|
183719
185679
|
case "git_commit":
|
|
183720
185680
|
return GIT_COMMIT_SOURCE_BOOST;
|
|
@@ -183732,6 +185692,9 @@ function compareUnifiedResults(left, right) {
|
|
|
183732
185692
|
if (left.source === "message" && right.source === "message") {
|
|
183733
185693
|
return left.messageOrdinal - right.messageOrdinal;
|
|
183734
185694
|
}
|
|
185695
|
+
if (left.source === "compartment" && right.source === "compartment") {
|
|
185696
|
+
return left.startOrdinal - right.startOrdinal;
|
|
185697
|
+
}
|
|
183735
185698
|
if (left.source === "git_commit" && right.source === "git_commit") {
|
|
183736
185699
|
return right.committedAtMs - left.committedAtMs;
|
|
183737
185700
|
}
|
|
@@ -183782,10 +185745,12 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183782
185745
|
const isEmbeddingRuntimeEnabled = options.isEmbeddingRuntimeEnabled ?? isEmbeddingEnabled;
|
|
183783
185746
|
const gitCommitsEnabled = options.gitCommitsEnabled ?? false;
|
|
183784
185747
|
const activeSources = resolveSources(options.sources);
|
|
183785
|
-
const
|
|
185748
|
+
const memoryFeatureEnabled = options.memoryEnabled ?? true;
|
|
185749
|
+
const runMemory = activeSources.has("memory") && memoryFeatureEnabled;
|
|
183786
185750
|
const runMessages = activeSources.has("message");
|
|
183787
185751
|
const runGitCommits = activeSources.has("git_commit") && gitCommitsEnabled;
|
|
183788
|
-
const
|
|
185752
|
+
const runCompartmentChunks = runMessages && memoryFeatureEnabled && embeddingEnabled;
|
|
185753
|
+
const needsEmbedding = (runMemory || runGitCommits || runCompartmentChunks) && embeddingEnabled && isEmbeddingRuntimeEnabled();
|
|
183789
185754
|
const queryEmbeddingPromise = needsEmbedding ? embedQuery(trimmedQuery, options.signal).catch((error51) => {
|
|
183790
185755
|
log(`[search] query embedding failed: ${error51 instanceof Error ? error51.message : String(error51)}`);
|
|
183791
185756
|
return null;
|
|
@@ -183801,6 +185766,24 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183801
185766
|
probes: messageProbes
|
|
183802
185767
|
}) : [];
|
|
183803
185768
|
const queryEmbedding = await queryEmbeddingPromise;
|
|
185769
|
+
const workspace = resolveSearchWorkspaceContext(db, projectPath);
|
|
185770
|
+
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
185771
|
+
const embeddingModelId = embeddingSnapshot?.modelId;
|
|
185772
|
+
const chunkModelId = embeddingSnapshot?.chunkModelId;
|
|
185773
|
+
const compartmentResults = runCompartmentChunks ? searchCompartmentChunks({
|
|
185774
|
+
db,
|
|
185775
|
+
sessionId,
|
|
185776
|
+
projectPath,
|
|
185777
|
+
queryEmbedding,
|
|
185778
|
+
limit: tierLimit,
|
|
185779
|
+
maxOrdinal: options.maxMessageOrdinal,
|
|
185780
|
+
modelId: chunkModelId && chunkModelId !== "off" ? chunkModelId : null
|
|
185781
|
+
}) : [];
|
|
185782
|
+
const messageLikeResults = mergeMessageAndCompartmentResults({
|
|
185783
|
+
messages: messageResults,
|
|
185784
|
+
compartments: compartmentResults,
|
|
185785
|
+
limit: tierLimit
|
|
185786
|
+
});
|
|
183804
185787
|
const [memoryResults, gitCommitResults] = await Promise.all([
|
|
183805
185788
|
runMemory ? searchMemories({
|
|
183806
185789
|
db,
|
|
@@ -183809,6 +185792,8 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183809
185792
|
limit: tierLimit,
|
|
183810
185793
|
memoryEnabled: true,
|
|
183811
185794
|
queryEmbedding,
|
|
185795
|
+
queryModelId: embeddingModelId && embeddingModelId !== "off" ? embeddingModelId : null,
|
|
185796
|
+
workspace,
|
|
183812
185797
|
visibleMemoryIds: options.visibleMemoryIds
|
|
183813
185798
|
}) : Promise.resolve([]),
|
|
183814
185799
|
runGitCommits ? Promise.resolve(searchGitCommits({
|
|
@@ -183819,7 +185804,7 @@ async function unifiedSearch(db, sessionId, projectPath, query, options = {}) {
|
|
|
183819
185804
|
queryEmbedding
|
|
183820
185805
|
})) : Promise.resolve([])
|
|
183821
185806
|
]);
|
|
183822
|
-
const results = [...memoryResults, ...
|
|
185807
|
+
const results = [...memoryResults, ...messageLikeResults, ...gitCommitResults].sort(compareUnifiedResults).slice(0, limit);
|
|
183823
185808
|
const countRetrievals = options.countRetrievals ?? true;
|
|
183824
185809
|
if (countRetrievals) {
|
|
183825
185810
|
const memoryIds = results.filter((result) => result.source === "memory").map((result) => result.memoryId);
|
|
@@ -183883,6 +185868,11 @@ function renderFragment(result, charCap) {
|
|
|
183883
185868
|
const compressed = cavemanCompress(result.content, "ultra");
|
|
183884
185869
|
return truncate(compressed, charCap);
|
|
183885
185870
|
}
|
|
185871
|
+
case "compartment": {
|
|
185872
|
+
const source = result.snippet ?? result.title;
|
|
185873
|
+
const compressed = cavemanCompress(source, "ultra");
|
|
185874
|
+
return truncate(compressed, charCap);
|
|
185875
|
+
}
|
|
183886
185876
|
}
|
|
183887
185877
|
}
|
|
183888
185878
|
function buildAutoSearchHint(results, options = {}) {
|
|
@@ -184237,51 +186227,6 @@ function planEmergencyDrop(input) {
|
|
|
184237
186227
|
};
|
|
184238
186228
|
}
|
|
184239
186229
|
|
|
184240
|
-
// src/hooks/magic-context/system-injection-stripper.ts
|
|
184241
|
-
var SYSTEM_INJECTION_MARKERS = [
|
|
184242
|
-
"<!-- OMO_INTERNAL_INITIATOR -->",
|
|
184243
|
-
"[SYSTEM DIRECTIVE: MAGIC-CONTEXT",
|
|
184244
|
-
"[SYSTEM DIRECTIVE: OH-MY-OPENCODE",
|
|
184245
|
-
"[Category+Skill Reminder]",
|
|
184246
|
-
"[EDIT ERROR - IMMEDIATE ACTION REQUIRED]",
|
|
184247
|
-
"[task CALL FAILED - IMMEDIATE RETRY REQUIRED]",
|
|
184248
|
-
"[EMERGENCY CONTEXT WINDOW WARNING]",
|
|
184249
|
-
"Unstable background agent appears idle",
|
|
184250
|
-
"**THE SUBAGENT JUST CLAIMED THIS TASK IS DONE."
|
|
184251
|
-
];
|
|
184252
|
-
var SYSTEM_REMINDER_REGEX = /<system-reminder>[\s\S]*?<\/system-reminder>/gi;
|
|
184253
|
-
var OMO_MARKER_REGEX = /<!-- OMO_INTERNAL_INITIATOR -->/g;
|
|
184254
|
-
function stripSystemInjection(text) {
|
|
184255
|
-
let hasInjection = false;
|
|
184256
|
-
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
184257
|
-
if (text.includes(marker)) {
|
|
184258
|
-
hasInjection = true;
|
|
184259
|
-
break;
|
|
184260
|
-
}
|
|
184261
|
-
}
|
|
184262
|
-
if (SYSTEM_REMINDER_REGEX.test(text))
|
|
184263
|
-
hasInjection = true;
|
|
184264
|
-
SYSTEM_REMINDER_REGEX.lastIndex = 0;
|
|
184265
|
-
if (!hasInjection)
|
|
184266
|
-
return null;
|
|
184267
|
-
let cleaned = text;
|
|
184268
|
-
cleaned = cleaned.replace(SYSTEM_REMINDER_REGEX, "");
|
|
184269
|
-
cleaned = cleaned.replace(OMO_MARKER_REGEX, "");
|
|
184270
|
-
cleaned = cleaned.replace(/\[SYSTEM DIRECTIVE: OH-MY-(?:OPENCODE|CLAUDE)[^\]]*\][\s\S]*?(?=\n\n(?!\s*[-*])|$)/g, "");
|
|
184271
|
-
for (const marker of SYSTEM_INJECTION_MARKERS) {
|
|
184272
|
-
if (marker.startsWith("<!-- ") || marker.startsWith("[SYSTEM DIRECTIVE"))
|
|
184273
|
-
continue;
|
|
184274
|
-
const idx = cleaned.indexOf(marker);
|
|
184275
|
-
if (idx === -1)
|
|
184276
|
-
continue;
|
|
184277
|
-
const blockEnd = cleaned.indexOf(`
|
|
184278
|
-
|
|
184279
|
-
`, idx + marker.length);
|
|
184280
|
-
cleaned = blockEnd !== -1 ? cleaned.slice(0, idx) + cleaned.slice(blockEnd) : cleaned.slice(0, idx);
|
|
184281
|
-
}
|
|
184282
|
-
return cleaned.trim();
|
|
184283
|
-
}
|
|
184284
|
-
|
|
184285
186230
|
// src/hooks/magic-context/heuristic-cleanup.ts
|
|
184286
186231
|
init_tag_part_guards();
|
|
184287
186232
|
var DEDUP_SAFE_TOOLS = new Set([
|
|
@@ -184523,7 +186468,7 @@ function isVisibleNoteReadPart(part) {
|
|
|
184523
186468
|
}
|
|
184524
186469
|
|
|
184525
186470
|
// src/hooks/magic-context/todo-view.ts
|
|
184526
|
-
import { createHash as
|
|
186471
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
184527
186472
|
var TERMINAL_STATUSES = new Set(["completed", "cancelled"]);
|
|
184528
186473
|
var TITLE_DONE_STATUSES = new Set(["completed"]);
|
|
184529
186474
|
var SYNTHETIC_CALL_ID_PREFIX = "mc_synthetic_todo_";
|
|
@@ -184568,7 +186513,7 @@ function buildSyntheticTodoPart(stateJson) {
|
|
|
184568
186513
|
};
|
|
184569
186514
|
}
|
|
184570
186515
|
function computeSyntheticCallId(stateJson) {
|
|
184571
|
-
const hash2 =
|
|
186516
|
+
const hash2 = createHash11("sha256").update(stateJson).digest("hex").slice(0, 16);
|
|
184572
186517
|
return `${SYNTHETIC_CALL_ID_PREFIX}${hash2}`;
|
|
184573
186518
|
}
|
|
184574
186519
|
function parseTodoState(stateJson) {
|
|
@@ -184619,15 +186564,25 @@ async function runPostTransformPhase(args) {
|
|
|
184619
186564
|
const emergencyBypassCompartmentGate = forceMaterialization;
|
|
184620
186565
|
const deferredMaterialize = args.canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
184621
186566
|
const materializationRequested = isExplicitFlush || deferredMaterialize;
|
|
184622
|
-
const
|
|
186567
|
+
const m0M1EnabledForFold = args.fullFeatureMode && args.m0M1 !== undefined && (!!args.m0M1.projectPath || !!args.m0M1.projectDirectory);
|
|
186568
|
+
const m0HardFoldThisPass = m0M1EnabledForFold && args.m0M1 ? mustMaterialize({
|
|
186569
|
+
db: args.db,
|
|
186570
|
+
sessionId: args.sessionId,
|
|
186571
|
+
state: args.sessionMeta,
|
|
186572
|
+
projectPath: args.m0M1.projectPath,
|
|
186573
|
+
projectDirectory: args.m0M1.projectDirectory,
|
|
186574
|
+
hardSignals: args.m0M1.hardSignals
|
|
186575
|
+
}).value : false;
|
|
186576
|
+
const shouldReadPendingOps = materializationRequested || args.schedulerDecision === "execute" || forceMaterialization || m0HardFoldThisPass || compartmentRunning;
|
|
184623
186577
|
const pendingOps = shouldReadPendingOps ? getPendingOps(args.db, args.sessionId) : [];
|
|
184624
186578
|
const hasPendingUserOps = pendingOps.length > 0;
|
|
184625
|
-
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization) && (!compartmentRunning || emergencyBypassCompartmentGate);
|
|
184626
|
-
const shouldRunHeuristics = (!compartmentRunning || emergencyBypassCompartmentGate) && (materializationRequested || forceMaterialization || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
|
|
186579
|
+
const shouldApplyPendingOps = (args.schedulerDecision === "execute" || materializationRequested || forceMaterialization || m0HardFoldThisPass) && (!compartmentRunning || emergencyBypassCompartmentGate);
|
|
186580
|
+
const shouldRunHeuristics = (!compartmentRunning || emergencyBypassCompartmentGate) && (materializationRequested || forceMaterialization || m0HardFoldThisPass || emergencyDropEligible || args.schedulerDecision === "execute" && (!alreadyRanThisTurn || !args.fullFeatureMode));
|
|
184627
186581
|
const isCacheBustingPass = shouldApplyPendingOps || shouldRunHeuristics;
|
|
186582
|
+
const canUseEmptySentinels = modelAcceptsEmptyContent(args.resolvedProviderID);
|
|
184628
186583
|
if (shouldRunHeuristics) {
|
|
184629
186584
|
const subagentRerun = !args.fullFeatureMode && alreadyRanThisTurn && args.schedulerDecision === "execute" && !isExplicitFlush && !forceMaterialization;
|
|
184630
|
-
const reason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : subagentRerun ? `scheduler_execute_subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
186585
|
+
const reason = isExplicitFlush ? "explicit_flush" : deferredMaterialize ? "deferred_materialization" : forceMaterialization ? `force_materialization (${args.contextUsage.percentage.toFixed(1)}% >= ${args.forceMaterializationPercentage}%)` : m0HardFoldThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into known m[0] bust, scheduler=${args.schedulerDecision})` : subagentRerun ? `scheduler_execute_subagent_rerun (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})` : `scheduler_execute (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
184631
186586
|
sessionLog(args.sessionId, `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=${args.currentTurnId}`);
|
|
184632
186587
|
}
|
|
184633
186588
|
if (alreadyRanThisTurn && args.schedulerDecision === "execute" && !materializationRequested && args.fullFeatureMode) {
|
|
@@ -184670,7 +186625,9 @@ async function runPostTransformPhase(args) {
|
|
|
184670
186625
|
logTransformTiming(args.sessionId, "applyHeuristicCleanup", t5, `droppedTools=${cleanup.droppedTools} deduplicatedTools=${cleanup.deduplicatedTools} droppedInjections=${cleanup.droppedInjections} compressedTextTags=${cleanup.compressedTextTags}`);
|
|
184671
186626
|
const t7 = performance.now();
|
|
184672
186627
|
const clearedReasoning = clearOldReasoning(args.messages, args.reasoningByMessage, args.messageTagNumbers, args.clearReasoningAge);
|
|
184673
|
-
|
|
186628
|
+
if (canUseEmptySentinels) {
|
|
186629
|
+
stripClearedReasoning(args.messages);
|
|
186630
|
+
}
|
|
184674
186631
|
const strippedInline = stripInlineThinking(args.messages, args.messageTagNumbers, args.clearReasoningAge);
|
|
184675
186632
|
if (clearedReasoning > 0 || strippedInline > 0) {
|
|
184676
186633
|
let maxTag = 0;
|
|
@@ -184716,7 +186673,6 @@ async function runPostTransformPhase(args) {
|
|
|
184716
186673
|
if (args.watermark > 0) {
|
|
184717
186674
|
const tWatermarkCleanup = performance.now();
|
|
184718
186675
|
truncateErroredTools(args.messages, args.watermark, args.messageTagNumbers);
|
|
184719
|
-
stripProcessedImages(args.messages, args.watermark, args.messageTagNumbers);
|
|
184720
186676
|
logTransformTiming(args.sessionId, "watermarkCleanup", tWatermarkCleanup);
|
|
184721
186677
|
}
|
|
184722
186678
|
if (shouldApplyPendingOps) {
|
|
@@ -184726,21 +186682,40 @@ async function runPostTransformPhase(args) {
|
|
|
184726
186682
|
sessionLog(args.sessionId, "transform failed applying pending operations:", error51);
|
|
184727
186683
|
updateSessionMeta(args.db, args.sessionId, { lastTransformError: getErrorMessage(error51) });
|
|
184728
186684
|
}
|
|
184729
|
-
|
|
184730
|
-
|
|
184731
|
-
|
|
184732
|
-
|
|
184733
|
-
|
|
184734
|
-
|
|
184735
|
-
|
|
184736
|
-
|
|
184737
|
-
|
|
186685
|
+
if (canUseEmptySentinels) {
|
|
186686
|
+
try {
|
|
186687
|
+
const t8 = performance.now();
|
|
186688
|
+
const frozenStaleReduceIds = getStaleReduceStrippedIds(args.db, args.sessionId);
|
|
186689
|
+
const staleReduceResult = dropStaleReduceCalls(args.messages, frozenStaleReduceIds, {
|
|
186690
|
+
detect: isCacheBustingPass,
|
|
186691
|
+
protectedCount: args.protectedTags
|
|
186692
|
+
});
|
|
186693
|
+
if (isCacheBustingPass && staleReduceResult.newlyStrippedIds.length > 0) {
|
|
186694
|
+
addStaleReduceStrippedIds(args.db, args.sessionId, staleReduceResult.newlyStrippedIds);
|
|
186695
|
+
}
|
|
186696
|
+
logTransformTiming(args.sessionId, "dropStaleReduceCalls", t8);
|
|
186697
|
+
} catch (error51) {
|
|
186698
|
+
sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error51);
|
|
184738
186699
|
}
|
|
184739
|
-
logTransformTiming(args.sessionId, "dropStaleReduceCalls", t8);
|
|
184740
|
-
} catch (error51) {
|
|
184741
|
-
sessionLog(args.sessionId, "transform failed dropping stale ctx_reduce calls:", error51);
|
|
184742
186700
|
}
|
|
184743
|
-
|
|
186701
|
+
if (canUseEmptySentinels && args.watermark > 0) {
|
|
186702
|
+
try {
|
|
186703
|
+
const tImg = performance.now();
|
|
186704
|
+
const frozenImageIds = getProcessedImageStrippedIds(args.db, args.sessionId);
|
|
186705
|
+
const imageResult = stripProcessedImages(args.messages, frozenImageIds, {
|
|
186706
|
+
detect: isCacheBustingPass,
|
|
186707
|
+
watermark: args.watermark,
|
|
186708
|
+
messageTagNumbers: args.messageTagNumbers
|
|
186709
|
+
});
|
|
186710
|
+
if (isCacheBustingPass && imageResult.newlyStrippedIds.length > 0) {
|
|
186711
|
+
addProcessedImageStrippedIds(args.db, args.sessionId, imageResult.newlyStrippedIds);
|
|
186712
|
+
}
|
|
186713
|
+
logTransformTiming(args.sessionId, "stripProcessedImages", tImg);
|
|
186714
|
+
} catch (error51) {
|
|
186715
|
+
sessionLog(args.sessionId, "transform failed stripping processed images:", error51);
|
|
186716
|
+
}
|
|
186717
|
+
}
|
|
186718
|
+
const m0M1Enabled = m0M1EnabledForFold;
|
|
184744
186719
|
if (m0M1Enabled && args.m0M1) {
|
|
184745
186720
|
const tInjectM0M1 = performance.now();
|
|
184746
186721
|
try {
|
|
@@ -184787,7 +186762,7 @@ async function runPostTransformPhase(args) {
|
|
|
184787
186762
|
const tPlaceholder = performance.now();
|
|
184788
186763
|
const persistedIds = getStrippedPlaceholderIds(args.db, args.sessionId);
|
|
184789
186764
|
if (persistedIds.size > 0) {
|
|
184790
|
-
const { replayed, missingIds } = replaySentinelByMessageIds(args.messages, persistedIds, args.
|
|
186765
|
+
const { replayed, missingIds } = replaySentinelByMessageIds(args.messages, persistedIds, args.resolvedProviderID);
|
|
184791
186766
|
if (replayed > 0) {
|
|
184792
186767
|
sessionLog(args.sessionId, `sentinel replay: neutralized ${replayed} previously-stripped messages`);
|
|
184793
186768
|
}
|
|
@@ -184798,9 +186773,9 @@ async function runPostTransformPhase(args) {
|
|
|
184798
186773
|
}
|
|
184799
186774
|
}
|
|
184800
186775
|
if (isCacheBustingPass) {
|
|
184801
|
-
const droppedResult = stripDroppedPlaceholderMessages(args.messages, args.
|
|
186776
|
+
const droppedResult = stripDroppedPlaceholderMessages(args.messages, args.resolvedProviderID);
|
|
184802
186777
|
const protectedTailStart = Math.max(0, args.messages.length - args.protectedTags * 2);
|
|
184803
|
-
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart, args.
|
|
186778
|
+
const systemInjectedResult = stripSystemInjectedMessages(args.messages, protectedTailStart, args.resolvedProviderID);
|
|
184804
186779
|
const newlyNeutralized = droppedResult.sentineledIds.length + systemInjectedResult.sentineledIds.length;
|
|
184805
186780
|
if (newlyNeutralized > 0) {
|
|
184806
186781
|
const addedIds = [
|
|
@@ -185000,6 +186975,7 @@ function clearMessageTokensCache(sessionId, messageId) {
|
|
|
185000
186975
|
if (cache)
|
|
185001
186976
|
cache.delete(messageId);
|
|
185002
186977
|
}
|
|
186978
|
+
var recordedSessionProjectIdentity = new BoundedSessionMap(MESSAGE_TOKENS_CACHE_MAX);
|
|
185003
186979
|
function findLastAssistantModel2(messages) {
|
|
185004
186980
|
for (let i = messages.length - 1;i >= 0; i--) {
|
|
185005
186981
|
const info = messages[i].info;
|
|
@@ -185047,9 +187023,11 @@ function createTransform(deps) {
|
|
|
185047
187023
|
const fullFeatureMode = !reducedMode;
|
|
185048
187024
|
const ctxReduceEnabledEffective = deps.ctxReduceEnabled !== false && resolveCtxReduceAvailabilityFromMessages(sessionId, messages);
|
|
185049
187025
|
let sessionDirectory = deps.directory ?? "";
|
|
187026
|
+
let sessionDirectoryResolvedFromHost = false;
|
|
185050
187027
|
const cachedDirectory = deps.sessionDirectoryBySession?.get(sessionId);
|
|
185051
187028
|
if (cachedDirectory && cachedDirectory.length > 0) {
|
|
185052
187029
|
sessionDirectory = cachedDirectory;
|
|
187030
|
+
sessionDirectoryResolvedFromHost = true;
|
|
185053
187031
|
} else if (deps.client !== undefined) {
|
|
185054
187032
|
try {
|
|
185055
187033
|
const sessionResponse = await deps.client.session.get({ path: { id: sessionId } }).catch(() => null);
|
|
@@ -185057,6 +187035,7 @@ function createTransform(deps) {
|
|
|
185057
187035
|
if (sessionInfo && typeof sessionInfo.directory === "string" && sessionInfo.directory.length > 0) {
|
|
185058
187036
|
sessionDirectory = sessionInfo.directory;
|
|
185059
187037
|
deps.sessionDirectoryBySession?.set(sessionId, sessionDirectory);
|
|
187038
|
+
sessionDirectoryResolvedFromHost = true;
|
|
185060
187039
|
}
|
|
185061
187040
|
} catch {}
|
|
185062
187041
|
}
|
|
@@ -185151,6 +187130,8 @@ function createTransform(deps) {
|
|
|
185151
187130
|
deps.liveModelBySession?.set(sessionId, recovered);
|
|
185152
187131
|
}
|
|
185153
187132
|
}
|
|
187133
|
+
const resolvedProviderID = modelForBudget?.providerID;
|
|
187134
|
+
const canUseEmptySentinels = modelAcceptsEmptyContent(resolvedProviderID);
|
|
185154
187135
|
const resolvedContextLimit = modelForBudget ? resolveTrustedContextLimit(modelForBudget.providerID, modelForBudget.modelID, {
|
|
185155
187136
|
db,
|
|
185156
187137
|
sessionID: sessionId
|
|
@@ -185315,6 +187296,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185315
187296
|
logTransformTiming(sessionId, "emergencyRecoveryBlock", tFirstPass);
|
|
185316
187297
|
const projectIdentity = deps.memoryConfig?.enabled ? resolveProjectIdentity(compartmentDirectory || process.cwd()) : undefined;
|
|
185317
187298
|
const sessionProjectIdentity = projectIdentity ?? (sessionDirectory ? resolveProjectIdentity(sessionDirectory) : deps.projectPath);
|
|
187299
|
+
if (sessionProjectIdentity && sessionDirectoryResolvedFromHost && recordedSessionProjectIdentity.get(sessionId) !== sessionProjectIdentity) {
|
|
187300
|
+
recordSessionProjectIdentity(db, sessionId, sessionProjectIdentity);
|
|
187301
|
+
recordedSessionProjectIdentity.set(sessionId, sessionProjectIdentity);
|
|
187302
|
+
}
|
|
185318
187303
|
let triggerBoundarySnapshot;
|
|
185319
187304
|
if (fullFeatureMode && historianRunnable && !sessionMeta.compartmentInProgress) {
|
|
185320
187305
|
const tTrigger = performance.now();
|
|
@@ -185409,7 +187394,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185409
187394
|
}
|
|
185410
187395
|
}
|
|
185411
187396
|
const t3 = performance.now();
|
|
185412
|
-
const strippedStructuralNoise = stripStructuralNoise(messages);
|
|
187397
|
+
const strippedStructuralNoise = canUseEmptySentinels ? stripStructuralNoise(messages) : 0;
|
|
185413
187398
|
logTransformTiming(sessionId, "stripStructuralNoise", t3, `strippedParts=${strippedStructuralNoise}`);
|
|
185414
187399
|
const persistedReasoningWatermark = sessionMeta?.clearedReasoningThroughTag ?? 0;
|
|
185415
187400
|
if (persistedReasoningWatermark > 0) {
|
|
@@ -185430,18 +187415,10 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185430
187415
|
logTransformTiming(sessionId, "replayCavemanCompression", tCavemanReplay);
|
|
185431
187416
|
}
|
|
185432
187417
|
const t4 = performance.now();
|
|
185433
|
-
const strippedClearedReasoning = stripClearedReasoning(messages);
|
|
187418
|
+
const strippedClearedReasoning = canUseEmptySentinels ? stripClearedReasoning(messages) : 0;
|
|
185434
187419
|
logTransformTiming(sessionId, "stripClearedReasoning", t4, `strippedParts=${strippedClearedReasoning}`);
|
|
185435
187420
|
const tMergeStrip = performance.now();
|
|
185436
|
-
|
|
185437
|
-
if (liveProviderID === undefined) {
|
|
185438
|
-
const recovered = findLastAssistantModelFromOpenCodeDb(sessionId);
|
|
185439
|
-
if (recovered) {
|
|
185440
|
-
liveProviderID = recovered.providerID;
|
|
185441
|
-
deps.liveModelBySession?.set(sessionId, recovered);
|
|
185442
|
-
}
|
|
185443
|
-
}
|
|
185444
|
-
const strippedMergedReasoning = stripReasoningFromMergedAssistants(messages, liveProviderID);
|
|
187421
|
+
const strippedMergedReasoning = stripReasoningFromMergedAssistants(messages, resolvedProviderID);
|
|
185445
187422
|
if (strippedMergedReasoning > 0) {
|
|
185446
187423
|
sessionLog(sessionId, `stripped ${strippedMergedReasoning} reasoning parts from merged assistants (anthropic groupIntoBlocks workaround)`);
|
|
185447
187424
|
}
|
|
@@ -185560,7 +187537,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185560
187537
|
sessionDirectory,
|
|
185561
187538
|
autoSearch: deps.autoSearch,
|
|
185562
187539
|
cavemanTextCompression: deps.ctxReduceEnabled === false && !reducedMode ? deps.cavemanTextCompression : undefined,
|
|
185563
|
-
|
|
187540
|
+
resolvedProviderID,
|
|
185564
187541
|
historyRefreshSessions: deps.historyRefreshSessions,
|
|
185565
187542
|
m0M1: {
|
|
185566
187543
|
projectPath: projectIdentity,
|
|
@@ -185713,7 +187690,7 @@ Historian previously failed ${historianFailureState.failureCount} time(s), so Ma
|
|
|
185713
187690
|
let tailToolTokens;
|
|
185714
187691
|
let liveTailTokens;
|
|
185715
187692
|
try {
|
|
185716
|
-
const agg = getActiveTagTokenAggregate(db, sessionId);
|
|
187693
|
+
const agg = getActiveTagTokenAggregate(db, sessionId, deps.protectedTags);
|
|
185717
187694
|
tailToolTokens = agg.toolOutput;
|
|
185718
187695
|
liveTailTokens = agg.conversation + agg.toolCall;
|
|
185719
187696
|
} catch {
|
|
@@ -186348,10 +188325,11 @@ function maybeInjectChannel1Nudge(args, sessionId, tool, output) {
|
|
|
186348
188325
|
contextLimit: state.contextLimit,
|
|
186349
188326
|
executeThresholdPercentage: state.executeThresholdPercentage
|
|
186350
188327
|
});
|
|
188328
|
+
const workingWindowTokens = Math.round(state.contextLimit * state.executeThresholdPercentage / 100);
|
|
186351
188329
|
const decision = decideChannel1({
|
|
186352
188330
|
undroppedTokens,
|
|
186353
188331
|
pressure,
|
|
186354
|
-
|
|
188332
|
+
workingWindowTokens,
|
|
186355
188333
|
lastNudgeUndropped: getLastNudgeUndropped(args.db, sessionId),
|
|
186356
188334
|
lastNudgeLevel: getLastNudgeLevel(args.db, sessionId),
|
|
186357
188335
|
hasRecentReduce: false
|
|
@@ -186413,7 +188391,7 @@ function createToolExecuteAfterHook(args) {
|
|
|
186413
188391
|
init_send_session_notification();
|
|
186414
188392
|
|
|
186415
188393
|
// src/hooks/magic-context/system-prompt-hash.ts
|
|
186416
|
-
import { createHash as
|
|
188394
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
186417
188395
|
|
|
186418
188396
|
// src/agents/magic-context-prompt.ts
|
|
186419
188397
|
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
@@ -186613,7 +188591,7 @@ function createSystemPromptHashHandler(deps) {
|
|
|
186613
188591
|
`);
|
|
186614
188592
|
if (systemContent.length === 0)
|
|
186615
188593
|
return;
|
|
186616
|
-
const currentHash =
|
|
188594
|
+
const currentHash = createHash12("md5").update(systemContent).digest("hex");
|
|
186617
188595
|
if (!sessionMetaEarly) {
|
|
186618
188596
|
return;
|
|
186619
188597
|
}
|
|
@@ -186874,6 +188852,46 @@ function createMagicContextHook(deps) {
|
|
|
186874
188852
|
ensureProjectRegistered: ensureProjectRegisteredFromOpenCodeDirectory,
|
|
186875
188853
|
getNotificationParams: (sid) => getLiveNotificationParams(sid, liveModelBySession, variantBySession, agentBySession)
|
|
186876
188854
|
});
|
|
188855
|
+
const executeEmbedHistory = async (sessionId) => {
|
|
188856
|
+
if (deps.config.memory?.enabled === false) {
|
|
188857
|
+
return "Memory is disabled for this project, so there is no semantic embedding to backfill.";
|
|
188858
|
+
}
|
|
188859
|
+
const directory = sessionDirectoryBySession.get(sessionId) ?? deps.directory;
|
|
188860
|
+
await ensureProjectRegisteredFromOpenCodeDirectory(directory, db);
|
|
188861
|
+
const sessionProjectIdentity = resolveProjectIdentity(directory);
|
|
188862
|
+
setRecompStarting({ recompProgressBySession }, sessionId, "Embedding history…", "embed");
|
|
188863
|
+
const outcome = await embedSessionCompartmentChunks(db, sessionProjectIdentity, sessionId, {
|
|
188864
|
+
onProgress: ({ embedded, total }) => {
|
|
188865
|
+
const cur = recompProgressBySession.get(sessionId);
|
|
188866
|
+
if (!cur || cur.phase !== "recomp")
|
|
188867
|
+
return;
|
|
188868
|
+
recompProgressBySession.set(sessionId, {
|
|
188869
|
+
...cur,
|
|
188870
|
+
processedMessages: embedded,
|
|
188871
|
+
totalMessages: total,
|
|
188872
|
+
updatedAt: Date.now()
|
|
188873
|
+
});
|
|
188874
|
+
}
|
|
188875
|
+
});
|
|
188876
|
+
const terminal = (phase, message) => {
|
|
188877
|
+
setRecompTerminal({ recompProgressBySession }, sessionId, phase, message);
|
|
188878
|
+
return message;
|
|
188879
|
+
};
|
|
188880
|
+
switch (outcome.status) {
|
|
188881
|
+
case "nothing":
|
|
188882
|
+
return terminal("done", "All of this session's history is already embedded.");
|
|
188883
|
+
case "disabled":
|
|
188884
|
+
return terminal("skipped", "No embedding provider is configured, so there is nothing to embed.");
|
|
188885
|
+
case "busy":
|
|
188886
|
+
return terminal("skipped", `Embedding is already running for this project — ${outcome.total} compartment${outcome.total === 1 ? "" : "s"} still pending. Try again shortly.`);
|
|
188887
|
+
case "aborted":
|
|
188888
|
+
return terminal("done", `Embedded ${outcome.embedded} of ${outcome.total} compartments before stopping.`);
|
|
188889
|
+
case "stalled":
|
|
188890
|
+
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.`);
|
|
188891
|
+
default:
|
|
188892
|
+
return terminal("done", `Embedded ${outcome.embedded} compartment${outcome.embedded === 1 ? "" : "s"} of history for semantic search.`);
|
|
188893
|
+
}
|
|
188894
|
+
};
|
|
186877
188895
|
const sidekickRunnable = isSidekickRunnable(deps.config);
|
|
186878
188896
|
const sidekickConfig = sidekickRunnable ? deps.config.sidekick : undefined;
|
|
186879
188897
|
const transform2 = createTransform({
|
|
@@ -187028,6 +189046,7 @@ function createMagicContextHook(deps) {
|
|
|
187028
189046
|
},
|
|
187029
189047
|
executeRecomp: historianRunnable ? async (sessionId, options) => runManagedRecomp(buildManagedRecompCtx(sessionId), sessionId, options) : undefined,
|
|
187030
189048
|
runUpgrade: historianRunnable ? async (sessionId) => runManagedUpgrade(buildManagedRecompCtx(sessionId), sessionId) : undefined,
|
|
189049
|
+
executeEmbedHistory,
|
|
187031
189050
|
sendNotification: async (sessionId, text, params) => {
|
|
187032
189051
|
await sendIgnoredMessage(deps.client, sessionId, text, {
|
|
187033
189052
|
...getLiveNotificationParams(sessionId, liveModelBySession, variantBySession, agentBySession),
|
|
@@ -188166,6 +190185,7 @@ init_memory();
|
|
|
188166
190185
|
init_embedding();
|
|
188167
190186
|
init_embedding_cache();
|
|
188168
190187
|
init_normalize_hash();
|
|
190188
|
+
init_workspaces();
|
|
188169
190189
|
init_logger();
|
|
188170
190190
|
await init_storage();
|
|
188171
190191
|
import { tool as tool2 } from "@opencode-ai/plugin";
|
|
@@ -188325,6 +190345,23 @@ function createCtxMemoryTool(deps) {
|
|
|
188325
190345
|
}
|
|
188326
190346
|
const projectPath = deps.resolveProjectPath(toolContext.directory);
|
|
188327
190347
|
await deps.ensureProjectRegistered?.(toolContext.directory, deps.db);
|
|
190348
|
+
const workspaceIdentitySet = resolveWorkspaceIdentitySet(deps.db, projectPath);
|
|
190349
|
+
const expandedWorkspace = expandWorkspaceIdentitySetWithAliases(deps.db, workspaceIdentitySet.identities);
|
|
190350
|
+
const workspaceVisibleIdentities = workspaceIdentitySet.identities.length > 1 ? expandedWorkspace.expandedIdentities : workspaceIdentitySet.identities;
|
|
190351
|
+
const targetIdentityForStoredPath = (rawProjectPath) => workspaceIdentitySet.identities.length > 1 ? resolveStoredPathWorkspaceIdentity(rawProjectPath, workspaceIdentitySet.identities, expandedWorkspace.canonicalIdentityByStoredPath) ?? projectIdentityForStoredPath(rawProjectPath) : projectIdentityForStoredPath(rawProjectPath);
|
|
190352
|
+
const toolShareCategories = workspaceIdentitySet.identities.length > 1 ? resolveWorkspaceShareCategories(deps.db, projectPath) : null;
|
|
190353
|
+
const memoryVisibleToTool = (memory) => {
|
|
190354
|
+
if (workspaceIdentitySet.identities.length <= 1) {
|
|
190355
|
+
return memoryBelongsToProject(memory, projectPath);
|
|
190356
|
+
}
|
|
190357
|
+
if (!storedPathBelongsToWorkspace(memory.projectPath, workspaceIdentitySet.identities, workspaceVisibleIdentities, expandedWorkspace.canonicalIdentityByStoredPath)) {
|
|
190358
|
+
return false;
|
|
190359
|
+
}
|
|
190360
|
+
const isOwn = targetIdentityForStoredPath(memory.projectPath) === projectPath;
|
|
190361
|
+
if (isOwn)
|
|
190362
|
+
return true;
|
|
190363
|
+
return toolShareCategories === null || toolShareCategories.includes(memory.category);
|
|
190364
|
+
};
|
|
188328
190365
|
const embeddingSnapshot = getProjectEmbeddingSnapshot(projectPath);
|
|
188329
190366
|
if (embeddingSnapshot ? !embeddingSnapshot.features.memoryEnabled : deps.memoryEnabled === false) {
|
|
188330
190367
|
return getDisabledMessage();
|
|
@@ -188381,18 +190418,18 @@ function createCtxMemoryTool(deps) {
|
|
|
188381
190418
|
}
|
|
188382
190419
|
const rawProjectPath = projectPathForMemoryId(deps.db, updateId);
|
|
188383
190420
|
const memory = getMemoryById(deps.db, updateId);
|
|
188384
|
-
if (!memory || !rawProjectPath || !
|
|
190421
|
+
if (!memory || !rawProjectPath || !memoryVisibleToTool(memory)) {
|
|
188385
190422
|
return `Error: Memory with ID ${updateId} was not found.`;
|
|
188386
190423
|
}
|
|
188387
190424
|
if (toolContext.agent !== DREAMER_AGENT && !isPrimaryMutableMemory(memory)) {
|
|
188388
190425
|
return inactiveMemoryError(updateId, "updating");
|
|
188389
190426
|
}
|
|
188390
190427
|
const normalizedHash = computeNormalizedHash(content);
|
|
188391
|
-
const duplicate = getMemoryByHash(deps.db,
|
|
190428
|
+
const duplicate = getMemoryByHash(deps.db, targetIdentityForStoredPath(rawProjectPath), memory.category, normalizedHash);
|
|
188392
190429
|
if (duplicate && duplicate.id !== memory.id) {
|
|
188393
190430
|
return `Error: Memory content already exists as ID ${duplicate.id}; merge or archive duplicates instead.`;
|
|
188394
190431
|
}
|
|
188395
|
-
const projectIdentity =
|
|
190432
|
+
const projectIdentity = targetIdentityForStoredPath(rawProjectPath);
|
|
188396
190433
|
deps.db.transaction(() => {
|
|
188397
190434
|
updateMemoryContentInCurrentTransaction(deps.db, memory, content, normalizedHash);
|
|
188398
190435
|
queueMemoryMutation(deps.db, {
|
|
@@ -188406,7 +190443,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188406
190443
|
queueMemoryEmbedding({
|
|
188407
190444
|
deps,
|
|
188408
190445
|
sessionId: toolContext.sessionID,
|
|
188409
|
-
projectPath,
|
|
190446
|
+
projectPath: projectIdentity,
|
|
188410
190447
|
memoryId: memory.id,
|
|
188411
190448
|
content
|
|
188412
190449
|
});
|
|
@@ -188429,7 +190466,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188429
190466
|
return "Error: One or more source memories were not found.";
|
|
188430
190467
|
}
|
|
188431
190468
|
if (toolContext.agent !== DREAMER_AGENT) {
|
|
188432
|
-
const foreign = sourceMemories.find((memory) => !
|
|
190469
|
+
const foreign = sourceMemories.find((memory) => !memoryVisibleToTool(memory));
|
|
188433
190470
|
if (foreign) {
|
|
188434
190471
|
return `Error: Memory with ID ${foreign.id} was not found.`;
|
|
188435
190472
|
}
|
|
@@ -188513,15 +190550,16 @@ function createCtxMemoryTool(deps) {
|
|
|
188513
190550
|
return `Merged memories [${ids.join(", ")}] into canonical memory [ID: ${canonicalMemory.id}] in ${category}; superseded [${supersededIds.join(", ")}].`;
|
|
188514
190551
|
}
|
|
188515
190552
|
if (args.action === "archive") {
|
|
188516
|
-
const
|
|
188517
|
-
if (!
|
|
190553
|
+
const rawArchiveIds = args.ids;
|
|
190554
|
+
if (!rawArchiveIds || rawArchiveIds.length === 0 || !rawArchiveIds.every(Number.isInteger)) {
|
|
188518
190555
|
return "Error: 'ids' must contain at least one integer memory ID when action is 'archive'.";
|
|
188519
190556
|
}
|
|
190557
|
+
const archiveIds = [...new Set(rawArchiveIds)];
|
|
188520
190558
|
const targets = [];
|
|
188521
190559
|
for (const memoryId of archiveIds) {
|
|
188522
190560
|
const rawProjectPath = projectPathForMemoryId(deps.db, memoryId);
|
|
188523
190561
|
const memory = getMemoryById(deps.db, memoryId);
|
|
188524
|
-
if (!memory || !rawProjectPath || !
|
|
190562
|
+
if (!memory || !rawProjectPath || !memoryVisibleToTool(memory)) {
|
|
188525
190563
|
return `Error: Memory with ID ${memoryId} was not found.`;
|
|
188526
190564
|
}
|
|
188527
190565
|
if (toolContext.agent !== DREAMER_AGENT && !isPrimaryMutableMemory(memory)) {
|
|
@@ -188529,7 +190567,7 @@ function createCtxMemoryTool(deps) {
|
|
|
188529
190567
|
}
|
|
188530
190568
|
targets.push({
|
|
188531
190569
|
memoryId,
|
|
188532
|
-
projectIdentity:
|
|
190570
|
+
projectIdentity: targetIdentityForStoredPath(rawProjectPath)
|
|
188533
190571
|
});
|
|
188534
190572
|
}
|
|
188535
190573
|
deps.db.transaction(() => {
|
|
@@ -189003,8 +191041,9 @@ function formatAge2(committedAtMs) {
|
|
|
189003
191041
|
}
|
|
189004
191042
|
function formatResult(result, index) {
|
|
189005
191043
|
if (result.source === "memory") {
|
|
191044
|
+
const source = result.sourceName ? ` source=${result.sourceName}` : "";
|
|
189006
191045
|
return [
|
|
189007
|
-
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category} match=${result.matchType}`,
|
|
191046
|
+
`[${index}] [memory] score=${result.score.toFixed(2)} id=${result.memoryId} category=${result.category}${source} match=${result.matchType}`,
|
|
189008
191047
|
result.content
|
|
189009
191048
|
].join(`
|
|
189010
191049
|
`);
|
|
@@ -189014,6 +191053,13 @@ function formatResult(result, index) {
|
|
|
189014
191053
|
`[${index}] [git_commit] score=${result.score.toFixed(2)} sha=${result.shortSha} ${formatAge2(result.committedAtMs)} match=${result.matchType}`,
|
|
189015
191054
|
result.content
|
|
189016
191055
|
].join(`
|
|
191056
|
+
`);
|
|
191057
|
+
}
|
|
191058
|
+
if (result.source === "compartment") {
|
|
191059
|
+
return [
|
|
191060
|
+
`[${index}] [message] score=${result.score.toFixed(2)} compartment_id=${result.compartmentId} range=${result.startOrdinal}-${result.endOrdinal} match=${result.matchType} title=${result.title}`,
|
|
191061
|
+
result.snippet ? `Snippet: ${result.snippet}` : result.content
|
|
191062
|
+
].join(`
|
|
189017
191063
|
`);
|
|
189018
191064
|
}
|
|
189019
191065
|
const expandStart = Math.max(1, result.messageOrdinal - 3);
|
|
@@ -189029,7 +191075,7 @@ function formatSearchResults(query, results) {
|
|
|
189029
191075
|
return `No results found for "${query}" across memories, git commits, or message history.`;
|
|
189030
191076
|
}
|
|
189031
191077
|
const bodyParts = results.map((result, index) => formatResult(result, index + 1));
|
|
189032
|
-
if (results.some((result) => result.source === "message")) {
|
|
191078
|
+
if (results.some((result) => result.source === "message" || result.source === "compartment")) {
|
|
189033
191079
|
bodyParts.push("Use ctx_expand(start, end) with the range from any message result above to read the full conversation context.");
|
|
189034
191080
|
}
|
|
189035
191081
|
const body = bodyParts.join(`
|
|
@@ -189187,11 +191233,11 @@ import { createServer } from "node:http";
|
|
|
189187
191233
|
import { dirname as dirname5 } from "node:path";
|
|
189188
191234
|
|
|
189189
191235
|
// src/shared/rpc-utils.ts
|
|
189190
|
-
import { createHash as
|
|
191236
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
189191
191237
|
import { join as join20 } from "node:path";
|
|
189192
191238
|
function projectHash(directory) {
|
|
189193
191239
|
const normalized = directory.replace(/\/+$/, "");
|
|
189194
|
-
return
|
|
191240
|
+
return createHash13("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
189195
191241
|
}
|
|
189196
191242
|
function rpcPortDir(storageDir, directory) {
|
|
189197
191243
|
return join20(storageDir, "rpc", projectHash(directory));
|