@cortexkit/pi-magic-context 0.22.4 → 0.22.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/dist/index.js +549 -172
- package/dist/subagent-entry.js +340 -73
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -8073,6 +8073,19 @@ function hasGitDir(canonical) {
|
|
|
8073
8073
|
return false;
|
|
8074
8074
|
}
|
|
8075
8075
|
}
|
|
8076
|
+
function normalizeStoredProjectPath(rawOrStored) {
|
|
8077
|
+
if (rawOrStored.startsWith("git:") || rawOrStored.startsWith("dir:")) {
|
|
8078
|
+
return rawOrStored;
|
|
8079
|
+
}
|
|
8080
|
+
try {
|
|
8081
|
+
return resolveProjectIdentity(rawOrStored);
|
|
8082
|
+
} catch {
|
|
8083
|
+
return directoryFallback(rawOrStored);
|
|
8084
|
+
}
|
|
8085
|
+
}
|
|
8086
|
+
function storedPathBelongsToIdentity(storedProjectPath, projectIdentity) {
|
|
8087
|
+
return storedProjectPath === projectIdentity || normalizeStoredProjectPath(storedProjectPath) === projectIdentity;
|
|
8088
|
+
}
|
|
8076
8089
|
|
|
8077
8090
|
// ../plugin/src/shared/logger.ts
|
|
8078
8091
|
import * as fs from "node:fs";
|
|
@@ -142072,12 +142085,6 @@ function isCompartmentRow(row) {
|
|
|
142072
142085
|
const candidate = row;
|
|
142073
142086
|
return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.sequence === "number" && typeof candidate.start_message === "number" && typeof candidate.end_message === "number" && typeof candidate.start_message_id === "string" && typeof candidate.end_message_id === "string" && typeof candidate.title === "string" && typeof candidate.content === "string" && isStringOrNullish(candidate.p1) && isStringOrNullish(candidate.p2) && isStringOrNullish(candidate.p3) && isStringOrNullish(candidate.p4) && isNumberOrNullish(candidate.importance) && isStringOrNullish(candidate.episode_type) && isNumberOrNullish(candidate.legacy) && typeof candidate.created_at === "number";
|
|
142074
142087
|
}
|
|
142075
|
-
function isSessionFactRow(row) {
|
|
142076
|
-
if (row === null || typeof row !== "object")
|
|
142077
|
-
return false;
|
|
142078
|
-
const candidate = row;
|
|
142079
|
-
return typeof candidate.id === "number" && typeof candidate.session_id === "string" && typeof candidate.category === "string" && typeof candidate.content === "string" && typeof candidate.created_at === "number" && typeof candidate.updated_at === "number";
|
|
142080
|
-
}
|
|
142081
142088
|
function insertCompartmentRows(db, sessionId, compartments, now) {
|
|
142082
142089
|
const stmt = getInsertCompartmentStatement(db);
|
|
142083
142090
|
for (const compartment of compartments) {
|
|
@@ -142106,16 +142113,6 @@ function toCompartment(row) {
|
|
|
142106
142113
|
createdAt: row.created_at
|
|
142107
142114
|
};
|
|
142108
142115
|
}
|
|
142109
|
-
function toSessionFact(row) {
|
|
142110
|
-
return {
|
|
142111
|
-
id: row.id,
|
|
142112
|
-
sessionId: row.session_id,
|
|
142113
|
-
category: row.category,
|
|
142114
|
-
content: row.content,
|
|
142115
|
-
createdAt: row.created_at,
|
|
142116
|
-
updatedAt: row.updated_at
|
|
142117
|
-
};
|
|
142118
|
-
}
|
|
142119
142116
|
function getCompartments(db, sessionId) {
|
|
142120
142117
|
const rows = db.prepare("SELECT * FROM compartments WHERE session_id = ? ORDER BY sequence ASC").all(sessionId).filter(isCompartmentRow);
|
|
142121
142118
|
return rows.map(toCompartment);
|
|
@@ -142136,10 +142133,6 @@ function appendCompartments(db, sessionId, compartments) {
|
|
|
142136
142133
|
insertCompartmentRows(db, sessionId, compartments, now);
|
|
142137
142134
|
})();
|
|
142138
142135
|
}
|
|
142139
|
-
function getSessionFacts(db, sessionId) {
|
|
142140
|
-
const rows = db.prepare("SELECT * FROM session_facts WHERE session_id = ? ORDER BY category ASC, id ASC").all(sessionId).filter(isSessionFactRow);
|
|
142141
|
-
return rows.map(toSessionFact);
|
|
142142
|
-
}
|
|
142143
142136
|
function saveRecompStagingPass(db, sessionId, passNumber, compartments, facts) {
|
|
142144
142137
|
const now = Date.now();
|
|
142145
142138
|
db.transaction(() => {
|
|
@@ -142183,14 +142176,6 @@ function getRecompStaging(db, sessionId) {
|
|
|
142183
142176
|
lastEndMessage: lastEnd
|
|
142184
142177
|
};
|
|
142185
142178
|
}
|
|
142186
|
-
function invalidateAllMemoryBlockCaches(db) {
|
|
142187
|
-
try {
|
|
142188
|
-
const rows = db.prepare("SELECT session_id FROM session_meta").all();
|
|
142189
|
-
for (const row of rows) {
|
|
142190
|
-
clearCachedM0M1(db, row.session_id);
|
|
142191
|
-
}
|
|
142192
|
-
} catch {}
|
|
142193
|
-
}
|
|
142194
142179
|
function clearRecompStaging(db, sessionId) {
|
|
142195
142180
|
db.transaction(() => {
|
|
142196
142181
|
db.prepare("DELETE FROM recomp_compartments WHERE session_id = ?").run(sessionId);
|
|
@@ -143331,6 +143316,7 @@ CREATE INDEX IF NOT EXISTS idx_dream_queue_pending ON dream_queue(started_at, en
|
|
|
143331
143316
|
ensureColumn(db, "session_meta", "system_prompt_hash", "TEXT DEFAULT ''");
|
|
143332
143317
|
ensureColumn(db, "session_meta", "cleared_reasoning_through_tag", "INTEGER DEFAULT 0");
|
|
143333
143318
|
ensureColumn(db, "session_meta", "stripped_placeholder_ids", "TEXT DEFAULT ''");
|
|
143319
|
+
ensureColumn(db, "session_meta", "stale_reduce_stripped_ids", "TEXT DEFAULT ''");
|
|
143334
143320
|
ensureColumn(db, "compartments", "start_message_id", "TEXT DEFAULT ''");
|
|
143335
143321
|
ensureColumn(db, "compartments", "end_message_id", "TEXT DEFAULT ''");
|
|
143336
143322
|
ensureColumn(db, "memory_embeddings", "model_id", "TEXT");
|
|
@@ -143481,6 +143467,7 @@ function healNullTextColumns(db) {
|
|
|
143481
143467
|
["todo_synthetic_state_json", ""],
|
|
143482
143468
|
["system_prompt_hash", ""],
|
|
143483
143469
|
["stripped_placeholder_ids", ""],
|
|
143470
|
+
["stale_reduce_stripped_ids", ""],
|
|
143484
143471
|
["memory_block_cache", ""],
|
|
143485
143472
|
["memory_block_ids", ""],
|
|
143486
143473
|
["compaction_marker_state", ""],
|
|
@@ -144416,7 +144403,7 @@ function runMigrations(db) {
|
|
|
144416
144403
|
}
|
|
144417
144404
|
// ../plugin/src/features/magic-context/project-docs-hash.ts
|
|
144418
144405
|
import { createHash as createHash3 } from "node:crypto";
|
|
144419
|
-
import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
144406
|
+
import { lstatSync, readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
|
|
144420
144407
|
import path4 from "node:path";
|
|
144421
144408
|
var PROJECT_DOC_FILES = ["ARCHITECTURE.md", "STRUCTURE.md"];
|
|
144422
144409
|
var PROJECT_DOCS_DELIMITER = `
|
|
@@ -144424,6 +144411,7 @@ var PROJECT_DOCS_DELIMITER = `
|
|
|
144424
144411
|
---
|
|
144425
144412
|
|
|
144426
144413
|
`;
|
|
144414
|
+
var MAX_PROJECT_DOC_BYTES = 256 * 1024;
|
|
144427
144415
|
var docsCache = new Map;
|
|
144428
144416
|
function canonicalizeDocContent(raw) {
|
|
144429
144417
|
return raw.replace(/^\uFEFF/, "").replace(/\r\n/g, `
|
|
@@ -144433,9 +144421,10 @@ function canonicalizeDocContent(raw) {
|
|
|
144433
144421
|
}
|
|
144434
144422
|
function fingerprintFile(filePath) {
|
|
144435
144423
|
try {
|
|
144436
|
-
const stat =
|
|
144424
|
+
const stat = lstatSync(filePath);
|
|
144425
|
+
const isReadableDoc = stat.isFile() && stat.size <= MAX_PROJECT_DOC_BYTES;
|
|
144437
144426
|
return {
|
|
144438
|
-
exists:
|
|
144427
|
+
exists: isReadableDoc,
|
|
144439
144428
|
mtimeMs: stat.mtimeMs,
|
|
144440
144429
|
size: stat.size
|
|
144441
144430
|
};
|
|
@@ -144478,6 +144467,16 @@ function readCanonicalPieces(projectDirectory, files) {
|
|
|
144478
144467
|
if (!fingerprint?.exists) {
|
|
144479
144468
|
continue;
|
|
144480
144469
|
}
|
|
144470
|
+
let safeToRead = false;
|
|
144471
|
+
try {
|
|
144472
|
+
const st = lstatSync(filePath);
|
|
144473
|
+
safeToRead = st.isFile() && st.size <= MAX_PROJECT_DOC_BYTES;
|
|
144474
|
+
} catch {
|
|
144475
|
+
safeToRead = false;
|
|
144476
|
+
}
|
|
144477
|
+
if (!safeToRead) {
|
|
144478
|
+
continue;
|
|
144479
|
+
}
|
|
144481
144480
|
const canonicalContent = canonicalizeDocContent(readFileSync2(filePath, "utf8"));
|
|
144482
144481
|
hashPieces.push(`file:${filename}
|
|
144483
144482
|
${canonicalContent}`);
|
|
@@ -144798,7 +144797,8 @@ function casUpdateJsonArrayColumn(db, sessionId, column, validator, mutate, opti
|
|
|
144798
144797
|
}
|
|
144799
144798
|
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
144800
144799
|
const row = db.prepare(`SELECT ${column} FROM session_meta WHERE session_id = ?`).get(sessionId);
|
|
144801
|
-
const
|
|
144800
|
+
const rawCurrent = row?.[column] ?? null;
|
|
144801
|
+
const currentBlob = rawCurrent ?? "[]";
|
|
144802
144802
|
const current = parseJsonArray(currentBlob, validator);
|
|
144803
144803
|
const next = mutate(current);
|
|
144804
144804
|
if (next === null)
|
|
@@ -144806,7 +144806,7 @@ function casUpdateJsonArrayColumn(db, sessionId, column, validator, mutate, opti
|
|
|
144806
144806
|
const nextBlob = stableStringify(next);
|
|
144807
144807
|
if (nextBlob === currentBlob)
|
|
144808
144808
|
return true;
|
|
144809
|
-
const result = db.prepare(`UPDATE session_meta SET ${column} = ? WHERE session_id = ? AND ${column}
|
|
144809
|
+
const result = db.prepare(`UPDATE session_meta SET ${column} = ? WHERE session_id = ? AND ${column} IS ?`).run(nextBlob, sessionId, rawCurrent);
|
|
144810
144810
|
if (result.changes > 0)
|
|
144811
144811
|
return true;
|
|
144812
144812
|
}
|
|
@@ -144935,14 +144935,16 @@ function getHistorianFailureState(db, sessionId) {
|
|
|
144935
144935
|
};
|
|
144936
144936
|
}
|
|
144937
144937
|
function incrementHistorianFailure(db, sessionId, error) {
|
|
144938
|
+
let nextCount = 1;
|
|
144938
144939
|
db.transaction(() => {
|
|
144939
144940
|
ensureSessionMetaRow(db, sessionId);
|
|
144940
144941
|
const current = getHistorianFailureState(db, sessionId);
|
|
144941
|
-
|
|
144942
|
+
nextCount = current.failureCount + 1;
|
|
144942
144943
|
db.prepare("UPDATE session_meta SET historian_failure_count = ?, historian_last_error = ?, historian_last_failure_at = ? WHERE session_id = ?").run(nextCount, error, Date.now(), sessionId);
|
|
144943
144944
|
const reason = error.replace(/\s+/g, " ").trim().slice(0, 300);
|
|
144944
144945
|
sessionLog(sessionId, `historian failure recorded: count=${nextCount} reason="${reason}"`);
|
|
144945
144946
|
})();
|
|
144947
|
+
return nextCount;
|
|
144946
144948
|
}
|
|
144947
144949
|
function clearHistorianFailureState(db, sessionId) {
|
|
144948
144950
|
db.transaction(() => {
|
|
@@ -145011,10 +145013,39 @@ function getStrippedPlaceholderIds(db, sessionId) {
|
|
|
145011
145013
|
} catch {}
|
|
145012
145014
|
return new Set;
|
|
145013
145015
|
}
|
|
145014
|
-
function
|
|
145016
|
+
function applyStrippedPlaceholderDelta(db, sessionId, delta) {
|
|
145017
|
+
const add = delta.add ? [...delta.add] : [];
|
|
145018
|
+
const remove = delta.remove ? [...delta.remove] : [];
|
|
145019
|
+
if (add.length === 0 && remove.length === 0)
|
|
145020
|
+
return true;
|
|
145015
145021
|
ensureSessionMetaRow(db, sessionId);
|
|
145016
|
-
|
|
145017
|
-
|
|
145022
|
+
for (let attempt = 0;attempt < CAS_RETRY_LIMIT; attempt += 1) {
|
|
145023
|
+
const row = db.prepare("SELECT stripped_placeholder_ids FROM session_meta WHERE session_id = ?").get(sessionId);
|
|
145024
|
+
const rawStored = row ? row.stripped_placeholder_ids ?? null : null;
|
|
145025
|
+
const current = new Set(parseStrippedBlob(rawStored));
|
|
145026
|
+
for (const id of add)
|
|
145027
|
+
current.add(id);
|
|
145028
|
+
for (const id of remove)
|
|
145029
|
+
current.delete(id);
|
|
145030
|
+
const nextBlob = current.size > 0 ? JSON.stringify([...current]) : "";
|
|
145031
|
+
if (nextBlob === (rawStored ?? ""))
|
|
145032
|
+
return true;
|
|
145033
|
+
const result = db.prepare("UPDATE session_meta SET stripped_placeholder_ids = ? WHERE session_id = ? AND stripped_placeholder_ids IS ?").run(nextBlob, sessionId, rawStored);
|
|
145034
|
+
if (result.changes > 0)
|
|
145035
|
+
return true;
|
|
145036
|
+
}
|
|
145037
|
+
sessionLog(sessionId, `stripped_placeholder_ids CAS: ${CAS_RETRY_LIMIT} retries exhausted`);
|
|
145038
|
+
return false;
|
|
145039
|
+
}
|
|
145040
|
+
function parseStrippedBlob(raw) {
|
|
145041
|
+
if (!raw || raw.length === 0)
|
|
145042
|
+
return [];
|
|
145043
|
+
try {
|
|
145044
|
+
const parsed = JSON.parse(raw);
|
|
145045
|
+
if (Array.isArray(parsed))
|
|
145046
|
+
return parsed.filter((v) => typeof v === "string");
|
|
145047
|
+
} catch {}
|
|
145048
|
+
return [];
|
|
145018
145049
|
}
|
|
145019
145050
|
function isPendingCompactionMarker(value) {
|
|
145020
145051
|
return typeof value === "object" && value !== null && typeof value.ordinal === "number" && typeof value.endMessageId === "string" && typeof value.publishedAt === "number";
|
|
@@ -149732,7 +149763,7 @@ async function runDream(args) {
|
|
|
149732
149763
|
}
|
|
149733
149764
|
}
|
|
149734
149765
|
const deadline = startedAt + args.maxRuntimeMinutes * 60 * 1000;
|
|
149735
|
-
const lastDreamAt = getDreamState(args.db, `last_dream_at:${args.projectIdentity}`)
|
|
149766
|
+
const lastDreamAt = getDreamState(args.db, `last_dream_at:${args.projectIdentity}`);
|
|
149736
149767
|
log(`[dreamer] last dream at: ${lastDreamAt ?? "never"} (project=${args.projectIdentity})`);
|
|
149737
149768
|
let lastErrorSignature = null;
|
|
149738
149769
|
let consecutiveSameErrorFailures = 0;
|
|
@@ -150114,7 +150145,6 @@ async function runDream(args) {
|
|
|
150114
150145
|
const hasSuccessfulTask = result.tasks.some((t) => !t.error && !POST_TASK_NAMES.has(t.name));
|
|
150115
150146
|
if (hasSuccessfulTask && !lostLease) {
|
|
150116
150147
|
setDreamState(args.db, `last_dream_at:${args.projectIdentity}`, String(result.finishedAt));
|
|
150117
|
-
setDreamState(args.db, "last_dream_at", String(result.finishedAt));
|
|
150118
150148
|
}
|
|
150119
150149
|
const totalDuration = ((result.finishedAt - startedAt) / 1000).toFixed(1);
|
|
150120
150150
|
const succeeded = result.tasks.filter((t) => !t.error).length;
|
|
@@ -150390,8 +150420,7 @@ function findProjectsNeedingDream(db) {
|
|
|
150390
150420
|
const now = new Date;
|
|
150391
150421
|
for (const row of projectRows) {
|
|
150392
150422
|
const lastDreamAtStr = getDreamState(db, `last_dream_at:${row.project_path}`);
|
|
150393
|
-
const
|
|
150394
|
-
const lastDreamAt = Number(lastDreamAtStr ?? fallbackStr ?? "0") || 0;
|
|
150423
|
+
const lastDreamAt = Number(lastDreamAtStr ?? "0") || 0;
|
|
150395
150424
|
if (lastDreamAt > 0 && isDreamFromCurrentWindow(lastDreamAt, now)) {
|
|
150396
150425
|
continue;
|
|
150397
150426
|
}
|
|
@@ -165363,6 +165392,59 @@ class LocalEmbeddingProvider {
|
|
|
165363
165392
|
}
|
|
165364
165393
|
}
|
|
165365
165394
|
|
|
165395
|
+
// ../plugin/src/features/magic-context/memory/embedding-ssrf.ts
|
|
165396
|
+
var METADATA_HOSTNAMES = new Set(["metadata.google.internal", "metadata.goog"]);
|
|
165397
|
+
var IPV6_METADATA_HOSTS = new Set(["fd00:ec2::254"]);
|
|
165398
|
+
function isLinkLocalIpv4(host) {
|
|
165399
|
+
return /^169\.254\.\d{1,3}\.\d{1,3}$/.test(host);
|
|
165400
|
+
}
|
|
165401
|
+
function ipv4FromMappedIpv6(host) {
|
|
165402
|
+
const m = /^::ffff:(.+)$/.exec(host);
|
|
165403
|
+
if (!m)
|
|
165404
|
+
return null;
|
|
165405
|
+
const tail = m[1];
|
|
165406
|
+
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(tail))
|
|
165407
|
+
return tail;
|
|
165408
|
+
const hex3 = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(tail);
|
|
165409
|
+
if (hex3) {
|
|
165410
|
+
const hi = Number.parseInt(hex3[1], 16);
|
|
165411
|
+
const lo = Number.parseInt(hex3[2], 16);
|
|
165412
|
+
if (Number.isNaN(hi) || Number.isNaN(lo))
|
|
165413
|
+
return null;
|
|
165414
|
+
return `${hi >> 8 & 255}.${hi & 255}.${lo >> 8 & 255}.${lo & 255}`;
|
|
165415
|
+
}
|
|
165416
|
+
return null;
|
|
165417
|
+
}
|
|
165418
|
+
function blockedEmbeddingEndpointReason(endpoint) {
|
|
165419
|
+
const trimmed = endpoint.trim();
|
|
165420
|
+
if (trimmed.length === 0)
|
|
165421
|
+
return null;
|
|
165422
|
+
let url2;
|
|
165423
|
+
try {
|
|
165424
|
+
url2 = new URL(trimmed);
|
|
165425
|
+
} catch {
|
|
165426
|
+
return `embedding endpoint is not a valid URL: ${trimmed}`;
|
|
165427
|
+
}
|
|
165428
|
+
const host = url2.hostname.toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
|
|
165429
|
+
if (METADATA_HOSTNAMES.has(host)) {
|
|
165430
|
+
return `embedding endpoint host ${host} is a cloud metadata service (blocked)`;
|
|
165431
|
+
}
|
|
165432
|
+
if (IPV6_METADATA_HOSTS.has(host)) {
|
|
165433
|
+
return `embedding endpoint host ${host} is the AWS IPv6 metadata service (blocked)`;
|
|
165434
|
+
}
|
|
165435
|
+
if (isLinkLocalIpv4(host)) {
|
|
165436
|
+
return `embedding endpoint host ${host} is link-local / cloud metadata (blocked)`;
|
|
165437
|
+
}
|
|
165438
|
+
const mappedV4 = ipv4FromMappedIpv6(host);
|
|
165439
|
+
if (mappedV4 && isLinkLocalIpv4(mappedV4)) {
|
|
165440
|
+
return `embedding endpoint host ${host} (IPv4-mapped ${mappedV4}) is link-local / cloud metadata (blocked)`;
|
|
165441
|
+
}
|
|
165442
|
+
if (host.startsWith("fe80:")) {
|
|
165443
|
+
return `embedding endpoint host ${host} is link-local / cloud metadata (blocked)`;
|
|
165444
|
+
}
|
|
165445
|
+
return null;
|
|
165446
|
+
}
|
|
165447
|
+
|
|
165366
165448
|
// ../plugin/src/features/magic-context/memory/embedding-openai.ts
|
|
165367
165449
|
function normalizeEndpoint2(endpoint) {
|
|
165368
165450
|
return endpoint?.trim().replace(/\/+$/, "") ?? "";
|
|
@@ -165405,6 +165487,12 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
165405
165487
|
this.initialized = false;
|
|
165406
165488
|
return false;
|
|
165407
165489
|
}
|
|
165490
|
+
const blockedReason = blockedEmbeddingEndpointReason(this.endpoint);
|
|
165491
|
+
if (blockedReason) {
|
|
165492
|
+
log(`[magic-context] embedding endpoint blocked: ${blockedReason}`);
|
|
165493
|
+
this.initialized = false;
|
|
165494
|
+
return false;
|
|
165495
|
+
}
|
|
165408
165496
|
this.initialized = true;
|
|
165409
165497
|
return true;
|
|
165410
165498
|
}
|
|
@@ -165450,6 +165538,7 @@ class OpenAICompatibleEmbeddingProvider {
|
|
|
165450
165538
|
...this.inputType ? { input_type: this.inputType } : {},
|
|
165451
165539
|
...this.truncate ? { truncate: this.truncate } : {}
|
|
165452
165540
|
}),
|
|
165541
|
+
redirect: "error",
|
|
165453
165542
|
signal: internalController.signal
|
|
165454
165543
|
});
|
|
165455
165544
|
if (!response.ok) {
|
|
@@ -165816,11 +165905,15 @@ function resolveEmbeddingConfig(config2) {
|
|
|
165816
165905
|
}
|
|
165817
165906
|
if (config2.provider === "openai-compatible") {
|
|
165818
165907
|
const apiKey = config2.api_key?.trim();
|
|
165908
|
+
const inputType = config2.input_type?.trim();
|
|
165909
|
+
const truncate = config2.truncate?.trim();
|
|
165819
165910
|
return {
|
|
165820
165911
|
provider: "openai-compatible",
|
|
165821
165912
|
model: config2.model.trim(),
|
|
165822
165913
|
endpoint: config2.endpoint.trim(),
|
|
165823
|
-
...apiKey ? { api_key: apiKey } : {}
|
|
165914
|
+
...apiKey ? { api_key: apiKey } : {},
|
|
165915
|
+
...inputType ? { input_type: inputType } : {},
|
|
165916
|
+
...truncate ? { truncate } : {}
|
|
165824
165917
|
};
|
|
165825
165918
|
}
|
|
165826
165919
|
return { provider: "off" };
|
|
@@ -165836,7 +165929,9 @@ function createProvider(config2) {
|
|
|
165836
165929
|
return new OpenAICompatibleEmbeddingProvider({
|
|
165837
165930
|
endpoint: config2.endpoint,
|
|
165838
165931
|
model: config2.model,
|
|
165839
|
-
apiKey: config2.api_key
|
|
165932
|
+
apiKey: config2.api_key,
|
|
165933
|
+
inputType: config2.input_type,
|
|
165934
|
+
truncate: config2.truncate
|
|
165840
165935
|
});
|
|
165841
165936
|
}
|
|
165842
165937
|
return new LocalEmbeddingProvider(config2.model);
|
|
@@ -166648,10 +166743,20 @@ var EMBEDDING_AFFECTING_KEYS = new Set([
|
|
|
166648
166743
|
"embedding.api_key",
|
|
166649
166744
|
"embedding.endpoint",
|
|
166650
166745
|
"embedding.model",
|
|
166651
|
-
"embedding.provider"
|
|
166746
|
+
"embedding.provider",
|
|
166747
|
+
"embedding.input_type",
|
|
166748
|
+
"embedding.truncate"
|
|
166652
166749
|
]);
|
|
166653
166750
|
var EMBEDDING_AFFECTING_TOP_LEVEL_KEYS = new Set(["embedding", "memory", "experimental"]);
|
|
166654
|
-
var EMBEDDING_WARNING_TERMS = [
|
|
166751
|
+
var EMBEDDING_WARNING_TERMS = [
|
|
166752
|
+
"api_key",
|
|
166753
|
+
"endpoint",
|
|
166754
|
+
"model",
|
|
166755
|
+
"provider",
|
|
166756
|
+
"embedding",
|
|
166757
|
+
"input_type",
|
|
166758
|
+
"truncate"
|
|
166759
|
+
];
|
|
166655
166760
|
var loggedFailureSignatures = new Map;
|
|
166656
166761
|
function sha256Prefix2(value, length = 16) {
|
|
166657
166762
|
return createHash8("sha256").update(value).digest("hex").slice(0, length);
|
|
@@ -166717,6 +166822,31 @@ function handleUntrustedLoad(db, projectIdentity, directory, detailed) {
|
|
|
166717
166822
|
return true;
|
|
166718
166823
|
}
|
|
166719
166824
|
|
|
166825
|
+
// ../plugin/src/config/prune-config-leaf.ts
|
|
166826
|
+
function isPlainObject2(value) {
|
|
166827
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
166828
|
+
}
|
|
166829
|
+
function pruneNestedConfigLeaf(block, relativePath) {
|
|
166830
|
+
if (relativePath.length === 0)
|
|
166831
|
+
return null;
|
|
166832
|
+
const result = { ...block };
|
|
166833
|
+
let cursor = result;
|
|
166834
|
+
for (let i = 0;i < relativePath.length - 1; i++) {
|
|
166835
|
+
const seg = String(relativePath[i]);
|
|
166836
|
+
const child = cursor[seg];
|
|
166837
|
+
if (!isPlainObject2(child))
|
|
166838
|
+
return null;
|
|
166839
|
+
const clonedChild = { ...child };
|
|
166840
|
+
cursor[seg] = clonedChild;
|
|
166841
|
+
cursor = clonedChild;
|
|
166842
|
+
}
|
|
166843
|
+
const leaf = String(relativePath[relativePath.length - 1]);
|
|
166844
|
+
if (!(leaf in cursor))
|
|
166845
|
+
return null;
|
|
166846
|
+
delete cursor[leaf];
|
|
166847
|
+
return { block: result, removed: relativePath.map(String).join(".") };
|
|
166848
|
+
}
|
|
166849
|
+
|
|
166720
166850
|
// src/config/index.ts
|
|
166721
166851
|
import { existsSync as existsSync10, readFileSync as readFileSync8 } from "node:fs";
|
|
166722
166852
|
import { homedir as homedir4 } from "node:os";
|
|
@@ -166808,6 +166938,70 @@ function migrateLegacyExperimental(rawConfig, warnings) {
|
|
|
166808
166938
|
return patched;
|
|
166809
166939
|
}
|
|
166810
166940
|
|
|
166941
|
+
// ../plugin/src/config/project-security.ts
|
|
166942
|
+
var HIDDEN_AGENT_KEYS = ["historian", "dreamer", "sidekick"];
|
|
166943
|
+
var AGENT_ESCALATION_FIELDS = ["prompt", "permission", "tools", "system_prompt"];
|
|
166944
|
+
function isPlainObject3(value) {
|
|
166945
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
166946
|
+
}
|
|
166947
|
+
function stripUnsafeProjectConfigFields(projectRaw) {
|
|
166948
|
+
const warnings = [];
|
|
166949
|
+
if ("auto_update" in projectRaw) {
|
|
166950
|
+
delete projectRaw.auto_update;
|
|
166951
|
+
warnings.push("Ignoring auto_update from project config (security: this setting only honors user-level config).");
|
|
166952
|
+
}
|
|
166953
|
+
for (const agentKey of HIDDEN_AGENT_KEYS) {
|
|
166954
|
+
const block = projectRaw[agentKey];
|
|
166955
|
+
if (!isPlainObject3(block))
|
|
166956
|
+
continue;
|
|
166957
|
+
const removed = [];
|
|
166958
|
+
for (const field of AGENT_ESCALATION_FIELDS) {
|
|
166959
|
+
if (field in block) {
|
|
166960
|
+
delete block[field];
|
|
166961
|
+
removed.push(field);
|
|
166962
|
+
}
|
|
166963
|
+
}
|
|
166964
|
+
if (removed.length > 0) {
|
|
166965
|
+
warnings.push(`Ignoring ${agentKey}.${removed.join("/")} from project config ` + "(security: a repository cannot reprogram or re-permission hidden agents).");
|
|
166966
|
+
}
|
|
166967
|
+
}
|
|
166968
|
+
return warnings;
|
|
166969
|
+
}
|
|
166970
|
+
function normalizeEndpoint3(value) {
|
|
166971
|
+
if (typeof value !== "string")
|
|
166972
|
+
return;
|
|
166973
|
+
const trimmed = value.trim().replace(/\/+$/, "");
|
|
166974
|
+
return trimmed.length > 0 ? trimmed.toLowerCase() : undefined;
|
|
166975
|
+
}
|
|
166976
|
+
function dropInheritedEmbeddingKeyOnRedirect(projectRaw, mergedRaw, userRaw) {
|
|
166977
|
+
const projectEmbedding = projectRaw.embedding;
|
|
166978
|
+
if (!isPlainObject3(projectEmbedding))
|
|
166979
|
+
return [];
|
|
166980
|
+
const redirectsEndpoint = "endpoint" in projectEmbedding;
|
|
166981
|
+
if (!redirectsEndpoint)
|
|
166982
|
+
return [];
|
|
166983
|
+
const userEmbedding = userRaw?.embedding;
|
|
166984
|
+
if (isPlainObject3(userEmbedding)) {
|
|
166985
|
+
const projectEndpoint = normalizeEndpoint3(projectEmbedding.endpoint);
|
|
166986
|
+
const userEndpoint = normalizeEndpoint3(userEmbedding.endpoint);
|
|
166987
|
+
if (projectEndpoint !== undefined && projectEndpoint === userEndpoint) {
|
|
166988
|
+
return [];
|
|
166989
|
+
}
|
|
166990
|
+
}
|
|
166991
|
+
const providesOwnKey = typeof projectEmbedding.api_key === "string" && projectEmbedding.api_key.length > 0;
|
|
166992
|
+
if (providesOwnKey)
|
|
166993
|
+
return [];
|
|
166994
|
+
const mergedEmbedding = mergedRaw.embedding;
|
|
166995
|
+
if (!isPlainObject3(mergedEmbedding))
|
|
166996
|
+
return [];
|
|
166997
|
+
if (!("api_key" in mergedEmbedding))
|
|
166998
|
+
return [];
|
|
166999
|
+
delete mergedEmbedding.api_key;
|
|
167000
|
+
return [
|
|
167001
|
+
"Dropped inherited user embedding api_key because project config redirected " + "embedding.endpoint without supplying its own key (security: prevents key " + "exfiltration to a repository-chosen endpoint)."
|
|
167002
|
+
];
|
|
167003
|
+
}
|
|
167004
|
+
|
|
166811
167005
|
// ../plugin/src/config/variable.ts
|
|
166812
167006
|
import { existsSync as existsSync9, readFileSync as readFileSync7 } from "node:fs";
|
|
166813
167007
|
import { homedir as homedir3 } from "node:os";
|
|
@@ -166872,6 +167066,21 @@ function stripJsonComments(content) {
|
|
|
166872
167066
|
// ../plugin/src/config/variable.ts
|
|
166873
167067
|
var ENV_PATTERN = /\{env:([^}]+)\}/g;
|
|
166874
167068
|
var FILE_PATTERN = /\{file:([^}]+)\}/g;
|
|
167069
|
+
function sensitiveFilePathReason(resolvedPath) {
|
|
167070
|
+
const home = homedir3();
|
|
167071
|
+
const sensitiveDirs = [
|
|
167072
|
+
{ dir: resolve4(home, ".ssh"), label: "SSH keys" },
|
|
167073
|
+
{ dir: resolve4(home, ".aws"), label: "AWS credentials" },
|
|
167074
|
+
{ dir: resolve4(home, ".gnupg"), label: "GnuPG keyring" },
|
|
167075
|
+
{ dir: resolve4(home, ".config", "gh"), label: "GitHub CLI auth" }
|
|
167076
|
+
];
|
|
167077
|
+
for (const { dir, label } of sensitiveDirs) {
|
|
167078
|
+
if (resolvedPath === dir || resolvedPath.startsWith(`${dir}/`)) {
|
|
167079
|
+
return label;
|
|
167080
|
+
}
|
|
167081
|
+
}
|
|
167082
|
+
return null;
|
|
167083
|
+
}
|
|
166875
167084
|
function substituteConfigVariables(input) {
|
|
166876
167085
|
const warnings = [];
|
|
166877
167086
|
let text = input.text;
|
|
@@ -166925,6 +167134,10 @@ function substituteConfigVariables(input) {
|
|
|
166925
167134
|
} else if (!isAbsolute3(filePath)) {
|
|
166926
167135
|
filePath = resolve4(configDir, filePath);
|
|
166927
167136
|
}
|
|
167137
|
+
const sensitiveReason = sensitiveFilePathReason(filePath);
|
|
167138
|
+
if (sensitiveReason) {
|
|
167139
|
+
warnings.push(`${token} resolves to a sensitive path (${sensitiveReason}: ${filePath}); ` + "inlining its contents into config — make sure this is intentional.");
|
|
167140
|
+
}
|
|
166928
167141
|
if (!existsSync9(filePath)) {
|
|
166929
167142
|
warnings.push(`File not found for ${token} (resolved to ${filePath}); using empty string`);
|
|
166930
167143
|
continue;
|
|
@@ -166963,7 +167176,8 @@ function loadConfigFile(path7, scope) {
|
|
|
166963
167176
|
const rawText = readFileSync8(path7, "utf-8");
|
|
166964
167177
|
const substituted = substituteConfigVariables({
|
|
166965
167178
|
text: rawText,
|
|
166966
|
-
configPath: path7
|
|
167179
|
+
configPath: path7,
|
|
167180
|
+
isProjectConfig: scope === "project"
|
|
166967
167181
|
});
|
|
166968
167182
|
return {
|
|
166969
167183
|
path: path7,
|
|
@@ -167005,14 +167219,14 @@ function redactConfigValue(value) {
|
|
|
167005
167219
|
}
|
|
167006
167220
|
return typeof value;
|
|
167007
167221
|
}
|
|
167008
|
-
function
|
|
167222
|
+
function isPlainObject4(value) {
|
|
167009
167223
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
167010
167224
|
}
|
|
167011
167225
|
function mergeRawConfigs(base, override) {
|
|
167012
167226
|
const merged = { ...base };
|
|
167013
167227
|
for (const [key, overrideValue] of Object.entries(override)) {
|
|
167014
167228
|
const baseValue = merged[key];
|
|
167015
|
-
merged[key] =
|
|
167229
|
+
merged[key] = isPlainObject4(baseValue) && isPlainObject4(overrideValue) ? mergeRawConfigs(baseValue, overrideValue) : overrideValue;
|
|
167016
167230
|
}
|
|
167017
167231
|
return merged;
|
|
167018
167232
|
}
|
|
@@ -167026,10 +167240,15 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
167026
167240
|
}
|
|
167027
167241
|
const defaults = MagicContextConfigSchema.parse({});
|
|
167028
167242
|
const errorPaths = new Set;
|
|
167243
|
+
const issuePathsByKey = new Map;
|
|
167029
167244
|
for (const issue2 of parsed.error.issues) {
|
|
167030
167245
|
const topKey = issue2.path[0];
|
|
167031
167246
|
if (topKey !== undefined) {
|
|
167032
|
-
|
|
167247
|
+
const key = String(topKey);
|
|
167248
|
+
errorPaths.add(key);
|
|
167249
|
+
const paths = issuePathsByKey.get(key) ?? [];
|
|
167250
|
+
paths.push([...issue2.path]);
|
|
167251
|
+
issuePathsByKey.set(key, paths);
|
|
167033
167252
|
}
|
|
167034
167253
|
}
|
|
167035
167254
|
const patched = { ...migrated };
|
|
@@ -167037,11 +167256,32 @@ function parsePiConfig(rawConfig, recoveredTopLevelKeys = []) {
|
|
|
167037
167256
|
for (const key of errorPaths) {
|
|
167038
167257
|
recoveredTopLevelKeys.push(key);
|
|
167039
167258
|
const isAgentConfig = key === "historian" || key === "dreamer" || key === "sidekick";
|
|
167040
|
-
delete patched[key];
|
|
167041
167259
|
if (isAgentConfig) {
|
|
167260
|
+
delete patched[key];
|
|
167042
167261
|
warnings.push(`"${key}": invalid agent configuration, ignoring. Check your magic-context.jsonc.`);
|
|
167043
167262
|
continue;
|
|
167044
167263
|
}
|
|
167264
|
+
const issuePaths = issuePathsByKey.get(key) ?? [];
|
|
167265
|
+
const rawValue = migrated[key];
|
|
167266
|
+
const allNested = issuePaths.length > 0 && issuePaths.every((p) => p.length >= 2) && typeof rawValue === "object" && rawValue !== null && !Array.isArray(rawValue);
|
|
167267
|
+
if (allNested) {
|
|
167268
|
+
let prunedBlock = {
|
|
167269
|
+
...rawValue
|
|
167270
|
+
};
|
|
167271
|
+
const prunedLeaves = [];
|
|
167272
|
+
for (const p of issuePaths) {
|
|
167273
|
+
const relative3 = p.slice(1);
|
|
167274
|
+
const result = pruneNestedConfigLeaf(prunedBlock, relative3);
|
|
167275
|
+
if (result) {
|
|
167276
|
+
prunedBlock = result.block;
|
|
167277
|
+
prunedLeaves.push(result.removed);
|
|
167278
|
+
}
|
|
167279
|
+
}
|
|
167280
|
+
patched[key] = prunedBlock;
|
|
167281
|
+
warnings.push(`"${key}": invalid nested field(s) ${prunedLeaves.map((l) => `"${l}"`).join(", ")}, using defaults for those.`);
|
|
167282
|
+
continue;
|
|
167283
|
+
}
|
|
167284
|
+
delete patched[key];
|
|
167045
167285
|
const defaultValue = defaults[key];
|
|
167046
167286
|
warnings.push(`"${key}": invalid value (${redactConfigValue(rawConfig[key])}), using default ${JSON.stringify(defaultValue)}.`);
|
|
167047
167287
|
}
|
|
@@ -167074,10 +167314,22 @@ function loadPiConfig(opts = {}) {
|
|
|
167074
167314
|
return 0;
|
|
167075
167315
|
return a.scope === "user" ? -1 : 1;
|
|
167076
167316
|
});
|
|
167317
|
+
const userRaw = mergeFiles.find((f) => f.scope === "user")?.config;
|
|
167077
167318
|
for (const loaded of mergeFiles) {
|
|
167078
167319
|
const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
|
|
167079
167320
|
warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
|
|
167080
|
-
|
|
167321
|
+
if (loaded.scope === "project") {
|
|
167322
|
+
const projectRaw = { ...loaded.config };
|
|
167323
|
+
for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
|
|
167324
|
+
warnings.push(`${prefix} ${warning}`);
|
|
167325
|
+
}
|
|
167326
|
+
rawConfig = mergeRawConfigs(rawConfig, projectRaw);
|
|
167327
|
+
for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, userRaw)) {
|
|
167328
|
+
warnings.push(`${prefix} ${warning}`);
|
|
167329
|
+
}
|
|
167330
|
+
} else {
|
|
167331
|
+
rawConfig = mergeRawConfigs(rawConfig, loaded.config);
|
|
167332
|
+
}
|
|
167081
167333
|
}
|
|
167082
167334
|
const parsed = parsePiConfig(rawConfig);
|
|
167083
167335
|
warnings.push(...parsed.warnings.map((warning) => `[merged config] ${warning}`));
|
|
@@ -167152,10 +167404,22 @@ function loadPiConfigDetailed(opts = {}) {
|
|
|
167152
167404
|
return 0;
|
|
167153
167405
|
return a.scope === "user" ? -1 : 1;
|
|
167154
167406
|
});
|
|
167407
|
+
const userRaw = mergeFiles.find((f) => f.scope === "user")?.config;
|
|
167155
167408
|
for (const loaded of mergeFiles) {
|
|
167156
167409
|
const prefix = loaded.scope === "user" ? "[user config]" : "[project config]";
|
|
167157
167410
|
warnings.push(...loaded.warnings.map((warning) => `${prefix} ${warning}`));
|
|
167158
|
-
|
|
167411
|
+
if (loaded.scope === "project") {
|
|
167412
|
+
const projectRaw = { ...loaded.config };
|
|
167413
|
+
for (const warning of stripUnsafeProjectConfigFields(projectRaw)) {
|
|
167414
|
+
warnings.push(`${prefix} ${warning}`);
|
|
167415
|
+
}
|
|
167416
|
+
rawConfig = mergeRawConfigs(rawConfig, projectRaw);
|
|
167417
|
+
for (const warning of dropInheritedEmbeddingKeyOnRedirect(projectRaw, rawConfig, userRaw)) {
|
|
167418
|
+
warnings.push(`${prefix} ${warning}`);
|
|
167419
|
+
}
|
|
167420
|
+
} else {
|
|
167421
|
+
rawConfig = mergeRawConfigs(rawConfig, loaded.config);
|
|
167422
|
+
}
|
|
167159
167423
|
}
|
|
167160
167424
|
const recoveredTopLevelKeys = [];
|
|
167161
167425
|
const parsed = parsePiConfig(rawConfig, recoveredTopLevelKeys);
|
|
@@ -167210,7 +167474,11 @@ function registerPiDreamerProject(opts) {
|
|
|
167210
167474
|
}
|
|
167211
167475
|
const existing = registeredProjects2.get(opts.projectIdentity);
|
|
167212
167476
|
if (existing) {
|
|
167213
|
-
|
|
167477
|
+
if (existing.projectDir === opts.projectDir) {
|
|
167478
|
+
return;
|
|
167479
|
+
}
|
|
167480
|
+
existing.cleanup();
|
|
167481
|
+
registeredProjects2.delete(opts.projectIdentity);
|
|
167214
167482
|
}
|
|
167215
167483
|
registerDreamProjectDirectory(opts.projectIdentity, opts.projectDir);
|
|
167216
167484
|
const client = createPiDreamerClient(opts);
|
|
@@ -167256,7 +167524,8 @@ function registerPiDreamerProject(opts) {
|
|
|
167256
167524
|
cancelled = true;
|
|
167257
167525
|
cleanup?.();
|
|
167258
167526
|
},
|
|
167259
|
-
runOnce
|
|
167527
|
+
runOnce,
|
|
167528
|
+
projectDir: opts.projectDir
|
|
167260
167529
|
});
|
|
167261
167530
|
}
|
|
167262
167531
|
async function runPiDreamForProject(projectIdentity) {
|
|
@@ -167283,7 +167552,7 @@ async function awaitInFlightDreamers() {
|
|
|
167283
167552
|
function createPiDreamerClient(opts) {
|
|
167284
167553
|
const runner2 = piSubagentRunnerFactory();
|
|
167285
167554
|
const model = opts.config.model;
|
|
167286
|
-
const fallbackModels =
|
|
167555
|
+
const fallbackModels = resolveFallbackChain(DREAMER_AGENT, opts.config.fallback_models);
|
|
167287
167556
|
const session = {
|
|
167288
167557
|
create: async (args) => {
|
|
167289
167558
|
const sessionId = `magic-context-pi-dream-${++sessionCounter}`;
|
|
@@ -167343,15 +167612,6 @@ function createPiDreamerClient(opts) {
|
|
|
167343
167612
|
};
|
|
167344
167613
|
return { session };
|
|
167345
167614
|
}
|
|
167346
|
-
function normalizeFallbackModels(value) {
|
|
167347
|
-
if (Array.isArray(value)) {
|
|
167348
|
-
return value;
|
|
167349
|
-
}
|
|
167350
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
167351
|
-
return [value];
|
|
167352
|
-
}
|
|
167353
|
-
return;
|
|
167354
|
-
}
|
|
167355
167615
|
function readDirectory(args) {
|
|
167356
167616
|
const query = args.query;
|
|
167357
167617
|
if (typeof query !== "object" || query === null) {
|
|
@@ -168682,6 +168942,9 @@ function escapeXmlAttr2(s) {
|
|
|
168682
168942
|
function escapeXmlContent2(s) {
|
|
168683
168943
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
168684
168944
|
}
|
|
168945
|
+
function isTieredRow(c) {
|
|
168946
|
+
return typeof c.p1 === "string" && c.p1.length > 0;
|
|
168947
|
+
}
|
|
168685
168948
|
function tierBody(c, tier2) {
|
|
168686
168949
|
const tiers = [c.p1, c.p2, c.p3, c.p4];
|
|
168687
168950
|
const requested = tiers[tier2 - 1];
|
|
@@ -168711,12 +168974,13 @@ function renderOneCompartment(c, tier2) {
|
|
|
168711
168974
|
const baseAttrs = `start="${c.startMessage}" end="${c.endMessage}" title="${escapeXmlAttr2(c.title)}"`;
|
|
168712
168975
|
if (tier2 >= 5)
|
|
168713
168976
|
return "";
|
|
168714
|
-
if (c.legacy === 1) {
|
|
168715
|
-
|
|
168977
|
+
if (c.legacy === 1 || !isTieredRow(c)) {
|
|
168978
|
+
const flat = (c.content ?? "").trim();
|
|
168979
|
+
if (tier2 >= 4 || flat.length === 0)
|
|
168716
168980
|
return `<compartment ${baseAttrs} />`;
|
|
168717
168981
|
return [
|
|
168718
168982
|
`<compartment ${baseAttrs}>`,
|
|
168719
|
-
escapeXmlContent2(legacyBodyForTier(
|
|
168983
|
+
escapeXmlContent2(legacyBodyForTier(flat, tier2)),
|
|
168720
168984
|
"</compartment>"
|
|
168721
168985
|
].join(`
|
|
168722
168986
|
`);
|
|
@@ -171139,6 +171403,9 @@ function safeGetActiveUserMemoriesPi(db) {
|
|
|
171139
171403
|
throw error51;
|
|
171140
171404
|
}
|
|
171141
171405
|
}
|
|
171406
|
+
function memoryProjectPath(state) {
|
|
171407
|
+
return state.memoryEnabled === false ? undefined : state.projectIdentity;
|
|
171408
|
+
}
|
|
171142
171409
|
var EMPTY_PI_HARD_SIGNALS = {
|
|
171143
171410
|
systemHash: "",
|
|
171144
171411
|
toolSetHash: "",
|
|
@@ -171206,17 +171473,15 @@ function readCurrentMarkers(db, state, projectDocsHash) {
|
|
|
171206
171473
|
return readCurrentMarkersFromCompartments(db, state, getCompartments(db, state.sessionId), projectDocsHash);
|
|
171207
171474
|
}
|
|
171208
171475
|
function readCurrentMarkersFromCompartments(db, state, compartments, projectDocsHash) {
|
|
171209
|
-
const
|
|
171210
|
-
|
|
171211
|
-
|
|
171212
|
-
]);
|
|
171213
|
-
const projectState = getProjectState(db, state.projectIdentity);
|
|
171476
|
+
const memPath = memoryProjectPath(state);
|
|
171477
|
+
const memories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"]) : [];
|
|
171478
|
+
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
171214
171479
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
171215
171480
|
return {
|
|
171216
171481
|
maxCompartmentSeq: compartments.length > 0 ? compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ) : EMPTY_MAX_COMPARTMENT_SEQ,
|
|
171217
171482
|
maxMemoryId: memories.length > 0 ? memories.reduce((max, memory) => memory.id > max ? memory.id : max, 0) : 0,
|
|
171218
171483
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
171219
|
-
maxMemoryMutationId: getMaxMemoryMutationId(db,
|
|
171484
|
+
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
171220
171485
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
171221
171486
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
171222
171487
|
projectDocsHash: projectDocsHash ?? readProjectDocsCanonical(state.projectDirectory).canonicalHash,
|
|
@@ -171280,7 +171545,8 @@ ${memories.map((memory) => `- ${escapeXmlContent(memory.content)}`).join(`
|
|
|
171280
171545
|
</${wrapper}>`;
|
|
171281
171546
|
}
|
|
171282
171547
|
function renderM0Pi(state, db, projectDocs = readProjectDocsCanonical(state.projectDirectory).renderedBlock, decayPressureMultiplier = 1, memoriesOverride, compartmentsOverride, userProfileOverride) {
|
|
171283
|
-
const
|
|
171548
|
+
const memPath = memoryProjectPath(state);
|
|
171549
|
+
const allMemories = memoriesOverride ?? (memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"]) : []);
|
|
171284
171550
|
const memories = allMemories.length > 0 ? trimMemoriesToBudgetV2(state.sessionId, allMemories, state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS).renderOrder : allMemories;
|
|
171285
171551
|
const memoryBlock = memories.length > 0 ? renderMemoryBlockV2(memories) : undefined;
|
|
171286
171552
|
const baseHistoryBudget = state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS;
|
|
@@ -171330,17 +171596,18 @@ class PiMaterializeContentionError extends Error {
|
|
|
171330
171596
|
}
|
|
171331
171597
|
}
|
|
171332
171598
|
function readFrozenM0InputsPi(state, db, docs = readProjectDocsCanonical(state.projectDirectory), memoryCutoff) {
|
|
171599
|
+
const memPath = memoryProjectPath(state);
|
|
171333
171600
|
const read = db.transaction(() => {
|
|
171334
171601
|
const compartments = getCompartments(db, state.sessionId);
|
|
171335
|
-
const memories = getMemoriesByProject(db,
|
|
171602
|
+
const memories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], memoryCutoff) : [];
|
|
171336
171603
|
const userProfile = safeGetActiveUserMemoriesPi(db);
|
|
171337
|
-
const projectState = getProjectState(db,
|
|
171604
|
+
const projectState = memPath ? getProjectState(db, memPath) : undefined;
|
|
171338
171605
|
const globalState = getProjectState(db, GLOBAL_USER_PROFILE_PROJECT_PATH);
|
|
171339
171606
|
const markers = {
|
|
171340
171607
|
maxCompartmentSeq: compartments.reduce((max, compartment) => compartment.sequence > max ? compartment.sequence : max, EMPTY_MAX_COMPARTMENT_SEQ),
|
|
171341
171608
|
maxMemoryId: memories.reduce((max, memory) => memory.id > max ? memory.id : max, 0),
|
|
171342
171609
|
maxMutationId: getMaxM0MutationId(db, state.sessionId) ?? 0,
|
|
171343
|
-
maxMemoryMutationId: getMaxMemoryMutationId(db,
|
|
171610
|
+
maxMemoryMutationId: memPath ? getMaxMemoryMutationId(db, memPath) ?? 0 : 0,
|
|
171344
171611
|
projectMemoryEpoch: projectState?.projectMemoryEpoch ?? 0,
|
|
171345
171612
|
projectUserProfileVersion: globalState?.projectUserProfileVersion ?? 0,
|
|
171346
171613
|
projectDocsHash: docs.canonicalHash,
|
|
@@ -171511,20 +171778,21 @@ ${lines.join(`
|
|
|
171511
171778
|
count: mutations.length
|
|
171512
171779
|
};
|
|
171513
171780
|
}
|
|
171514
|
-
function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRenderedKeyFilesBlock) {
|
|
171781
|
+
function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRenderedKeyFilesBlock, compartmentsOverride) {
|
|
171515
171782
|
const sections = [];
|
|
171516
171783
|
const keyFiles = renderedKeyFilesBlockPi(state, db, preRenderedKeyFilesBlock);
|
|
171517
171784
|
if (keyFiles)
|
|
171518
171785
|
sections.push(keyFiles);
|
|
171519
|
-
const
|
|
171786
|
+
const memPath = memoryProjectPath(state);
|
|
171787
|
+
const memoryUpdates = memPath ? renderMemoryUpdatesBlockPi({
|
|
171520
171788
|
db,
|
|
171521
|
-
projectPath:
|
|
171789
|
+
projectPath: memPath,
|
|
171522
171790
|
afterId: markers.maxMemoryMutationId,
|
|
171523
171791
|
renderedMemoryIds
|
|
171524
|
-
});
|
|
171792
|
+
}) : { block: undefined, count: 0 };
|
|
171525
171793
|
if (memoryUpdates.block)
|
|
171526
171794
|
sections.push(memoryUpdates.block);
|
|
171527
|
-
const newCompartments = getCompartments(db, state.sessionId).filter((compartment) => compartment.sequence > markers.maxCompartmentSeq);
|
|
171795
|
+
const newCompartments = (compartmentsOverride ?? getCompartments(db, state.sessionId)).filter((compartment) => compartment.sequence > markers.maxCompartmentSeq);
|
|
171528
171796
|
if (newCompartments.length > 0) {
|
|
171529
171797
|
const body = newCompartments.map((compartment) => renderCompartmentAtTier(compartment, 1)).join(`
|
|
171530
171798
|
|
|
@@ -171533,7 +171801,7 @@ function renderM1PiWithMetadata(state, db, markers, renderedMemoryIds, preRender
|
|
|
171533
171801
|
${body}
|
|
171534
171802
|
</new-compartments>`);
|
|
171535
171803
|
}
|
|
171536
|
-
const newMemories = getMemoriesByProject(db,
|
|
171804
|
+
const newMemories = memPath ? getMemoriesByProject(db, memPath, ["active", "permanent"], markers.materializedAt).filter((memory) => memory.id > markers.maxMemoryId) : [];
|
|
171537
171805
|
if (newMemories.length > 0) {
|
|
171538
171806
|
const memoryBudget = state.injectionBudgetTokens ?? DEFAULT_MEMORY_BUDGET_TOKENS;
|
|
171539
171807
|
const trimmedNewMemories = trimMemoriesToBudgetV2(state.sessionId, newMemories, Math.max(1, Math.floor(memoryBudget * 0.25))).renderOrder;
|
|
@@ -171703,7 +171971,7 @@ function softRefreshCachedM1Pi(args) {
|
|
|
171703
171971
|
if (!markers) {
|
|
171704
171972
|
throw new PiMaterializeContentionError(`invalid cached m[0] markers for ${args.state.sessionId}`);
|
|
171705
171973
|
}
|
|
171706
|
-
const rendered = renderM1PiWithMetadata(args.state, args.db, markers, parseMemoryBlockIds(row.memory_block_ids), preRenderedKeyFilesBlock);
|
|
171974
|
+
const rendered = renderM1PiWithMetadata(args.state, args.db, markers, parseMemoryBlockIds(row.memory_block_ids), preRenderedKeyFilesBlock, args.compartmentsForNormalization);
|
|
171707
171975
|
const m1Bytes = Buffer.from(rendered.text, "utf8");
|
|
171708
171976
|
const latestCompartment = args.compartmentsForNormalization.at(-1);
|
|
171709
171977
|
const advancedBoundary = latestCompartment?.endMessageId && latestCompartment.endMessageId.length > 0 ? latestCompartment.endMessageId : markers.lastBaselineEndMessageId;
|
|
@@ -171831,11 +172099,15 @@ function injectM0M1Pi(state, db, piMessages, entryIds, recomputeM1ThisPass = fal
|
|
|
171831
172099
|
m1 = replayed.m1;
|
|
171832
172100
|
markers = replayed.markers;
|
|
171833
172101
|
}
|
|
171834
|
-
const
|
|
172102
|
+
const M0_DRIFT_RATIO_FLOOR_TOKENS = 500;
|
|
172103
|
+
const M1_DRIFT_RATIO = 0.15;
|
|
171835
172104
|
const M1_ABSOLUTE_CAP_RATIO = 0.2;
|
|
171836
172105
|
const m1AbsoluteBudget = (state.historyBudgetTokens ?? DEFAULT_HISTORY_BUDGET_TOKENS) * M1_ABSOLUTE_CAP_RATIO;
|
|
171837
|
-
const
|
|
171838
|
-
|
|
172106
|
+
const m1HasContent = m1 !== PI_M1_PLACEHOLDER;
|
|
172107
|
+
const m1Tokens = m1HasContent ? estimateTokens(m1) : 0;
|
|
172108
|
+
const m0Tokens = estimateTokens(m0);
|
|
172109
|
+
const m1OverAbsoluteCap = m1HasContent && m1Tokens > m1AbsoluteBudget;
|
|
172110
|
+
if (!materialized && !contentionExhausted && m1Recomputed && recomputeM1ThisPass && (memoryUpdateCount > 40 || m1OverAbsoluteCap || m1HasContent && m0Tokens >= M0_DRIFT_RATIO_FLOOR_TOKENS && m1Tokens > m0Tokens * M1_DRIFT_RATIO)) {
|
|
171839
172111
|
decision = { value: true, reason: "drift" };
|
|
171840
172112
|
try {
|
|
171841
172113
|
const result = materializeM0PiWithRetry(state, db);
|
|
@@ -171856,10 +172128,10 @@ function injectM0M1Pi(state, db, piMessages, entryIds, recomputeM1ThisPass = fal
|
|
|
171856
172128
|
injected: true,
|
|
171857
172129
|
compartmentCount: getCompartments(db, state.sessionId).length,
|
|
171858
172130
|
factCount: 0,
|
|
171859
|
-
memoryCount: getMemoriesByProject(db, state
|
|
172131
|
+
memoryCount: memoryProjectPath(state) ? getMemoriesByProject(db, memoryProjectPath(state), [
|
|
171860
172132
|
"active",
|
|
171861
172133
|
"permanent"
|
|
171862
|
-
]).length,
|
|
172134
|
+
]).length : 0,
|
|
171863
172135
|
skippedVisibleMessages,
|
|
171864
172136
|
m0Materialized: materialized,
|
|
171865
172137
|
m0Reason: decision.reason,
|
|
@@ -173155,6 +173427,27 @@ function validateHistorianOutput(text, _sessionId, chunk, _priorCompartments, se
|
|
|
173155
173427
|
events: parsed.events.length > 0 ? parsed.events : undefined
|
|
173156
173428
|
};
|
|
173157
173429
|
}
|
|
173430
|
+
var HISTORIAN_PERSISTENT_FAILURE_THRESHOLD = 3;
|
|
173431
|
+
function buildHistorianFailureNotice(failureCount, lastError) {
|
|
173432
|
+
if (failureCount >= HISTORIAN_PERSISTENT_FAILURE_THRESHOLD) {
|
|
173433
|
+
return [
|
|
173434
|
+
"## Magic Context — history comparting needs attention",
|
|
173435
|
+
"",
|
|
173436
|
+
`Magic Context has been unable to compart this session's history ${failureCount} times in a row. This usually means the configured historian model is misconfigured or unreachable (Magic Context already retried every fallback model automatically).`,
|
|
173437
|
+
"",
|
|
173438
|
+
`Last error: ${lastError}`,
|
|
173439
|
+
"",
|
|
173440
|
+
"Check your historian model in magic-context.jsonc, then restart. Your conversation keeps working normally in the meantime — this only affects how older history is summarized."
|
|
173441
|
+
].join(`
|
|
173442
|
+
`);
|
|
173443
|
+
}
|
|
173444
|
+
return [
|
|
173445
|
+
"## Magic Context",
|
|
173446
|
+
"",
|
|
173447
|
+
"Hit a transient issue comparting history this turn — Magic Context will retry automatically on the next turn. Nothing is lost and your conversation continues normally. You'll only be alerted again if this keeps happening."
|
|
173448
|
+
].join(`
|
|
173449
|
+
`);
|
|
173450
|
+
}
|
|
173158
173451
|
function buildHistorianRepairPrompt(originalPrompt, previousOutput, validationError) {
|
|
173159
173452
|
return [
|
|
173160
173453
|
originalPrompt,
|
|
@@ -174993,7 +175286,7 @@ ${body}
|
|
|
174993
175286
|
function renderSessionRefCompartment(c) {
|
|
174994
175287
|
const importance = c.importance ?? 50;
|
|
174995
175288
|
const attrs = `start="${c.startMessage}" end="${c.endMessage}" title="${escapeXmlAttr(c.title)}"` + (c.episodeType ? ` episode_type="${escapeXmlAttr(c.episodeType)}"` : "") + ` importance="${importance}"`;
|
|
174996
|
-
if (c.p1
|
|
175289
|
+
if (typeof c.p1 === "string" && c.p1.length > 0) {
|
|
174997
175290
|
const p4 = c.p4 && c.p4.length > 0 ? `<p4>
|
|
174998
175291
|
${escapeXmlContent(c.p4)}
|
|
174999
175292
|
</p4>` : "<p4/>";
|
|
@@ -175094,8 +175387,10 @@ async function runPiHistorian(deps) {
|
|
|
175094
175387
|
const existingValidationError = validateStoredCompartments(priorCompartments);
|
|
175095
175388
|
if (existingValidationError) {
|
|
175096
175389
|
sessionLog(sessionId, `historian failure: source=existing-validation reason="${existingValidationError}"`);
|
|
175097
|
-
|
|
175098
|
-
|
|
175390
|
+
{
|
|
175391
|
+
const failCount = incrementHistorianFailure(db, sessionId, existingValidationError);
|
|
175392
|
+
await notify(buildHistorianFailureNotice(failCount, existingValidationError));
|
|
175393
|
+
}
|
|
175099
175394
|
return;
|
|
175100
175395
|
}
|
|
175101
175396
|
const offset = priorCompartments.length > 0 ? priorCompartments[priorCompartments.length - 1].endMessage + 1 : 1;
|
|
@@ -175114,8 +175409,10 @@ async function runPiHistorian(deps) {
|
|
|
175114
175409
|
const chunkCoverageError = validateChunkCoverage(chunk);
|
|
175115
175410
|
if (chunkCoverageError) {
|
|
175116
175411
|
sessionLog(sessionId, `historian failure: source=chunk-coverage reason="${chunkCoverageError}" chunkRange=${chunk.startIndex}-${chunk.endIndex}`);
|
|
175117
|
-
|
|
175118
|
-
|
|
175412
|
+
{
|
|
175413
|
+
const failCount = incrementHistorianFailure(db, sessionId, chunkCoverageError);
|
|
175414
|
+
await notify(buildHistorianFailureNotice(failCount, chunkCoverageError));
|
|
175415
|
+
}
|
|
175119
175416
|
return;
|
|
175120
175417
|
}
|
|
175121
175418
|
const projectPath = resolveProjectIdentity(directory);
|
|
@@ -175244,8 +175541,10 @@ ${chunk.text}`,
|
|
|
175244
175541
|
if (validatedPass.kind !== "ok") {
|
|
175245
175542
|
const errorMsg = validatedPass.kind === "validation-failed" ? validatedPass.error : validatedPass.kind === "spawn-failed" ? `subagent run failed (${validatedPass.reason}): ${validatedPass.error}` : "historian returned no usable text";
|
|
175246
175543
|
sessionLog(sessionId, `historian failure: ${errorMsg}`);
|
|
175247
|
-
|
|
175248
|
-
|
|
175544
|
+
{
|
|
175545
|
+
const failCount = incrementHistorianFailure(db, sessionId, errorMsg);
|
|
175546
|
+
await notify(buildHistorianFailureNotice(failCount, errorMsg));
|
|
175547
|
+
}
|
|
175249
175548
|
return;
|
|
175250
175549
|
}
|
|
175251
175550
|
if (twoPass && validatedPass.kind === "ok") {
|
|
@@ -175290,8 +175589,10 @@ ${chunk.text}`,
|
|
|
175290
175589
|
if (lastNewEnd + 1 <= offset) {
|
|
175291
175590
|
const errorMsg = `historian returned compartments that did not advance past raw message ${offset - 1}`;
|
|
175292
175591
|
sessionLog(sessionId, `historian failure: source=no-progress newCompartmentCount=${newCompartments.length} lastNewEnd=${lastNewEnd} priorEnd=${offset - 1}`);
|
|
175293
|
-
|
|
175294
|
-
|
|
175592
|
+
{
|
|
175593
|
+
const failCount = incrementHistorianFailure(db, sessionId, errorMsg);
|
|
175594
|
+
await notify(buildHistorianFailureNotice(failCount, errorMsg));
|
|
175595
|
+
}
|
|
175295
175596
|
return;
|
|
175296
175597
|
}
|
|
175297
175598
|
const markerSummary = buildPiCompactionSummary(newCompartments);
|
|
@@ -175405,8 +175706,10 @@ ${chunk.text}`,
|
|
|
175405
175706
|
const desc = describeError(error51);
|
|
175406
175707
|
telemetry.failureReason = `exception: ${desc.brief}`;
|
|
175407
175708
|
sessionLog(sessionId, `historian failure: source=exception ${desc.brief}${desc.stackHead ? ` stackHead="${desc.stackHead}"` : ""}`);
|
|
175408
|
-
|
|
175409
|
-
|
|
175709
|
+
{
|
|
175710
|
+
const failCount = incrementHistorianFailure(db, sessionId, desc.brief);
|
|
175711
|
+
await notify(buildHistorianFailureNotice(failCount, desc.brief));
|
|
175712
|
+
}
|
|
175410
175713
|
} finally {
|
|
175411
175714
|
updateSessionMeta(db, sessionId, { compartmentInProgress: false });
|
|
175412
175715
|
try {
|
|
@@ -175870,6 +176173,7 @@ function stripPiDroppedPlaceholderMessages(args) {
|
|
|
175870
176173
|
};
|
|
175871
176174
|
const canPrune = (isCacheBusting || args.forceDiscovery === true) && !!stableIdByRef;
|
|
175872
176175
|
const presentIds = canPrune ? new Set : null;
|
|
176176
|
+
const discoveredIds = [];
|
|
175873
176177
|
if (isCacheBusting || args.forceDiscovery) {
|
|
175874
176178
|
for (let i = 0;i < messages.length; i++) {
|
|
175875
176179
|
const id = idOf(messages[i], i);
|
|
@@ -175880,6 +176184,7 @@ function stripPiDroppedPlaceholderMessages(args) {
|
|
|
175880
176184
|
continue;
|
|
175881
176185
|
if (!idsToStrip.has(id)) {
|
|
175882
176186
|
idsToStrip.add(id);
|
|
176187
|
+
discoveredIds.push(id);
|
|
175883
176188
|
discovered++;
|
|
175884
176189
|
}
|
|
175885
176190
|
}
|
|
@@ -175894,17 +176199,20 @@ function stripPiDroppedPlaceholderMessages(args) {
|
|
|
175894
176199
|
}
|
|
175895
176200
|
let pruned = 0;
|
|
175896
176201
|
if (presentIds) {
|
|
175897
|
-
const
|
|
175898
|
-
for (const id of
|
|
175899
|
-
if (presentIds.has(id))
|
|
175900
|
-
|
|
175901
|
-
}
|
|
175902
|
-
pruned =
|
|
175903
|
-
if (
|
|
175904
|
-
|
|
176202
|
+
const removedIds = [];
|
|
176203
|
+
for (const id of persistedIds) {
|
|
176204
|
+
if (!presentIds.has(id))
|
|
176205
|
+
removedIds.push(id);
|
|
176206
|
+
}
|
|
176207
|
+
pruned = removedIds.length;
|
|
176208
|
+
if (discoveredIds.length > 0 || removedIds.length > 0) {
|
|
176209
|
+
applyStrippedPlaceholderDelta(db, sessionId, {
|
|
176210
|
+
add: discoveredIds,
|
|
176211
|
+
remove: removedIds
|
|
176212
|
+
});
|
|
175905
176213
|
}
|
|
175906
|
-
} else if (
|
|
175907
|
-
|
|
176214
|
+
} else if (discoveredIds.length > 0) {
|
|
176215
|
+
applyStrippedPlaceholderDelta(db, sessionId, { add: discoveredIds });
|
|
175908
176216
|
}
|
|
175909
176217
|
if (removed > 0 || discovered > 0 || pruned > 0) {
|
|
175910
176218
|
sessionLog(sessionId, `placeholder strip: removed=${removed} discovered=${discovered} pruned=${pruned}`);
|
|
@@ -175929,6 +176237,7 @@ var PARTNER_FRAME_CLOSER_REDUCE = `
|
|
|
175929
176237
|
Reduction prompts are routine housekeeping to keep the session fast and cheap — act on them as light maintenance, never as scarcity warnings. Keep individual operations efficient, but never let context size change *what* work you take on or *how thoroughly* you do it.`;
|
|
175930
176238
|
var PARTNER_FRAME_CLOSER_NO_REDUCE = `
|
|
175931
176239
|
Context is managed for you entirely automatically — there's nothing to prune and no warnings to act on. Stay reasonably concise per operation, and never let context size change *what* work you take on or *how thoroughly* you do it.`;
|
|
176240
|
+
var CTX_NOTE_GUIDANCE = `Use \`ctx_note\` ONLY for genuinely future concerns — something to revisit much later, not work coming up in the next few turns (that's already in your active context) and not active multi-step work (use todos for that). Magic Context preserves your full context across both compaction and restarts, so an upcoming restart or "let's come back to this later" is never a reason to take a note — nothing is lost either way. Notes you do take survive compression and resurface at natural work boundaries (after commits, historian runs, todo completion).`;
|
|
175932
176241
|
function getToolHistoryGuidance(dropToolStructure) {
|
|
175933
176242
|
if (dropToolStructure) {
|
|
175934
176243
|
return `Compressed history intentionally omits tool calls and their outputs — summaries like "I edited file X" are historian records, not patterns to replicate. In the live conversation, older tool calls and their results are cleaned up to save context — you may see your own past messages referencing actions without the corresponding tool call or result visible. This is normal context management. ALWAYS use real tool calls; never simulate, fabricate, or inline tool outputs in your text. If there is no tool result message, the action did not happen. NEVER simulate, hallucinate or claim tool calls, command output, search results, file edits, or diffs in plain text as if they actually occurred.`;
|
|
@@ -175939,7 +176248,8 @@ var BASE_INTRO = (protectedTags, dropToolStructure) => `Messages and tool output
|
|
|
175939
176248
|
Use \`ctx_reduce\` to manage context size. It supports one operation:
|
|
175940
176249
|
- \`drop\`: Remove entirely (best for tool outputs you already acted on).
|
|
175941
176250
|
Syntax: "3-5", "1,2,9", or "1-5,8,12-15". Last ${protectedTags} tags are protected.
|
|
175942
|
-
|
|
176251
|
+
Do not announce or narrate \`ctx_reduce\` drops — just call the tool silently. Saying "I'll drop these outputs" wastes tokens the user does not care about.
|
|
176252
|
+
${CTX_NOTE_GUIDANCE}
|
|
175943
176253
|
Use \`ctx_memory\` to manage cross-session project memories. Write new memories or delete stale ones. Memories persist across sessions and are automatically injected into new sessions.
|
|
175944
176254
|
**Save to memory proactively**: If you spent multiple turns finding something (a file path, a DB location, a config pattern, a workaround), save it with \`ctx_memory\` so future sessions don't repeat the search. Examples:
|
|
175945
176255
|
- Found a project's source code path after searching → \`ctx_memory(action="write", category="ENVIRONMENT", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
@@ -175959,7 +176269,7 @@ NEVER drop large ranges blindly (e.g., "1-50"). Review each tag before deciding.
|
|
|
175959
176269
|
NEVER drop user messages — they are short and will be summarized by compartmentalization automatically. Dropping them loses context the historian needs.
|
|
175960
176270
|
NEVER drop assistant text messages unless they are exceptionally large. Your conversation messages are lightweight; only large tool outputs are worth dropping.
|
|
175961
176271
|
Before your turn finishes, consider using \`ctx_reduce\` to drop large tool outputs you no longer need.`;
|
|
175962
|
-
var BASE_INTRO_NO_REDUCE = (dropToolStructure) =>
|
|
176272
|
+
var BASE_INTRO_NO_REDUCE = (dropToolStructure) => `${CTX_NOTE_GUIDANCE}
|
|
175963
176273
|
Use \`ctx_memory\` to manage cross-session project memories. Write new memories or delete stale ones. Memories persist across sessions and are automatically injected into new sessions.
|
|
175964
176274
|
**Save to memory proactively**: If you spent multiple turns finding something (a file path, a DB location, a config pattern, a workaround), save it with \`ctx_memory\` so future sessions don't repeat the search. Examples:
|
|
175965
176275
|
- Found a project's source code path after searching → \`ctx_memory(action="write", category="ENVIRONMENT", content="OpenCode source is at ~/Work/OSS/opencode")\`
|
|
@@ -176749,7 +177059,9 @@ function consumeDeferredMaterialization(sessionId) {
|
|
|
176749
177059
|
deferredMaterializationSessions.delete(sessionId);
|
|
176750
177060
|
return wasSet;
|
|
176751
177061
|
}
|
|
177062
|
+
var MAX_TRACKED_SESSIONS = 100;
|
|
176752
177063
|
function trackSessionForProject(projectIdentity, sessionId) {
|
|
177064
|
+
activeContextHandlerSessions.delete(sessionId);
|
|
176753
177065
|
activeContextHandlerSessions.add(sessionId);
|
|
176754
177066
|
let sessions = sessionsByProject.get(projectIdentity);
|
|
176755
177067
|
if (!sessions) {
|
|
@@ -176757,6 +177069,12 @@ function trackSessionForProject(projectIdentity, sessionId) {
|
|
|
176757
177069
|
sessionsByProject.set(projectIdentity, sessions);
|
|
176758
177070
|
}
|
|
176759
177071
|
sessions.add(sessionId);
|
|
177072
|
+
while (activeContextHandlerSessions.size > MAX_TRACKED_SESSIONS) {
|
|
177073
|
+
const oldest = activeContextHandlerSessions.values().next().value;
|
|
177074
|
+
if (oldest === undefined || oldest === sessionId)
|
|
177075
|
+
break;
|
|
177076
|
+
clearContextHandlerSession(oldest);
|
|
177077
|
+
}
|
|
176760
177078
|
}
|
|
176761
177079
|
function isContextHandlerSessionActive(sessionId) {
|
|
176762
177080
|
return activeContextHandlerSessions.has(sessionId);
|
|
@@ -177140,24 +177458,26 @@ function registerPiContextHandler(pi, options) {
|
|
|
177140
177458
|
}
|
|
177141
177459
|
let usagePercentage = 0;
|
|
177142
177460
|
let usageInputTokens = 0;
|
|
177461
|
+
let usedPersistedUsage = false;
|
|
177143
177462
|
if (sessionMetaForUsage.lastContextPercentage > 0 && sessionMetaForUsage.lastInputTokens > 0) {
|
|
177144
177463
|
usagePercentage = sessionMetaForUsage.lastContextPercentage;
|
|
177145
177464
|
usageInputTokens = sessionMetaForUsage.lastInputTokens;
|
|
177465
|
+
usedPersistedUsage = true;
|
|
177146
177466
|
} else {
|
|
177147
177467
|
usagePercentage = typeof piUsage?.percent === "number" ? piUsage.percent : 0;
|
|
177148
177468
|
usageInputTokens = typeof piUsage?.tokens === "number" ? piUsage.tokens : 0;
|
|
177149
177469
|
}
|
|
177150
|
-
let usageContextLimit =
|
|
177470
|
+
let usageContextLimit = isSaneLimit(piUsage?.contextWindow) ? piUsage.contextWindow : undefined;
|
|
177151
177471
|
const tEmergencyRecovery = performance.now();
|
|
177472
|
+
let needsEmergencyBump = false;
|
|
177473
|
+
let emergencyRecoveryArmed = false;
|
|
177152
177474
|
try {
|
|
177153
177475
|
const overflowState = getOverflowState(options.db, sessionId);
|
|
177154
177476
|
if (overflowState.detectedContextLimit > 0) {
|
|
177155
177477
|
usageContextLimit = Math.min(usageContextLimit ?? overflowState.detectedContextLimit, overflowState.detectedContextLimit);
|
|
177156
177478
|
}
|
|
177157
|
-
|
|
177158
|
-
|
|
177159
|
-
usagePercentage = 95;
|
|
177160
|
-
}
|
|
177479
|
+
emergencyRecoveryArmed = overflowState.needsEmergencyRecovery;
|
|
177480
|
+
needsEmergencyBump = overflowState.needsEmergencyRecovery && usagePercentage < 95;
|
|
177161
177481
|
} catch (err) {
|
|
177162
177482
|
sessionLog(sessionId, `transform: overflow state read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
177163
177483
|
}
|
|
@@ -177169,6 +177489,13 @@ function registerPiContextHandler(pi, options) {
|
|
|
177169
177489
|
usageContextLimit = modelWindow;
|
|
177170
177490
|
}
|
|
177171
177491
|
}
|
|
177492
|
+
if (!usedPersistedUsage && isSaneLimit(usageContextLimit) && usageInputTokens > 0) {
|
|
177493
|
+
usagePercentage = usageInputTokens / usageContextLimit * 100;
|
|
177494
|
+
}
|
|
177495
|
+
if (needsEmergencyBump) {
|
|
177496
|
+
sessionLog(sessionId, `transform: overflow recovery flag set — bumping percentage to 95% (detectedLimit=${usageContextLimit ?? "unknown"})`);
|
|
177497
|
+
usagePercentage = 95;
|
|
177498
|
+
}
|
|
177172
177499
|
let schedulerDecision;
|
|
177173
177500
|
const tScheduler = performance.now();
|
|
177174
177501
|
try {
|
|
@@ -177218,10 +177545,6 @@ function registerPiContextHandler(pi, options) {
|
|
|
177218
177545
|
setDeferredExecutePendingIfAbsent(options.db, sessionId, flagPayload);
|
|
177219
177546
|
}
|
|
177220
177547
|
schedulerDecision = midTurnAdjustedSchedulerDecision;
|
|
177221
|
-
const deferredExecutePending = peekDeferredExecutePending(options.db, sessionId);
|
|
177222
|
-
if (deferredExecutePending !== null && schedulerDecision === "defer" && !midTurn) {
|
|
177223
|
-
schedulerDecision = "execute";
|
|
177224
|
-
}
|
|
177225
177548
|
sessionLog(sessionId, `[boundary-exec] base=${schedulerDecisionEarly} bypass=${bypassReason} midTurn=${midTurn} effective=${midTurnAdjustedSchedulerDecision} sideEffect=${sideEffect}`);
|
|
177226
177549
|
const forceMaterialization = usagePercentage >= FORCE_MATERIALIZATION_PERCENTAGE;
|
|
177227
177550
|
const isEmergency = usagePercentage >= EMERGENCY_BLOCK_PERCENTAGE;
|
|
@@ -177239,6 +177562,14 @@ function registerPiContextHandler(pi, options) {
|
|
|
177239
177562
|
sessionLog(sessionId, "EMERGENCY: historian wait completed (or timed out)");
|
|
177240
177563
|
} catch {}
|
|
177241
177564
|
}
|
|
177565
|
+
if (emergencyRecoveryArmed && !inFlightHistorian.has(sessionId) && !hasEligiblePiCompartmentHistory(options.db, sessionId)) {
|
|
177566
|
+
try {
|
|
177567
|
+
clearEmergencyRecovery(options.db, sessionId);
|
|
177568
|
+
sessionLog(sessionId, "EMERGENCY: disarming recovery — no eligible pre-tail history to compact (would otherwise loop at 95%)");
|
|
177569
|
+
} catch (err) {
|
|
177570
|
+
sessionLog(sessionId, `EMERGENCY: clearEmergencyRecovery failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
177571
|
+
}
|
|
177572
|
+
}
|
|
177242
177573
|
}
|
|
177243
177574
|
const isCacheBusting = historyRefreshSessions.has(sessionId);
|
|
177244
177575
|
sessionLog(sessionId, `transform: usage=${usagePercentage.toFixed(1)}% (${usageInputTokens} tokens, limit=${usageContextLimit ?? "?"}) decision=${schedulerDecision}${forceMaterialization ? " force=true" : ""}${isEmergency ? " EMERGENCY=true" : ""}${isCacheBusting ? " busting=true" : ""}`);
|
|
@@ -177256,6 +177587,7 @@ function registerPiContextHandler(pi, options) {
|
|
|
177256
177587
|
heuristics: options.heuristics,
|
|
177257
177588
|
injection: options.injection ? {
|
|
177258
177589
|
...options.injection,
|
|
177590
|
+
memoryEnabled: options.injection.memoryEnabled,
|
|
177259
177591
|
historyBudgetTokens: resolveHistoryBudgetTokensForPi({
|
|
177260
177592
|
historyBudgetPercentage: options.historian?.historyBudgetPercentage,
|
|
177261
177593
|
usagePercentage,
|
|
@@ -177573,7 +177905,16 @@ function maybeFireHistorian(args) {
|
|
|
177573
177905
|
let usageContextLimit;
|
|
177574
177906
|
try {
|
|
177575
177907
|
const piUsage = ctx.getContextUsage?.();
|
|
177576
|
-
usageContextLimit =
|
|
177908
|
+
usageContextLimit = isSaneLimit(piUsage?.contextWindow) ? piUsage.contextWindow : undefined;
|
|
177909
|
+
if (usageContextLimit === undefined && isSaneLimit(ctx.model?.contextWindow)) {
|
|
177910
|
+
usageContextLimit = ctx.model.contextWindow;
|
|
177911
|
+
}
|
|
177912
|
+
try {
|
|
177913
|
+
const overflowState = getOverflowState(db, sessionId);
|
|
177914
|
+
if (overflowState.detectedContextLimit > 0) {
|
|
177915
|
+
usageContextLimit = Math.min(usageContextLimit ?? overflowState.detectedContextLimit, overflowState.detectedContextLimit);
|
|
177916
|
+
}
|
|
177917
|
+
} catch {}
|
|
177577
177918
|
const sessionMetaForUsage = getOrCreateSessionMeta(db, sessionId);
|
|
177578
177919
|
if (sessionMetaForUsage.lastContextPercentage > 0 && sessionMetaForUsage.lastInputTokens > 0) {
|
|
177579
177920
|
usage = {
|
|
@@ -177586,8 +177927,9 @@ function maybeFireHistorian(args) {
|
|
|
177586
177927
|
sessionLog(sessionId, `historian trigger eval: no usage info yet (tokens=${piUsage?.tokens ?? "<no piUsage>"}, percent=${piUsage?.percent ?? "<no piUsage>"}, contextWindow=${piUsage?.contextWindow ?? "<no piUsage>"})`);
|
|
177587
177928
|
return;
|
|
177588
177929
|
}
|
|
177930
|
+
const fallbackPercentage = isSaneLimit(usageContextLimit) && piUsage.tokens > 0 ? piUsage.tokens / usageContextLimit * 100 : piUsage.percent;
|
|
177589
177931
|
usage = {
|
|
177590
|
-
percentage:
|
|
177932
|
+
percentage: fallbackPercentage,
|
|
177591
177933
|
inputTokens: piUsage.tokens
|
|
177592
177934
|
};
|
|
177593
177935
|
sessionLog(sessionId, `historian trigger eval: usage=${usage.percentage.toFixed(1)}% (${usage.inputTokens} tokens) [piUsage fallback], checking trigger...`);
|
|
@@ -177663,6 +178005,7 @@ async function runPipeline(args) {
|
|
|
177663
178005
|
let executedWorkThisPass = false;
|
|
177664
178006
|
let historyWasConsumedThisPass = false;
|
|
177665
178007
|
let materializationSatisfiedThisPass = false;
|
|
178008
|
+
let pendingOpsAppliedThisPass = false;
|
|
177666
178009
|
let suppressDeferredHistoryDrain = false;
|
|
177667
178010
|
let casLost = false;
|
|
177668
178011
|
const deferredHistoryWasPendingAtPassStart = deferredHistoryRefreshSessions.has(args.sessionId);
|
|
@@ -177686,7 +178029,9 @@ async function runPipeline(args) {
|
|
|
177686
178029
|
return findLatestUserMessageIdPi(args.messages, ids)?.messageId ?? null;
|
|
177687
178030
|
})();
|
|
177688
178031
|
const alreadyRanHeuristicsThisTurn = currentTurnId !== null && lastHeuristicsTurnIdBySession.get(args.sessionId) === currentTurnId;
|
|
177689
|
-
const
|
|
178032
|
+
const canConsumeDeferredLate = args.schedulerDecision === "execute" || args.forceMaterialization === true || args.contextUsage.percentage >= FORCE_MATERIALIZATION_PERCENTAGE;
|
|
178033
|
+
const deferredMaterializeEligible = canConsumeDeferredLate && deferredMaterializationSessions.has(args.sessionId);
|
|
178034
|
+
const shouldRunHeuristics = args.heuristics !== undefined && (args.forceMaterialization === true || hasPendingMaterialization(args.sessionId) || deferredMaterializeEligible || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
|
|
177690
178035
|
const entryFingerprintByMessageId = buildEntryFingerprintMap(args.messages, stableIdResolver);
|
|
177691
178036
|
adoptPiFallbackTags(args.db, args.sessionId, args.tagger, entryFingerprintByMessageId);
|
|
177692
178037
|
const tTag = performance.now();
|
|
@@ -177712,15 +178057,13 @@ async function runPipeline(args) {
|
|
|
177712
178057
|
const hasPendingMaterializeSignal = hasPendingMaterialization(args.sessionId);
|
|
177713
178058
|
const deferredMaterializationWasPending = deferredMaterializationSessions.has(args.sessionId);
|
|
177714
178059
|
const deferredHistoryRefreshWasPending = deferredHistoryWasPendingAtPassStart;
|
|
177715
|
-
const deferredExecuteWasPending = peekDeferredExecutePending(args.db, args.sessionId) !== null;
|
|
177716
178060
|
const pendingOps = getPendingOps(args.db, args.sessionId);
|
|
177717
|
-
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal
|
|
177718
|
-
const canConsumeDeferredLate = baseShouldApplyPendingOps || shouldRunHeuristics;
|
|
178061
|
+
const baseShouldApplyPendingOps = args.schedulerDecision === "execute" || args.forceMaterialization || hasPendingMaterializeSignal;
|
|
177719
178062
|
const deferredMaterialize = canConsumeDeferredLate && deferredMaterializationWasPending;
|
|
177720
178063
|
const deferredHistoryRefresh = canConsumeDeferredLate && deferredHistoryRefreshWasPending;
|
|
177721
178064
|
const shouldApplyPendingOps = baseShouldApplyPendingOps || deferredMaterialize;
|
|
177722
178065
|
if (shouldApplyPendingOps) {
|
|
177723
|
-
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" :
|
|
178066
|
+
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : `scheduler_execute (scheduler=${args.schedulerDecision})`;
|
|
177724
178067
|
sessionLog(args.sessionId, `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOps.length}, context=${args.contextUsage.percentage.toFixed(1)}%`);
|
|
177725
178068
|
try {
|
|
177726
178069
|
const tApplyPending = performance.now();
|
|
@@ -177728,14 +178071,12 @@ async function runPipeline(args) {
|
|
|
177728
178071
|
logTransformTiming(args.sessionId, "applyPendingOperations", tApplyPending);
|
|
177729
178072
|
executedWorkThisPass = true;
|
|
177730
178073
|
materializationSatisfiedThisPass = true;
|
|
178074
|
+
pendingOpsAppliedThisPass = true;
|
|
177731
178075
|
if (hasPendingMaterializeSignal) {
|
|
177732
178076
|
if (args.heuristics === undefined) {
|
|
177733
178077
|
consumePendingMaterialization(args.sessionId);
|
|
177734
178078
|
}
|
|
177735
178079
|
}
|
|
177736
|
-
if (deferredMaterialize) {
|
|
177737
|
-
consumeDeferredMaterialization(args.sessionId);
|
|
177738
|
-
}
|
|
177739
178080
|
} catch (err) {
|
|
177740
178081
|
sessionLog(args.sessionId, `pending operations failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
177741
178082
|
throw err;
|
|
@@ -177822,6 +178163,12 @@ async function runPipeline(args) {
|
|
|
177822
178163
|
sessionLog(args.sessionId, `heuristic cleanup failed (continuing): ${err instanceof Error ? err.message : String(err)}`);
|
|
177823
178164
|
}
|
|
177824
178165
|
}
|
|
178166
|
+
if (deferredMaterialize && pendingOpsAppliedThisPass) {
|
|
178167
|
+
const fullPassSucceeded = shouldRunHeuristics ? heuristicsExecuted : true;
|
|
178168
|
+
if (fullPassSucceeded) {
|
|
178169
|
+
consumeDeferredMaterialization(args.sessionId);
|
|
178170
|
+
}
|
|
178171
|
+
}
|
|
177825
178172
|
if (args.reasoningClearing && shouldRunHeuristics) {
|
|
177826
178173
|
try {
|
|
177827
178174
|
const tClearReasoning = performance.now();
|
|
@@ -177890,6 +178237,7 @@ async function runPipeline(args) {
|
|
|
177890
178237
|
sessionId: args.sessionId,
|
|
177891
178238
|
projectIdentity: args.projectIdentity,
|
|
177892
178239
|
projectDirectory: args.projectDirectory,
|
|
178240
|
+
memoryEnabled: args.injection.memoryEnabled,
|
|
177893
178241
|
injectionBudgetTokens: args.injection.injectionBudgetTokens,
|
|
177894
178242
|
historyBudgetTokens: args.injection.historyBudgetTokens,
|
|
177895
178243
|
keyFilesEnabled: args.injection.keyFilesEnabled,
|
|
@@ -178417,15 +178765,15 @@ function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEn
|
|
|
178417
178765
|
const existing = getPersistedCompactionMarkerState(db, sessionId);
|
|
178418
178766
|
if (existing) {
|
|
178419
178767
|
if (existing.boundaryOrdinal === lastCompartmentEnd) {
|
|
178420
|
-
return;
|
|
178768
|
+
return true;
|
|
178421
178769
|
}
|
|
178422
|
-
|
|
178423
|
-
|
|
178424
|
-
|
|
178425
|
-
|
|
178426
|
-
} catch (error51) {
|
|
178427
|
-
sessionLog(sessionId, `compaction-marker: failed to remove old boundary at ordinal ${existing.boundaryOrdinal}, proceeding with new injection:`, error51);
|
|
178770
|
+
const removed = removeCompactionMarker(existing);
|
|
178771
|
+
if (!removed) {
|
|
178772
|
+
sessionLog(sessionId, `compaction-marker: failed to remove old boundary at ordinal ${existing.boundaryOrdinal}; preserving persisted state for retry (not injecting new marker this pass)`);
|
|
178773
|
+
return false;
|
|
178428
178774
|
}
|
|
178775
|
+
setPersistedCompactionMarkerState(db, sessionId, null);
|
|
178776
|
+
sessionLog(sessionId, `compaction-marker: removed old boundary at ordinal ${existing.boundaryOrdinal}, moving to ${lastCompartmentEnd}`);
|
|
178429
178777
|
}
|
|
178430
178778
|
const result = injectCompactionMarker({
|
|
178431
178779
|
sessionId,
|
|
@@ -178439,7 +178787,9 @@ function updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEn
|
|
|
178439
178787
|
boundaryOrdinal: lastCompartmentEnd
|
|
178440
178788
|
});
|
|
178441
178789
|
sessionLog(sessionId, `compaction-marker: injected at ordinal ${lastCompartmentEnd}, boundary user msg ${result.boundaryMessageId}`);
|
|
178790
|
+
return true;
|
|
178442
178791
|
}
|
|
178792
|
+
return false;
|
|
178443
178793
|
}
|
|
178444
178794
|
|
|
178445
178795
|
// ../plugin/src/hooks/magic-context/compartment-runner-historian.ts
|
|
@@ -178991,7 +179341,6 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
178991
179341
|
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
178992
179342
|
clearInjectionCache(sessionId);
|
|
178993
179343
|
}
|
|
178994
|
-
deps.onCompartmentStatePublished?.(sessionId);
|
|
178995
179344
|
promoted2.facts;
|
|
178996
179345
|
if (deps.memoryEnabled !== false) {
|
|
178997
179346
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
@@ -179004,11 +179353,14 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
179004
179353
|
if (lastCompartmentEnd2 > 0) {
|
|
179005
179354
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd2);
|
|
179006
179355
|
}
|
|
179356
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
179007
179357
|
if (lastCompartmentEnd2 > 0) {
|
|
179008
|
-
updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd2, deps.directory);
|
|
179009
|
-
|
|
179010
|
-
|
|
179011
|
-
|
|
179358
|
+
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd2, deps.directory);
|
|
179359
|
+
if (markerUpdated) {
|
|
179360
|
+
const stalePending = getPendingCompactionMarkerState(db, sessionId);
|
|
179361
|
+
if (stalePending) {
|
|
179362
|
+
clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
|
|
179363
|
+
}
|
|
179012
179364
|
}
|
|
179013
179365
|
}
|
|
179014
179366
|
return [
|
|
@@ -179197,13 +179549,13 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
179197
179549
|
if (deps.preserveInjectionCacheUntilConsumed !== true) {
|
|
179198
179550
|
clearInjectionCache(sessionId);
|
|
179199
179551
|
}
|
|
179200
|
-
deps.onCompartmentStatePublished?.(sessionId);
|
|
179201
179552
|
const finalCompartments = promoted?.compartments ?? candidateCompartments;
|
|
179202
179553
|
const finalFacts = promoted?.facts ?? candidateFacts;
|
|
179203
179554
|
const lastCompartmentEnd = finalCompartments[finalCompartments.length - 1]?.endMessage ?? 0;
|
|
179204
179555
|
if (lastCompartmentEnd > 0) {
|
|
179205
179556
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd);
|
|
179206
179557
|
}
|
|
179558
|
+
deps.onCompartmentStatePublished?.(sessionId);
|
|
179207
179559
|
if (deps.memoryEnabled !== false) {
|
|
179208
179560
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
179209
179561
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
@@ -179212,10 +179564,12 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
179212
179564
|
embedAndStoreCompartments(db, sessionId, projectIdentity, toEmbed);
|
|
179213
179565
|
}
|
|
179214
179566
|
if (lastCompartmentEnd > 0) {
|
|
179215
|
-
updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
179216
|
-
|
|
179217
|
-
|
|
179218
|
-
|
|
179567
|
+
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastCompartmentEnd, deps.directory);
|
|
179568
|
+
if (markerUpdated) {
|
|
179569
|
+
const stalePending = getPendingCompactionMarkerState(db, sessionId);
|
|
179570
|
+
if (stalePending) {
|
|
179571
|
+
clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
|
|
179572
|
+
}
|
|
179219
179573
|
}
|
|
179220
179574
|
}
|
|
179221
179575
|
return [
|
|
@@ -179349,7 +179703,7 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
179349
179703
|
log(`[magic-context] partial recomp merged validation failed: ${mergedError}`);
|
|
179350
179704
|
return null;
|
|
179351
179705
|
}
|
|
179352
|
-
saveRecompStagingPass(db, sessionId, passCount + 1, merged,
|
|
179706
|
+
saveRecompStagingPass(db, sessionId, passCount + 1, merged, stagedFacts);
|
|
179353
179707
|
const promoted = promoteRecompStagingWithM0Mutation(db, sessionId, leaseHolderId);
|
|
179354
179708
|
if (!promoted) {
|
|
179355
179709
|
log("[magic-context] partial recomp promote returned null");
|
|
@@ -179369,10 +179723,12 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
179369
179723
|
}
|
|
179370
179724
|
const lastEnd = merged[merged.length - 1]?.endMessage ?? snapEnd;
|
|
179371
179725
|
if (lastEnd > 0) {
|
|
179372
|
-
updateCompactionMarkerAfterPublication(db, sessionId, lastEnd, deps.directory);
|
|
179373
|
-
|
|
179374
|
-
|
|
179375
|
-
|
|
179726
|
+
const markerUpdated = updateCompactionMarkerAfterPublication(db, sessionId, lastEnd, deps.directory);
|
|
179727
|
+
if (markerUpdated) {
|
|
179728
|
+
const stalePending = getPendingCompactionMarkerState(db, sessionId);
|
|
179729
|
+
if (stalePending) {
|
|
179730
|
+
clearPendingCompactionMarkerStateIf(db, sessionId, stalePending);
|
|
179731
|
+
}
|
|
179376
179732
|
}
|
|
179377
179733
|
}
|
|
179378
179734
|
return { compartmentCount: merged.length, lastEndMessage: lastEnd };
|
|
@@ -179414,10 +179770,7 @@ Snapped range ${snapStart}-${snapEnd} would cross into the protected tail (start
|
|
|
179414
179770
|
].join(`
|
|
179415
179771
|
`);
|
|
179416
179772
|
}
|
|
179417
|
-
const
|
|
179418
|
-
category: f.category,
|
|
179419
|
-
content: f.content
|
|
179420
|
-
}));
|
|
179773
|
+
const stagedFacts = [];
|
|
179421
179774
|
const parentSessionResponse = await client.session.get({ path: { id: sessionId } }).catch(() => null);
|
|
179422
179775
|
const parentSession = normalizeSDKResponse(parentSessionResponse, null, { preferResponseOnMissingData: true });
|
|
179423
179776
|
const sessionDirectory = parentSession?.directory ?? directory;
|
|
@@ -179434,7 +179787,7 @@ Snapped range ${snapStart}-${snapEnd} would cross into the protected tail (start
|
|
|
179434
179787
|
candidateCompartments = priorCompartments.map((c, idx) => compartmentToInput(c, idx));
|
|
179435
179788
|
passCount = 0;
|
|
179436
179789
|
offset = snapStart;
|
|
179437
|
-
saveRecompStagingPass(db, sessionId, 0, candidateCompartments,
|
|
179790
|
+
saveRecompStagingPass(db, sessionId, 0, candidateCompartments, stagedFacts);
|
|
179438
179791
|
setRecompPartialRange(db, sessionId, { start: snapStart, end: snapEnd });
|
|
179439
179792
|
}
|
|
179440
179793
|
let currentTokenBudget = historianChunkTokens;
|
|
@@ -179527,7 +179880,7 @@ Original state preserved (staging kept for retry).`;
|
|
|
179527
179880
|
passCount += 1;
|
|
179528
179881
|
currentTokenBudget = historianChunkTokens;
|
|
179529
179882
|
passAttempt = 1;
|
|
179530
|
-
saveRecompStagingPass(db, sessionId, passCount, candidateCompartments,
|
|
179883
|
+
saveRecompStagingPass(db, sessionId, passCount, candidateCompartments, stagedFacts);
|
|
179531
179884
|
const nextOffset = (validatedPass.compartments?.[validatedPass.compartments.length - 1]?.endMessage ?? chunk.endIndex) + 1;
|
|
179532
179885
|
if (nextOffset <= offset) {
|
|
179533
179886
|
return `## Magic Recomp — Failed
|
|
@@ -179548,7 +179901,6 @@ Partial recomp completed historian passes but the final compartment set failed v
|
|
|
179548
179901
|
...resumed ? ["Resumed from previous interrupted partial run."] : [],
|
|
179549
179902
|
`Rebuilt compartments covering messages ${snapStart}-${snapEnd} using ${passCount} historian pass${passCount === 1 ? "" : "es"}.`,
|
|
179550
179903
|
`Preserved ${priorCompartments.length} prior compartment(s) and ${tailCompartments.length} tail compartment(s) unchanged.`,
|
|
179551
|
-
`Facts unchanged (${currentFacts.length} entr${currentFacts.length === 1 ? "y" : "ies"}).`,
|
|
179552
179904
|
`Total compartments: ${finalResult.compartmentCount}.`
|
|
179553
179905
|
].join(`
|
|
179554
179906
|
`);
|
|
@@ -180646,7 +180998,7 @@ function formatThresholdPercent(value) {
|
|
|
180646
180998
|
// package.json
|
|
180647
180999
|
var package_default = {
|
|
180648
181000
|
name: "@cortexkit/pi-magic-context",
|
|
180649
|
-
version: "0.22.
|
|
181001
|
+
version: "0.22.5",
|
|
180650
181002
|
type: "module",
|
|
180651
181003
|
description: "Pi coding agent extension for Magic Context — cross-session memory and context management",
|
|
180652
181004
|
main: "dist/index.js",
|
|
@@ -185528,7 +185880,6 @@ function createCtxMemoryTool(deps) {
|
|
|
185528
185880
|
sourceType: dreamerAllowed ? "dreamer" : "agent"
|
|
185529
185881
|
});
|
|
185530
185882
|
queueEmbedding({ deps, projectIdentity, memoryId: memory2.id, content });
|
|
185531
|
-
invalidateAllMemoryBlockCaches(deps.db);
|
|
185532
185883
|
return ok2(`Saved memory [ID: ${memory2.id}] in ${rawCategory}.`);
|
|
185533
185884
|
}
|
|
185534
185885
|
if (params.action === "delete") {
|
|
@@ -185536,7 +185887,7 @@ function createCtxMemoryTool(deps) {
|
|
|
185536
185887
|
return err2("Error: 'id' is required when action is 'delete'.");
|
|
185537
185888
|
}
|
|
185538
185889
|
const memory2 = getMemoryById(deps.db, params.id);
|
|
185539
|
-
if (!memory2 || memory2.projectPath
|
|
185890
|
+
if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
|
|
185540
185891
|
return err2(`Error: Memory with ID ${params.id} was not found.`);
|
|
185541
185892
|
}
|
|
185542
185893
|
deps.db.transaction(() => {
|
|
@@ -185565,7 +185916,7 @@ function createCtxMemoryTool(deps) {
|
|
|
185565
185916
|
return err2("Error: 'content' is required when action is 'update'.");
|
|
185566
185917
|
}
|
|
185567
185918
|
const memory2 = getMemoryById(deps.db, params.id);
|
|
185568
|
-
if (!memory2 || memory2.projectPath
|
|
185919
|
+
if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
|
|
185569
185920
|
return err2(`Error: Memory with ID ${params.id} was not found.`);
|
|
185570
185921
|
}
|
|
185571
185922
|
const normalizedHash = computeNormalizedHash(content);
|
|
@@ -185599,9 +185950,6 @@ function createCtxMemoryTool(deps) {
|
|
|
185599
185950
|
if (sourceMemories.length !== ids.length) {
|
|
185600
185951
|
return err2("Error: One or more source memories were not found.");
|
|
185601
185952
|
}
|
|
185602
|
-
if (sourceMemories.some((memory2) => memory2.projectPath !== projectIdentity)) {
|
|
185603
|
-
return err2("Error: All memories to merge must belong to the current project.");
|
|
185604
|
-
}
|
|
185605
185953
|
const requestedCategory = params.category?.trim();
|
|
185606
185954
|
if (requestedCategory && !isMemoryCategory2(requestedCategory)) {
|
|
185607
185955
|
return err2(`Error: Unknown memory category '${requestedCategory}'. Valid: ${CATEGORY_PRIORITY.join(", ")}`);
|
|
@@ -185660,7 +186008,7 @@ function createCtxMemoryTool(deps) {
|
|
|
185660
186008
|
}
|
|
185661
186009
|
supersededMemory(deps.db, memory2.id, canonicalMemory.id);
|
|
185662
186010
|
queueMemoryMutation(deps.db, {
|
|
185663
|
-
projectPath: memory2.projectPath,
|
|
186011
|
+
projectPath: normalizeStoredProjectPath(memory2.projectPath),
|
|
185664
186012
|
mutationType: "superseded",
|
|
185665
186013
|
targetMemoryId: memory2.id,
|
|
185666
186014
|
supersededById: canonicalMemory.id
|
|
@@ -185668,7 +186016,7 @@ function createCtxMemoryTool(deps) {
|
|
|
185668
186016
|
}
|
|
185669
186017
|
if (canonicalExisting && canonicalContentChanged) {
|
|
185670
186018
|
queueMemoryMutation(deps.db, {
|
|
185671
|
-
projectPath: canonicalMemory.projectPath,
|
|
186019
|
+
projectPath: normalizeStoredProjectPath(canonicalMemory.projectPath),
|
|
185672
186020
|
mutationType: "update",
|
|
185673
186021
|
targetMemoryId: canonicalMemory.id,
|
|
185674
186022
|
category,
|
|
@@ -185690,7 +186038,7 @@ function createCtxMemoryTool(deps) {
|
|
|
185690
186038
|
return err2("Error: 'id' is required when action is 'archive'.");
|
|
185691
186039
|
}
|
|
185692
186040
|
const memory2 = getMemoryById(deps.db, params.id);
|
|
185693
|
-
if (!memory2 || memory2.projectPath
|
|
186041
|
+
if (!memory2 || !storedPathBelongsToIdentity(memory2.projectPath, projectIdentity)) {
|
|
185694
186042
|
return err2(`Error: Memory with ID ${params.id} was not found.`);
|
|
185695
186043
|
}
|
|
185696
186044
|
deps.db.transaction(() => {
|
|
@@ -185952,7 +186300,7 @@ ${smartNotes.map(formatNoteLine).join(`
|
|
|
185952
186300
|
// ../plugin/src/features/magic-context/range-parser.ts
|
|
185953
186301
|
function parseRangeString(input) {
|
|
185954
186302
|
const maxRangeElements = 1000;
|
|
185955
|
-
const trimmed = input.trim();
|
|
186303
|
+
const trimmed = input.replace(/§/g, "").trim();
|
|
185956
186304
|
if (trimmed === "") {
|
|
185957
186305
|
throw new Error("Range string must not be empty");
|
|
185958
186306
|
}
|
|
@@ -186213,6 +186561,7 @@ function createCtxSearchTool(deps) {
|
|
|
186213
186561
|
const embeddingEnabled = snapshot ? snapshot.enabled || snapshot.gitCommitEnabled : deps.embeddingEnabled;
|
|
186214
186562
|
const gitCommitsEnabled = snapshot?.gitCommitEnabled ?? deps.gitCommitsEnabled ?? false;
|
|
186215
186563
|
const lastCompartmentEnd = getLastCompartmentEndMessage(deps.db, sessionId);
|
|
186564
|
+
const messageOrdinalCutoff = lastCompartmentEnd >= 0 ? lastCompartmentEnd : 0;
|
|
186216
186565
|
const visibleMemoryIds = getVisibleMemoryIds(deps.db, sessionId);
|
|
186217
186566
|
const results = await unifiedSearch(deps.db, sessionId, projectIdentity, query, {
|
|
186218
186567
|
limit: normalizeLimit3(params.limit),
|
|
@@ -186223,7 +186572,7 @@ function createCtxSearchTool(deps) {
|
|
|
186223
186572
|
return result?.vector ?? null;
|
|
186224
186573
|
},
|
|
186225
186574
|
isEmbeddingRuntimeEnabled: () => embeddingEnabled === true,
|
|
186226
|
-
maxMessageOrdinal:
|
|
186575
|
+
maxMessageOrdinal: messageOrdinalCutoff,
|
|
186227
186576
|
gitCommitsEnabled,
|
|
186228
186577
|
sources: params.sources,
|
|
186229
186578
|
visibleMemoryIds,
|
|
@@ -186592,6 +186941,7 @@ async function src_default2(pi) {
|
|
|
186592
186941
|
clearReasoningAge: config2.clear_reasoning_age
|
|
186593
186942
|
},
|
|
186594
186943
|
injection: {
|
|
186944
|
+
memoryEnabled: config2.memory.enabled,
|
|
186595
186945
|
injectionBudgetTokens: config2.memory.injection_budget_tokens,
|
|
186596
186946
|
temporalAwareness: config2.temporal_awareness === true,
|
|
186597
186947
|
keyFilesEnabled: config2.dreamer?.pin_key_files?.enabled ?? false,
|
|
@@ -186703,6 +187053,33 @@ async function src_default2(pi) {
|
|
|
186703
187053
|
try {
|
|
186704
187054
|
const currentProject = resolveCurrentProject(ctx);
|
|
186705
187055
|
seenDreamerProjectIdentities.add(currentProject.projectIdentity);
|
|
187056
|
+
const switchedProject = currentProject.projectDir !== projectDir;
|
|
187057
|
+
const effectiveConfig = switchedProject ? loadPiConfig({ cwd: currentProject.projectDir }).config : config2;
|
|
187058
|
+
const effectiveDreamerConfig = switchedProject ? resolveDreamerFromConfig(effectiveConfig) : dreamerConfig;
|
|
187059
|
+
if (effectiveDreamerConfig) {
|
|
187060
|
+
try {
|
|
187061
|
+
registerPiDreamerProject({
|
|
187062
|
+
db,
|
|
187063
|
+
projectDir: currentProject.projectDir,
|
|
187064
|
+
projectIdentity: currentProject.projectIdentity,
|
|
187065
|
+
config: effectiveDreamerConfig,
|
|
187066
|
+
embeddingConfig: effectiveConfig.embedding,
|
|
187067
|
+
memoryEnabled: effectiveConfig.memory.enabled,
|
|
187068
|
+
gitCommitIndexing: effectiveConfig.memory.git_commit_indexing,
|
|
187069
|
+
onAdjunctsRefreshNeeded: signalPiSystemPromptRefreshForProject
|
|
187070
|
+
});
|
|
187071
|
+
} catch (err5) {
|
|
187072
|
+
warn("before_agent_start: registerPiDreamerProject threw:", err5);
|
|
187073
|
+
}
|
|
187074
|
+
} else if (switchedProject) {
|
|
187075
|
+
try {
|
|
187076
|
+
unregisterPiDreamerProject({
|
|
187077
|
+
projectIdentity: currentProject.projectIdentity
|
|
187078
|
+
});
|
|
187079
|
+
} catch (err5) {
|
|
187080
|
+
warn("before_agent_start: unregisterPiDreamerProject threw:", err5);
|
|
187081
|
+
}
|
|
187082
|
+
}
|
|
186706
187083
|
const sm = ctx.sessionManager;
|
|
186707
187084
|
let sessionId;
|
|
186708
187085
|
if (sm !== undefined) {
|