@cortexkit/pi-magic-context 0.44.0 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-tfzybajk.js → index-59dmj4zs.js} +4 -1
- package/dist/{index-jscq7067.js → index-5fw91enm.js} +1 -1
- package/dist/{index-mmkdxa5j.js → index-97e5fzy3.js} +1 -1
- package/dist/{index-8ytss1hp.js → index-mwpk0wn9.js} +439 -277
- package/dist/{index-2kj55q4e.js → index-nm3c0sn8.js} +105 -13
- package/dist/index.js +631 -447
- package/dist/{message-time-backfill-3rp0w2z9.js → message-time-backfill-5yrp95cx.js} +2 -2
- package/dist/{read-session-chunk-2s116ah5.js → read-session-chunk-ka7n4kah.js} +4 -2
- package/dist/{safe-notification-target-pd09ybr0.js → safe-notification-target-y3hg2m7p.js} +2 -2
- package/dist/subagent-entry.js +6 -6
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
setHarness,
|
|
3
3
|
getHarness,
|
|
4
|
+
harnessOwnsOpenCodeStore,
|
|
4
5
|
ensureCortexKitArtifactGitignore,
|
|
5
6
|
getProjectMagicContextHistorianDir,
|
|
6
7
|
getMagicContextStorageDir,
|
|
@@ -9,7 +10,7 @@ import {
|
|
|
9
10
|
log,
|
|
10
11
|
sessionLog,
|
|
11
12
|
flushLogger
|
|
12
|
-
} from "./index-
|
|
13
|
+
} from "./index-59dmj4zs.js";
|
|
13
14
|
import {
|
|
14
15
|
COMPACTION_ENABLED_PATH,
|
|
15
16
|
isDreamerRunnable,
|
|
@@ -43,12 +44,10 @@ import {
|
|
|
43
44
|
cortexKitProjectConfigBasePath,
|
|
44
45
|
migrateMagicContextConfigLocations,
|
|
45
46
|
withContentLanguageDirective,
|
|
46
|
-
buildPrimaryLanguageDirective,
|
|
47
47
|
parseCron,
|
|
48
48
|
nextOccurrence,
|
|
49
49
|
nextDueAtMs,
|
|
50
50
|
resolveModelConfigValue,
|
|
51
|
-
resolveModelConfigOrDefault,
|
|
52
51
|
DEFAULT_HISTORIAN_TIMEOUT_MS,
|
|
53
52
|
LIVE_RELOAD_CONFIG_PATHS,
|
|
54
53
|
getProtectedTokensTierOverrides,
|
|
@@ -61,6 +60,7 @@ import {
|
|
|
61
60
|
ProjectIdentityError,
|
|
62
61
|
resolveProjectIdentityStrict,
|
|
63
62
|
resolveProjectIdentity,
|
|
63
|
+
isUsableProjectIdentity,
|
|
64
64
|
resolveProjectIdentityForSession,
|
|
65
65
|
beginBootQuietPeriod,
|
|
66
66
|
scheduleAfterBootQuiet,
|
|
@@ -74,42 +74,6 @@ import {
|
|
|
74
74
|
indexSingleMessage,
|
|
75
75
|
indexMessagesAfterOrdinal,
|
|
76
76
|
sweepOrphanedOpenCodeMessageIndexes,
|
|
77
|
-
recordSessionProjectIdentity,
|
|
78
|
-
piHarnessKindFromExecutable,
|
|
79
|
-
COMPARTMENT_LEASE_RENEWAL_MS,
|
|
80
|
-
acquireCompartmentLease,
|
|
81
|
-
renewCompartmentLease,
|
|
82
|
-
releaseCompartmentLease,
|
|
83
|
-
releaseCompartmentLeaseBestEffort,
|
|
84
|
-
isCompartmentLeaseHeld,
|
|
85
|
-
isNoContentCompartment,
|
|
86
|
-
HAS_COMPARTMENT_CONTENT_SQL,
|
|
87
|
-
persistCachedM0,
|
|
88
|
-
clearCachedM0M1,
|
|
89
|
-
getCompartments,
|
|
90
|
-
getLastCompartmentEndMessage,
|
|
91
|
-
getLastCompartmentEndMessageId,
|
|
92
|
-
getCompartmentsByEndMessageId,
|
|
93
|
-
appendCompartments,
|
|
94
|
-
saveRecompStagingPass,
|
|
95
|
-
getRecompStaging,
|
|
96
|
-
clearRecompStaging,
|
|
97
|
-
getRecompPartialRange,
|
|
98
|
-
setRecompPartialRange,
|
|
99
|
-
escapeXmlAttr,
|
|
100
|
-
escapeXmlContent,
|
|
101
|
-
getModuleNoteEvaluationBridge,
|
|
102
|
-
getContextStoreUuid,
|
|
103
|
-
getAuthorityManagedMarker,
|
|
104
|
-
drainMirrorPages,
|
|
105
|
-
V2_MEMORY_CATEGORIES,
|
|
106
|
-
parseCompartmentOutput,
|
|
107
|
-
resolveWorkspaceShareCategories,
|
|
108
|
-
resolveWorkspaceIdentitySet,
|
|
109
|
-
expandWorkspaceIdentitySetWithAliases,
|
|
110
|
-
sourceNameForMemory,
|
|
111
|
-
computeWorkspaceEpochFingerprint,
|
|
112
|
-
readProjectDocsCanonical,
|
|
113
77
|
MAX_EXECUTE_THRESHOLD,
|
|
114
78
|
escalationBands,
|
|
115
79
|
HYGIENE_PROVIDER_UNITS_VERSION,
|
|
@@ -118,6 +82,10 @@ import {
|
|
|
118
82
|
computeProtectionWindow,
|
|
119
83
|
readEpochFloorSnapshot,
|
|
120
84
|
getProtectionWindowForSession,
|
|
85
|
+
persistCachedM0,
|
|
86
|
+
clearCachedM0M1,
|
|
87
|
+
readReplayDocument,
|
|
88
|
+
updateReplayDocument,
|
|
121
89
|
isProviderOverflowFailClosedProven,
|
|
122
90
|
describeProtectedTailDrainBudgetSkip,
|
|
123
91
|
loadProtectedTailMeta,
|
|
@@ -194,6 +162,45 @@ import {
|
|
|
194
162
|
setSessionWorkMetrics,
|
|
195
163
|
getSessionWorkMetrics,
|
|
196
164
|
resolveEpochFloorForPass,
|
|
165
|
+
getOrCreateSessionMeta,
|
|
166
|
+
updateSessionMeta,
|
|
167
|
+
advanceToolReclaimWatermark,
|
|
168
|
+
retryPendingSessionCleanups,
|
|
169
|
+
retryPendingRustSessionCleanupsForProject,
|
|
170
|
+
recordSessionProjectIdentity,
|
|
171
|
+
piHarnessKindFromExecutable,
|
|
172
|
+
COMPARTMENT_LEASE_RENEWAL_MS,
|
|
173
|
+
acquireCompartmentLease,
|
|
174
|
+
renewCompartmentLease,
|
|
175
|
+
releaseCompartmentLease,
|
|
176
|
+
releaseCompartmentLeaseBestEffort,
|
|
177
|
+
isCompartmentLeaseHeld,
|
|
178
|
+
isNoContentCompartment,
|
|
179
|
+
HAS_COMPARTMENT_CONTENT_SQL,
|
|
180
|
+
getCompartments,
|
|
181
|
+
getLastCompartmentEndMessage,
|
|
182
|
+
getLastCompartmentEndMessageId,
|
|
183
|
+
getCompartmentsByEndMessageId,
|
|
184
|
+
appendCompartments,
|
|
185
|
+
saveRecompStagingPass,
|
|
186
|
+
getRecompStaging,
|
|
187
|
+
clearRecompStaging,
|
|
188
|
+
getRecompPartialRange,
|
|
189
|
+
setRecompPartialRange,
|
|
190
|
+
escapeXmlAttr,
|
|
191
|
+
escapeXmlContent,
|
|
192
|
+
getModuleNoteEvaluationBridge,
|
|
193
|
+
getContextStoreUuid,
|
|
194
|
+
getAuthorityManagedMarker,
|
|
195
|
+
drainMirrorPages,
|
|
196
|
+
V2_MEMORY_CATEGORIES,
|
|
197
|
+
parseCompartmentOutput,
|
|
198
|
+
resolveWorkspaceShareCategories,
|
|
199
|
+
resolveWorkspaceIdentitySet,
|
|
200
|
+
expandWorkspaceIdentitySetWithAliases,
|
|
201
|
+
sourceNameForMemory,
|
|
202
|
+
computeWorkspaceEpochFingerprint,
|
|
203
|
+
readProjectDocsCanonical,
|
|
197
204
|
BoundedSessionMap,
|
|
198
205
|
registerLkgPersistence,
|
|
199
206
|
signatureForFields,
|
|
@@ -231,11 +238,6 @@ import {
|
|
|
231
238
|
getMemoryMutationsForRenderByProjects,
|
|
232
239
|
getMaxMemoryMutationId,
|
|
233
240
|
getMaxMemoryMutationIdForProjects,
|
|
234
|
-
getOrCreateSessionMeta,
|
|
235
|
-
updateSessionMeta,
|
|
236
|
-
advanceToolReclaimWatermark,
|
|
237
|
-
retryPendingSessionCleanups,
|
|
238
|
-
retryPendingRustSessionCleanupsForProject,
|
|
239
241
|
getNotes,
|
|
240
242
|
getSessionNotes,
|
|
241
243
|
getPendingSmartNotes,
|
|
@@ -374,6 +376,8 @@ import {
|
|
|
374
376
|
ensureProjectRegisteredFromPiDirectory,
|
|
375
377
|
resolvePiHarnessDetection,
|
|
376
378
|
resolvePiHarnessKind,
|
|
379
|
+
MEMORY_MURAL_BLOCK,
|
|
380
|
+
buildMagicContextSection,
|
|
377
381
|
resolveMuralWire,
|
|
378
382
|
updateCompactionMarkerAfterPublication,
|
|
379
383
|
COMPARTMENT_RENDER_EPOCH,
|
|
@@ -404,7 +408,7 @@ import {
|
|
|
404
408
|
registerTodoStateLifecycle,
|
|
405
409
|
syncCtxMemoryToolEnabled,
|
|
406
410
|
registerMagicContextTools
|
|
407
|
-
} from "./index-
|
|
411
|
+
} from "./index-mwpk0wn9.js";
|
|
408
412
|
import {
|
|
409
413
|
CTX_REDUCE_KEEP,
|
|
410
414
|
newestCtxReduceTagNumbers,
|
|
@@ -483,6 +487,7 @@ import {
|
|
|
483
487
|
claimOpenCodeDbDiagnosticOnce,
|
|
484
488
|
Database,
|
|
485
489
|
closeQuietly,
|
|
490
|
+
RAW_SUMMARY_TEXT_MAX_CHARS,
|
|
486
491
|
completedToolArcCrossesBoundary,
|
|
487
492
|
estimateTrueRawMessageTokens,
|
|
488
493
|
buildToolArcs,
|
|
@@ -507,6 +512,7 @@ import {
|
|
|
507
512
|
withRawSessionMessageCache2,
|
|
508
513
|
readRawSessionMessages2,
|
|
509
514
|
getRawSessionMessageOrdinalCount2,
|
|
515
|
+
visitRawSessionMessages2,
|
|
510
516
|
readRawSessionMessageRange2,
|
|
511
517
|
primeTailRawMessageCache2,
|
|
512
518
|
getCachedAbsoluteMessageCount2,
|
|
@@ -516,14 +522,14 @@ import {
|
|
|
516
522
|
getRawSessionTagKeysThrough2,
|
|
517
523
|
getLegacyProtectedTailStartOrdinal2,
|
|
518
524
|
readSessionChunk2
|
|
519
|
-
} from "./index-
|
|
525
|
+
} from "./index-nm3c0sn8.js";
|
|
520
526
|
import {
|
|
521
527
|
pushNotification2
|
|
522
528
|
} from "./index-b3eqj1g6.js";
|
|
523
|
-
import"./index-
|
|
529
|
+
import"./index-5fw91enm.js";
|
|
524
530
|
import {
|
|
525
531
|
logSlowWriteTransaction
|
|
526
|
-
} from "./index-
|
|
532
|
+
} from "./index-97e5fzy3.js";
|
|
527
533
|
import {
|
|
528
534
|
__toESM
|
|
529
535
|
} from "./index-22jkk6wg.js";
|
|
@@ -531,7 +537,7 @@ import {
|
|
|
531
537
|
// src/index.ts
|
|
532
538
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
533
539
|
import { createRequire as createRequire2 } from "node:module";
|
|
534
|
-
import { join as
|
|
540
|
+
import { join as join11, resolve as resolve4 } from "node:path";
|
|
535
541
|
|
|
536
542
|
// ../plugin/src/config/live-snapshot.ts
|
|
537
543
|
import { createHash } from "node:crypto";
|
|
@@ -1319,6 +1325,67 @@ function parseReportedLimit(message) {
|
|
|
1319
1325
|
return;
|
|
1320
1326
|
}
|
|
1321
1327
|
|
|
1328
|
+
// ../plugin/src/shared/model-cache-ttl.ts
|
|
1329
|
+
var MODEL_CACHE_LIFETIMES = [
|
|
1330
|
+
{
|
|
1331
|
+
source: "OpenAI GPT-5.6+ default",
|
|
1332
|
+
value: "30m",
|
|
1333
|
+
matches(model) {
|
|
1334
|
+
const version = /^gpt-(\d+)(?:\.(\d+))?(?:$|[^\d.])/.exec(model);
|
|
1335
|
+
if (!version)
|
|
1336
|
+
return false;
|
|
1337
|
+
const major = Number(version[1]);
|
|
1338
|
+
const minor = Number(version[2] ?? 0);
|
|
1339
|
+
return major > 5 || major === 5 && minor >= 6;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
];
|
|
1343
|
+
function resolveModelCacheTtl(config, modelKey) {
|
|
1344
|
+
if (config && typeof config !== "string") {
|
|
1345
|
+
const match = modelKey && !modelKey.includes("/") && Object.hasOwn(config, modelKey) && modelKey !== "default" ? config[modelKey] : resolveModelConfigValue(config, modelKey)?.value;
|
|
1346
|
+
if (match !== undefined)
|
|
1347
|
+
return { value: match, source: "config", modelKey };
|
|
1348
|
+
}
|
|
1349
|
+
if (typeof config === "string" && config !== "5m")
|
|
1350
|
+
return { value: config, source: "config", modelKey };
|
|
1351
|
+
const model = canonicalModelIdentity(modelKey ?? "").toLowerCase().split("/").at(-1) ?? "";
|
|
1352
|
+
const known = MODEL_CACHE_LIFETIMES.find((entry) => entry.matches(model));
|
|
1353
|
+
if (known)
|
|
1354
|
+
return { value: known.value, source: known.source, modelKey };
|
|
1355
|
+
return {
|
|
1356
|
+
value: (typeof config === "object" ? config.default : config) ?? "5m",
|
|
1357
|
+
source: "default",
|
|
1358
|
+
modelKey
|
|
1359
|
+
};
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
// ../plugin/src/features/magic-context/session-cache-ttl.ts
|
|
1363
|
+
function readSessionCacheTtl(db, sessionId) {
|
|
1364
|
+
const saved = readReplayDocument(db, sessionId).cacheTtlPolicy;
|
|
1365
|
+
return saved && typeof saved.value === "string" && saved.config !== undefined ? saved : undefined;
|
|
1366
|
+
}
|
|
1367
|
+
function resolveSessionCacheTtl(db, sessionId, config, modelKey) {
|
|
1368
|
+
const meta = getOrCreateSessionMeta(db, sessionId);
|
|
1369
|
+
let saved = readSessionCacheTtl(db, sessionId);
|
|
1370
|
+
if (!modelKey)
|
|
1371
|
+
return saved ?? resolveModelCacheTtl(config ?? meta.cacheTtl, undefined);
|
|
1372
|
+
if (!saved || saved.modelKey !== modelKey) {
|
|
1373
|
+
const frozenConfig = saved?.config ?? config ?? meta.cacheTtl;
|
|
1374
|
+
const resolved = resolveModelCacheTtl(frozenConfig, modelKey);
|
|
1375
|
+
const next = { ...resolved, config: frozenConfig };
|
|
1376
|
+
if (!updateReplayDocument(db, sessionId, (doc) => {
|
|
1377
|
+
doc.version = 2;
|
|
1378
|
+
doc.cacheTtlPolicy = next;
|
|
1379
|
+
return true;
|
|
1380
|
+
}))
|
|
1381
|
+
throw new Error("cannot persist session cache TTL policy");
|
|
1382
|
+
saved = next;
|
|
1383
|
+
}
|
|
1384
|
+
if (meta.cacheTtl !== saved.value)
|
|
1385
|
+
updateSessionMeta(db, sessionId, { cacheTtl: saved.value });
|
|
1386
|
+
return saved;
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1322
1389
|
// ../plugin/src/features/magic-context/session-project-backfill.ts
|
|
1323
1390
|
import { randomUUID } from "node:crypto";
|
|
1324
1391
|
import { existsSync } from "node:fs";
|
|
@@ -1896,141 +1963,6 @@ function producerSourceLocalBudget(providerTokens, modelKey) {
|
|
|
1896
1963
|
return ratio === 1 ? providerTokens : localBudget(providerTokens, ratio);
|
|
1897
1964
|
}
|
|
1898
1965
|
|
|
1899
|
-
// ../plugin/src/hooks/magic-context/event-resolvers.ts
|
|
1900
|
-
var DEFAULT_CONTEXT_LIMIT = 200000;
|
|
1901
|
-
function resolveCacheTtl(cacheTtl, modelKey) {
|
|
1902
|
-
if (typeof cacheTtl === "string") {
|
|
1903
|
-
return cacheTtl;
|
|
1904
|
-
}
|
|
1905
|
-
return resolveModelConfigOrDefault(cacheTtl, modelKey, cacheTtl.default ?? "5m");
|
|
1906
|
-
}
|
|
1907
|
-
var clampWarnSeen = new Set;
|
|
1908
|
-
function isFinitePositive(v) {
|
|
1909
|
-
return typeof v === "number" && Number.isFinite(v) && v > 0;
|
|
1910
|
-
}
|
|
1911
|
-
function* modelKeyLookupOrder(modelKey) {
|
|
1912
|
-
const slash = modelKey.indexOf("/");
|
|
1913
|
-
const providerRefs = slash >= 0 ? modelRefLookupOrder(modelKey) : [];
|
|
1914
|
-
let modelId = slash >= 0 ? modelKey.slice(slash + 1) : modelKey;
|
|
1915
|
-
while (modelId.length > 0) {
|
|
1916
|
-
for (const providerRef of providerRefs) {
|
|
1917
|
-
const providerSlash = providerRef.indexOf("/");
|
|
1918
|
-
yield `${providerRef.slice(0, providerSlash)}/${modelId}`;
|
|
1919
|
-
}
|
|
1920
|
-
yield modelId;
|
|
1921
|
-
const lastDash = modelId.lastIndexOf("-");
|
|
1922
|
-
if (lastDash <= 0)
|
|
1923
|
-
break;
|
|
1924
|
-
modelId = modelId.slice(0, lastDash);
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1927
|
-
function resolveExecuteThresholdDetail(config, modelKey, fallback, options) {
|
|
1928
|
-
if (options?.tokensConfig && isFinitePositive(options.contextLimit)) {
|
|
1929
|
-
const contextLimit = options.contextLimit;
|
|
1930
|
-
const tokenMatch = resolveTokensMatchWithKey(options.tokensConfig, modelKey);
|
|
1931
|
-
if (tokenMatch && isFinitePositive(tokenMatch.value)) {
|
|
1932
|
-
const cap = contextLimit * (MAX_EXECUTE_THRESHOLD / 100);
|
|
1933
|
-
const effectiveTokens = Math.min(tokenMatch.value, cap);
|
|
1934
|
-
if (effectiveTokens < tokenMatch.value) {
|
|
1935
|
-
const dedupeKey = `${options.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${tokenMatch.value}|${cap}`;
|
|
1936
|
-
if (!clampWarnSeen.has(dedupeKey)) {
|
|
1937
|
-
clampWarnSeen.add(dedupeKey);
|
|
1938
|
-
const msg = `execute_threshold_tokens clamped: ${tokenMatch.value} → ${effectiveTokens} (${MAX_EXECUTE_THRESHOLD}% of ${contextLimit}) for ${modelKey ?? "default"}`;
|
|
1939
|
-
if (options.sessionId) {
|
|
1940
|
-
sessionLog(options.sessionId, `WARN: ${msg}`);
|
|
1941
|
-
} else {
|
|
1942
|
-
log(`[magic-context] WARN: ${msg}`);
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
|
-
}
|
|
1946
|
-
const percentage = effectiveTokens / contextLimit * 100;
|
|
1947
|
-
const detail = {
|
|
1948
|
-
percentage: Math.min(percentage, MAX_EXECUTE_THRESHOLD),
|
|
1949
|
-
mode: "tokens",
|
|
1950
|
-
absoluteTokens: Math.floor(effectiveTokens),
|
|
1951
|
-
matchedKey: tokenMatch.matchedKey
|
|
1952
|
-
};
|
|
1953
|
-
if (effectiveTokens < tokenMatch.value) {
|
|
1954
|
-
detail.clamped = true;
|
|
1955
|
-
detail.configuredValue = tokenMatch.value;
|
|
1956
|
-
}
|
|
1957
|
-
return detail;
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
let resolved;
|
|
1961
|
-
let matchedKey;
|
|
1962
|
-
if (typeof config === "number") {
|
|
1963
|
-
resolved = config;
|
|
1964
|
-
} else if (modelKey) {
|
|
1965
|
-
let matched;
|
|
1966
|
-
for (const candidate of modelKeyLookupOrder(modelKey)) {
|
|
1967
|
-
if (typeof config[candidate] === "number") {
|
|
1968
|
-
matched = config[candidate];
|
|
1969
|
-
matchedKey = candidate;
|
|
1970
|
-
break;
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
if (matched === undefined && typeof config.default === "number") {
|
|
1974
|
-
resolved = config.default;
|
|
1975
|
-
matchedKey = "default";
|
|
1976
|
-
} else {
|
|
1977
|
-
resolved = matched ?? fallback;
|
|
1978
|
-
}
|
|
1979
|
-
} else if (typeof config.default === "number") {
|
|
1980
|
-
resolved = config.default;
|
|
1981
|
-
matchedKey = "default";
|
|
1982
|
-
} else {
|
|
1983
|
-
resolved = fallback;
|
|
1984
|
-
}
|
|
1985
|
-
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
1986
|
-
resolved = fallback;
|
|
1987
|
-
}
|
|
1988
|
-
const cappedPercentage = Math.min(resolved, MAX_EXECUTE_THRESHOLD);
|
|
1989
|
-
const percentageClamped = cappedPercentage < resolved;
|
|
1990
|
-
if (percentageClamped) {
|
|
1991
|
-
const dedupeKey = `pct|${options?.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${resolved}`;
|
|
1992
|
-
if (!clampWarnSeen.has(dedupeKey)) {
|
|
1993
|
-
clampWarnSeen.add(dedupeKey);
|
|
1994
|
-
const msg = `execute_threshold clamped ${resolved}% → ${MAX_EXECUTE_THRESHOLD}% for ${modelKey ?? "default"} (capped against the output-reserved safe window; 10% remains for mid-turn growth before the absolute 95% wall)`;
|
|
1995
|
-
if (options?.sessionId) {
|
|
1996
|
-
sessionLog(options.sessionId, `WARN: ${msg}`);
|
|
1997
|
-
} else {
|
|
1998
|
-
log(`[magic-context] WARN: ${msg}`);
|
|
1999
|
-
}
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2002
|
-
const detail = {
|
|
2003
|
-
percentage: cappedPercentage,
|
|
2004
|
-
mode: "percentage",
|
|
2005
|
-
matchedKey
|
|
2006
|
-
};
|
|
2007
|
-
if (percentageClamped) {
|
|
2008
|
-
detail.clamped = true;
|
|
2009
|
-
detail.configuredValue = resolved;
|
|
2010
|
-
}
|
|
2011
|
-
return detail;
|
|
2012
|
-
}
|
|
2013
|
-
function resolveExecuteThreshold(config, modelKey, fallback, options) {
|
|
2014
|
-
return resolveExecuteThresholdDetail(config, modelKey, fallback, options).percentage;
|
|
2015
|
-
}
|
|
2016
|
-
function resolveTokensMatchWithKey(tokensConfig, modelKey) {
|
|
2017
|
-
if (!tokensConfig) {
|
|
2018
|
-
return;
|
|
2019
|
-
}
|
|
2020
|
-
if (modelKey) {
|
|
2021
|
-
for (const candidate of modelKeyLookupOrder(modelKey)) {
|
|
2022
|
-
const value = tokensConfig[candidate];
|
|
2023
|
-
if (typeof value === "number") {
|
|
2024
|
-
return { value, matchedKey: candidate };
|
|
2025
|
-
}
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
if (typeof tokensConfig.default === "number") {
|
|
2029
|
-
return { value: tokensConfig.default, matchedKey: "default" };
|
|
2030
|
-
}
|
|
2031
|
-
return;
|
|
2032
|
-
}
|
|
2033
|
-
|
|
2034
1966
|
// ../plugin/src/hooks/magic-context/note-nudger.ts
|
|
2035
1967
|
var NOTE_NUDGE_COOLDOWN_MS = 15 * 60 * 1000;
|
|
2036
1968
|
var lastDeliveredAt = new Map;
|
|
@@ -3078,6 +3010,8 @@ import { parse, resolve as resolve3 } from "node:path";
|
|
|
3078
3010
|
|
|
3079
3011
|
// ../plugin/src/features/magic-context/dreamer/open-opencode-db.ts
|
|
3080
3012
|
function openOpenCodeDb() {
|
|
3013
|
+
if (!harnessOwnsOpenCodeStore())
|
|
3014
|
+
return null;
|
|
3081
3015
|
const resolution = resolveOpenCodeDbPath();
|
|
3082
3016
|
const dbPath = resolution.path;
|
|
3083
3017
|
if (!openCodeDbPathExists(resolution)) {
|
|
@@ -4007,6 +3941,15 @@ var HISTORIAN_AGENT = "historian";
|
|
|
4007
3941
|
var HISTORIAN_RECOMP_AGENT = "historian-recomp";
|
|
4008
3942
|
var HISTORIAN_EDITOR_AGENT = "historian-editor";
|
|
4009
3943
|
|
|
3944
|
+
// ../plugin/src/config/live-child-output-cap.ts
|
|
3945
|
+
var historianCaps = new BoundedSessionMap(4096);
|
|
3946
|
+
function rememberHistorianOutputCap(sessionId, cap) {
|
|
3947
|
+
historianCaps.set(sessionId, { value: cap });
|
|
3948
|
+
}
|
|
3949
|
+
function forgetHistorianOutputCap(sessionId) {
|
|
3950
|
+
historianCaps.delete(sessionId);
|
|
3951
|
+
}
|
|
3952
|
+
|
|
4010
3953
|
// ../plugin/src/features/magic-context/subagent-token-capture.ts
|
|
4011
3954
|
function asNumber(value) {
|
|
4012
3955
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
@@ -5423,6 +5366,8 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
|
5423
5366
|
const id = typeof created?.id === "string" ? created.id : "";
|
|
5424
5367
|
if (id && run.kind === "dreamer-task")
|
|
5425
5368
|
asyncChildren.add(id);
|
|
5369
|
+
if (id && run.kind !== "dreamer-task")
|
|
5370
|
+
rememberHistorianOutputCap(id, run.maxOutputTokens);
|
|
5426
5371
|
return { id, childSessionId: id || undefined };
|
|
5427
5372
|
},
|
|
5428
5373
|
async attempt(handle, request) {
|
|
@@ -5459,8 +5404,10 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
|
5459
5404
|
};
|
|
5460
5405
|
},
|
|
5461
5406
|
async close(handle, settlement) {
|
|
5462
|
-
if (handle?.id)
|
|
5407
|
+
if (handle?.id) {
|
|
5463
5408
|
asyncChildren.delete(handle.id);
|
|
5409
|
+
forgetHistorianOutputCap(handle.id);
|
|
5410
|
+
}
|
|
5464
5411
|
if (!client)
|
|
5465
5412
|
return;
|
|
5466
5413
|
await teardownChildSession({
|
|
@@ -10603,12 +10550,12 @@ async function promotePrimers(args) {
|
|
|
10603
10550
|
|
|
10604
10551
|
// ../plugin/src/features/magic-context/dreamer/primer-seed.ts
|
|
10605
10552
|
var PRIMER_SEED_CAP_TOKENS = 4000;
|
|
10606
|
-
function renderUserAndToolOrientation(
|
|
10553
|
+
function renderUserAndToolOrientation(sessionId, startOrdinal, endOrdinal, capTokens) {
|
|
10607
10554
|
const lines = [];
|
|
10608
10555
|
let tokens = 0;
|
|
10609
|
-
|
|
10610
|
-
|
|
10611
|
-
|
|
10556
|
+
let sawMessage = false;
|
|
10557
|
+
visitRawSessionMessages2(sessionId, startOrdinal, endOrdinal, (msg) => {
|
|
10558
|
+
sawMessage = true;
|
|
10612
10559
|
const out = [];
|
|
10613
10560
|
if (msg.role === "user" && hasMeaningfulUserText2(msg.parts)) {
|
|
10614
10561
|
const text = extractTexts2(msg.parts).map((t) => cleanUserText2(t)).map(normalizeText).filter((t) => t.length > 0).join(" / ");
|
|
@@ -10621,22 +10568,27 @@ function renderUserAndToolOrientation(messages, startOrdinal, endOrdinal, capTok
|
|
|
10621
10568
|
const lineTokens = estimateTokens(line);
|
|
10622
10569
|
if (tokens + lineTokens > capTokens && lines.length > 0) {
|
|
10623
10570
|
lines.push("… (orientation truncated; investigate the current source directly)");
|
|
10624
|
-
return
|
|
10625
|
-
`);
|
|
10571
|
+
return false;
|
|
10626
10572
|
}
|
|
10627
10573
|
lines.push(line);
|
|
10628
10574
|
tokens += lineTokens;
|
|
10629
10575
|
}
|
|
10630
|
-
|
|
10631
|
-
|
|
10632
|
-
`
|
|
10576
|
+
return true;
|
|
10577
|
+
}, { summary: true });
|
|
10578
|
+
return sawMessage ? lines.join(`
|
|
10579
|
+
`) : null;
|
|
10580
|
+
}
|
|
10581
|
+
function selectPrimerOriginCandidate(db, primer) {
|
|
10582
|
+
return getPrimerCandidatesByIds(db, primer.sourceCandidateIds).filter((candidate) => candidate.projectPath === primer.projectPath).sort((a, b) => b.sourceMessageTime - a.sourceMessageTime || b.id - a.id)[0];
|
|
10633
10583
|
}
|
|
10634
10584
|
function loadPrePostP1(db, sessionId, originStartMessage) {
|
|
10635
10585
|
const origin = db.prepare("SELECT sequence FROM compartments WHERE session_id = ? AND start_message = ? ORDER BY sequence ASC LIMIT 1").get(sessionId, originStartMessage);
|
|
10636
10586
|
if (typeof origin?.sequence !== "number")
|
|
10637
10587
|
return "";
|
|
10638
10588
|
const originSeq = origin.sequence;
|
|
10639
|
-
const rows = db.prepare(`SELECT sequence, start_message, end_message,
|
|
10589
|
+
const rows = db.prepare(`SELECT sequence, start_message, end_message,
|
|
10590
|
+
substr(title, 1, 512) AS title,
|
|
10591
|
+
substr(p1, 1, 1200) AS p1, substr(content, 1, 1200) AS content
|
|
10640
10592
|
FROM compartments
|
|
10641
10593
|
WHERE session_id = ? AND sequence IN (?, ?)
|
|
10642
10594
|
ORDER BY sequence ASC`).all(sessionId, originSeq - 1, originSeq + 1);
|
|
@@ -10650,28 +10602,28 @@ function loadPrePostP1(db, sessionId, originStartMessage) {
|
|
|
10650
10602
|
`);
|
|
10651
10603
|
}
|
|
10652
10604
|
function closedBookOriginP1(db, sessionId, originStartMessage) {
|
|
10653
|
-
const row = db.prepare(
|
|
10605
|
+
const row = db.prepare(`SELECT substr(title, 1, 512) AS title,
|
|
10606
|
+
substr(p1, 1, 2000) AS p1, substr(content, 1, 2000) AS content
|
|
10607
|
+
FROM compartments WHERE session_id = ? AND start_message = ? ORDER BY sequence ASC LIMIT 1`).get(sessionId, originStartMessage);
|
|
10654
10608
|
const body = (row?.p1 ?? row?.content ?? "").slice(0, 2000);
|
|
10655
10609
|
const orientation = row?.title ? `${row.title}: ${body}` : body;
|
|
10656
10610
|
return { orientation, sessionId };
|
|
10657
10611
|
}
|
|
10658
10612
|
function buildPrimerSeed(db, primer) {
|
|
10659
|
-
const
|
|
10660
|
-
const mostRecent = candidates.slice().sort((a, b) => b.sourceMessageTime - a.sourceMessageTime || b.id - a.id)[0];
|
|
10613
|
+
const mostRecent = selectPrimerOriginCandidate(db, primer);
|
|
10661
10614
|
if (!mostRecent || typeof mostRecent.sourceCompartmentStart !== "number" || typeof mostRecent.sourceCompartmentEnd !== "number") {
|
|
10662
10615
|
return { kind: "closed-book", orientation: "", prePost: "", sessionId: null };
|
|
10663
10616
|
}
|
|
10664
10617
|
const sessionId = mostRecent.sessionId;
|
|
10665
10618
|
const start = mostRecent.sourceCompartmentStart;
|
|
10666
10619
|
const end = mostRecent.sourceCompartmentEnd;
|
|
10667
|
-
let
|
|
10620
|
+
let orientation = null;
|
|
10668
10621
|
try {
|
|
10669
|
-
|
|
10622
|
+
orientation = renderUserAndToolOrientation(sessionId, start, end, PRIMER_SEED_CAP_TOKENS);
|
|
10670
10623
|
} catch {
|
|
10671
|
-
|
|
10624
|
+
orientation = null;
|
|
10672
10625
|
}
|
|
10673
|
-
|
|
10674
|
-
if (!inRange) {
|
|
10626
|
+
if (orientation === null) {
|
|
10675
10627
|
const closed = closedBookOriginP1(db, sessionId, start);
|
|
10676
10628
|
return {
|
|
10677
10629
|
kind: "closed-book",
|
|
@@ -10680,7 +10632,6 @@ function buildPrimerSeed(db, primer) {
|
|
|
10680
10632
|
sessionId
|
|
10681
10633
|
};
|
|
10682
10634
|
}
|
|
10683
|
-
const orientation = renderUserAndToolOrientation(raw, start, end, PRIMER_SEED_CAP_TOKENS);
|
|
10684
10635
|
return {
|
|
10685
10636
|
kind: "raw",
|
|
10686
10637
|
orientation,
|
|
@@ -10914,9 +10865,7 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
|
|
|
10914
10865
|
}
|
|
10915
10866
|
}
|
|
10916
10867
|
function originSessionIdForPrimer(args, primer) {
|
|
10917
|
-
|
|
10918
|
-
const mostRecent = candidates.slice().sort((a, b) => b.sourceMessageTime - a.sourceMessageTime || b.id - a.id)[0];
|
|
10919
|
-
return mostRecent?.sessionId ?? null;
|
|
10868
|
+
return selectPrimerOriginCandidate(args.db, primer)?.sessionId ?? null;
|
|
10920
10869
|
}
|
|
10921
10870
|
function recordInvocation3(args, startedAt, params) {
|
|
10922
10871
|
if (!args.parentSessionId)
|
|
@@ -11314,11 +11263,48 @@ function normalizeOpenCodeRows(db, sessionId, rows) {
|
|
|
11314
11263
|
return [];
|
|
11315
11264
|
const messageIds = rows.map((row) => row.id);
|
|
11316
11265
|
const placeholders = messageIds.map(() => "?").join(", ");
|
|
11317
|
-
const
|
|
11266
|
+
const userIds = rows.filter((row) => parseJsonRecord(row.data)?.role === "user").map((row) => row.id);
|
|
11267
|
+
const userPlaceholders = userIds.map(() => "?").join(", ") || "NULL";
|
|
11268
|
+
const output = `CASE json_type(data, '$.state.output')
|
|
11269
|
+
WHEN 'text' THEN json_extract(data, '$.state.output')
|
|
11270
|
+
WHEN 'null' THEN '' ELSE COALESCE(data -> '$.state.output', '') END`;
|
|
11271
|
+
const error = `CASE json_type(data, '$.state.error')
|
|
11272
|
+
WHEN 'text' THEN json_extract(data, '$.state.error')
|
|
11273
|
+
WHEN 'null' THEN '' ELSE COALESCE(data -> '$.state.error', '') END`;
|
|
11274
|
+
const containsError = (value) => ["error", "failed", "exception", "traceback"].map((word) => `(' ' || lower(${value}) || ' ') GLOB '*[^a-z0-9_]${word}[^a-z0-9_]*'`).join(" OR ");
|
|
11275
|
+
const errorWords = `CASE WHEN json_type(data, '$.state.output') IN ('object', 'array')
|
|
11276
|
+
THEN EXISTS (SELECT 1 FROM json_tree(data, '$.state.output') AS leaf
|
|
11277
|
+
WHERE (leaf.type = 'text' AND (${containsError("json_quote(leaf.atom)")}))
|
|
11278
|
+
OR (typeof(leaf.key) = 'text' AND (${containsError("json_quote(leaf.key)")})))
|
|
11279
|
+
WHEN instr(CAST(${output} AS BLOB), x'00') > 0 THEN EXISTS (
|
|
11280
|
+
WITH RECURSIVE segments(rest, piece) AS (
|
|
11281
|
+
SELECT CAST(${output} AS BLOB), x''
|
|
11282
|
+
UNION ALL
|
|
11283
|
+
SELECT CASE WHEN instr(rest, x'00') > 0
|
|
11284
|
+
THEN substr(rest, instr(rest, x'00') + 1) ELSE NULL END,
|
|
11285
|
+
CASE WHEN instr(rest, x'00') > 0
|
|
11286
|
+
THEN substr(rest, 1, instr(rest, x'00') - 1) ELSE rest END
|
|
11287
|
+
FROM segments WHERE rest IS NOT NULL
|
|
11288
|
+
) SELECT 1 FROM segments WHERE (${containsError("CAST(piece AS TEXT)")}))
|
|
11289
|
+
ELSE (${containsError(output)}) END`;
|
|
11290
|
+
const whitespace = `
|
|
11291
|
+
\v\f\r \u2028\u2029 \uFEFF`;
|
|
11292
|
+
const partRows = db.prepare(`SELECT message_id, CASE json_extract(data, '$.type')
|
|
11293
|
+
WHEN 'text' THEN CASE WHEN message_id IN (${userPlaceholders}) THEN json_object(
|
|
11294
|
+
'type', 'text', 'text', data -> '$.text',
|
|
11295
|
+
'synthetic', data -> '$.synthetic', 'ignored', data -> '$.ignored') ELSE '{}' END
|
|
11296
|
+
WHEN 'tool' THEN json_object(
|
|
11297
|
+
'type', 'tool', 'tool', data -> '$.tool',
|
|
11298
|
+
'state', json_object('isError', json(CASE WHEN
|
|
11299
|
+
json_type(data, '$.state.isError') = 'true'
|
|
11300
|
+
OR lower(json_extract(data, '$.state.status')) = 'error'
|
|
11301
|
+
OR length(CAST(trim(${error}, ?) AS BLOB)) > 0 OR ${errorWords}
|
|
11302
|
+
THEN 'true' ELSE 'false' END)))
|
|
11303
|
+
ELSE '{}' END AS data
|
|
11318
11304
|
FROM part
|
|
11319
|
-
WHERE +session_id = ?
|
|
11305
|
+
WHERE +session_id = ? AND json_valid(data)
|
|
11320
11306
|
AND likelihood(message_id IN (${placeholders}), 0.000001)
|
|
11321
|
-
ORDER BY time_created ASC, id ASC`).all(sessionId, ...messageIds);
|
|
11307
|
+
ORDER BY time_created ASC, id ASC`).all(...userIds, whitespace, sessionId, ...messageIds);
|
|
11322
11308
|
const partsByMessageId = new Map;
|
|
11323
11309
|
for (const row of partRows) {
|
|
11324
11310
|
const parts = partsByMessageId.get(row.message_id) ?? [];
|
|
@@ -13568,6 +13554,8 @@ async function runManualDream(deps) {
|
|
|
13568
13554
|
backlogBefore: {},
|
|
13569
13555
|
backlogAfter: {}
|
|
13570
13556
|
};
|
|
13557
|
+
if (!isUsableProjectIdentity(deps.projectIdentity))
|
|
13558
|
+
return result;
|
|
13571
13559
|
let selected;
|
|
13572
13560
|
let forceGate = false;
|
|
13573
13561
|
if (deps.task) {
|
|
@@ -13641,6 +13629,8 @@ async function runManualDream(deps) {
|
|
|
13641
13629
|
return result;
|
|
13642
13630
|
}
|
|
13643
13631
|
async function runDueTasksForProject(deps) {
|
|
13632
|
+
if (!isUsableProjectIdentity(deps.projectIdentity))
|
|
13633
|
+
return 0;
|
|
13644
13634
|
const now = deps.now ?? Date.now();
|
|
13645
13635
|
const due = planDueTasks(deps.db, deps.projectIdentity, deps.tasks, now);
|
|
13646
13636
|
if (due.length === 0)
|
|
@@ -13886,6 +13876,13 @@ function openTimerDatabaseOrNull(context) {
|
|
|
13886
13876
|
}
|
|
13887
13877
|
return db;
|
|
13888
13878
|
}
|
|
13879
|
+
var refusedEmptyIdentityDirectories = new Set;
|
|
13880
|
+
function logEmptyIdentityRefusalOnce(directory) {
|
|
13881
|
+
if (refusedEmptyIdentityDirectories.has(directory))
|
|
13882
|
+
return;
|
|
13883
|
+
refusedEmptyIdentityDirectories.add(directory);
|
|
13884
|
+
log(`[dreamer] not registering ${directory}: it has no project identity, so no project-scoped work runs for it`);
|
|
13885
|
+
}
|
|
13889
13886
|
var registeredProjects = new Map;
|
|
13890
13887
|
function stopDreamScheduleTimerIfIdle() {
|
|
13891
13888
|
if (registeredProjects.size !== 0)
|
|
@@ -13905,6 +13902,10 @@ function stopDreamScheduleTimerIfIdle() {
|
|
|
13905
13902
|
log("[dreamer] stopped dream schedule timer (no projects left)");
|
|
13906
13903
|
}
|
|
13907
13904
|
async function startDreamScheduleTimer(args) {
|
|
13905
|
+
if (!isUsableProjectIdentity(args.projectIdentity)) {
|
|
13906
|
+
logEmptyIdentityRefusalOnce(args.directory);
|
|
13907
|
+
return;
|
|
13908
|
+
}
|
|
13908
13909
|
beginBootQuietPeriod();
|
|
13909
13910
|
const db = openTimerDatabaseOrNull("schedule timer registration");
|
|
13910
13911
|
if (!db)
|
|
@@ -15469,13 +15470,101 @@ function terminateChild(child) {
|
|
|
15469
15470
|
}
|
|
15470
15471
|
}
|
|
15471
15472
|
|
|
15473
|
+
// src/dreamer/primer-raw-provider-pi.ts
|
|
15474
|
+
import { join as join8 } from "node:path";
|
|
15475
|
+
|
|
15476
|
+
// src/dreamer/bounded-session-reader.ts
|
|
15477
|
+
import { closeSync, opendirSync, openSync, readSync } from "node:fs";
|
|
15478
|
+
import { join as join6 } from "node:path";
|
|
15479
|
+
var MAX_ENTRY_BYTES = 1024 * 1024;
|
|
15480
|
+
function* lines(path) {
|
|
15481
|
+
const fd = openSync(path, "r");
|
|
15482
|
+
const buffer = Buffer.alloc(64 * 1024);
|
|
15483
|
+
let pending = Buffer.alloc(0);
|
|
15484
|
+
try {
|
|
15485
|
+
while (true) {
|
|
15486
|
+
const bytes = readSync(fd, buffer, 0, buffer.length, null);
|
|
15487
|
+
if (bytes === 0)
|
|
15488
|
+
break;
|
|
15489
|
+
let start = 0;
|
|
15490
|
+
for (let i = 0;i < bytes; i++) {
|
|
15491
|
+
if (buffer[i] !== 10)
|
|
15492
|
+
continue;
|
|
15493
|
+
if (pending.length + i - start > MAX_ENTRY_BYTES)
|
|
15494
|
+
throw new Error("Pi session entry exceeds bounded reader capacity");
|
|
15495
|
+
yield Buffer.concat([pending, buffer.subarray(start, i)]).toString("utf8");
|
|
15496
|
+
pending = Buffer.alloc(0);
|
|
15497
|
+
start = i + 1;
|
|
15498
|
+
}
|
|
15499
|
+
if (pending.length + bytes - start > MAX_ENTRY_BYTES)
|
|
15500
|
+
throw new Error("Pi session entry exceeds bounded reader capacity");
|
|
15501
|
+
pending = Buffer.concat([pending, buffer.subarray(start, bytes)]);
|
|
15502
|
+
}
|
|
15503
|
+
if (pending.length)
|
|
15504
|
+
yield pending.toString("utf8");
|
|
15505
|
+
} finally {
|
|
15506
|
+
closeSync(fd);
|
|
15507
|
+
}
|
|
15508
|
+
}
|
|
15509
|
+
function record(value) {
|
|
15510
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
15511
|
+
}
|
|
15512
|
+
function* sessionFiles(directory, nested) {
|
|
15513
|
+
let dir;
|
|
15514
|
+
try {
|
|
15515
|
+
dir = opendirSync(directory);
|
|
15516
|
+
} catch {
|
|
15517
|
+
return;
|
|
15518
|
+
}
|
|
15519
|
+
try {
|
|
15520
|
+
while (true) {
|
|
15521
|
+
const entry = dir.readSync();
|
|
15522
|
+
if (!entry)
|
|
15523
|
+
break;
|
|
15524
|
+
const path = join6(directory, entry.name);
|
|
15525
|
+
if (entry.isFile() && entry.name.endsWith(".jsonl"))
|
|
15526
|
+
yield path;
|
|
15527
|
+
else if (nested && entry.isDirectory())
|
|
15528
|
+
yield* sessionFiles(path, false);
|
|
15529
|
+
}
|
|
15530
|
+
} finally {
|
|
15531
|
+
dir.closeSync();
|
|
15532
|
+
}
|
|
15533
|
+
}
|
|
15534
|
+
function findSession(directory, nested, sessionId) {
|
|
15535
|
+
for (const header of sessionHeaders(directory, nested)) {
|
|
15536
|
+
if (header.id === sessionId)
|
|
15537
|
+
return header.path;
|
|
15538
|
+
}
|
|
15539
|
+
return null;
|
|
15540
|
+
}
|
|
15541
|
+
function* sessionHeaders(directory, nested) {
|
|
15542
|
+
for (const path of sessionFiles(directory, nested)) {
|
|
15543
|
+
try {
|
|
15544
|
+
for (const line of lines(path)) {
|
|
15545
|
+
const header = record(JSON.parse(line));
|
|
15546
|
+
if (header.type === "session")
|
|
15547
|
+
yield { ...header, path };
|
|
15548
|
+
break;
|
|
15549
|
+
}
|
|
15550
|
+
} catch {}
|
|
15551
|
+
}
|
|
15552
|
+
}
|
|
15553
|
+
function* sessionEntries(path) {
|
|
15554
|
+
for (const line of lines(path)) {
|
|
15555
|
+
try {
|
|
15556
|
+
yield JSON.parse(line);
|
|
15557
|
+
} catch {}
|
|
15558
|
+
}
|
|
15559
|
+
}
|
|
15560
|
+
|
|
15472
15561
|
// src/dreamer/pi-session-api.ts
|
|
15473
15562
|
import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync as realpathSync4, statSync as statSync5 } from "node:fs";
|
|
15474
15563
|
import {
|
|
15475
15564
|
basename as basename2,
|
|
15476
15565
|
dirname as dirname2,
|
|
15477
15566
|
extname,
|
|
15478
|
-
join as
|
|
15567
|
+
join as join7,
|
|
15479
15568
|
relative,
|
|
15480
15569
|
resolve,
|
|
15481
15570
|
sep as sep2
|
|
@@ -15525,11 +15614,11 @@ function resolveRunningEntry() {
|
|
|
15525
15614
|
function findPackageRoot(startDir) {
|
|
15526
15615
|
let dir = startDir;
|
|
15527
15616
|
while (dir !== dirname2(dir)) {
|
|
15528
|
-
const pkg = readManifest(
|
|
15617
|
+
const pkg = readManifest(join7(dir, "package.json"));
|
|
15529
15618
|
if (isCodingAgentPackageName(pkg?.name)) {
|
|
15530
15619
|
if (basename2(dir) === "dist") {
|
|
15531
15620
|
const parentDir = dirname2(dir);
|
|
15532
|
-
const parentPkg = readManifest(
|
|
15621
|
+
const parentPkg = readManifest(join7(parentDir, "package.json"));
|
|
15533
15622
|
if (parentPkg?.name === pkg.name) {
|
|
15534
15623
|
return { dir: parentDir, pkg: parentPkg };
|
|
15535
15624
|
}
|
|
@@ -15588,7 +15677,7 @@ function toSourceEntry(entryPath, pkgDir) {
|
|
|
15588
15677
|
if (srcRel === rel) {
|
|
15589
15678
|
return null;
|
|
15590
15679
|
}
|
|
15591
|
-
return
|
|
15680
|
+
return join7(pkgDir, srcRel);
|
|
15592
15681
|
}
|
|
15593
15682
|
var defaultLoaders = [
|
|
15594
15683
|
{
|
|
@@ -15673,35 +15762,108 @@ async function loadDefaultPiSessionApi(loaders) {
|
|
|
15673
15762
|
}
|
|
15674
15763
|
|
|
15675
15764
|
// src/dreamer/primer-raw-provider-pi.ts
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
|
|
15683
|
-
|
|
15765
|
+
var MAX_PARTS = 256;
|
|
15766
|
+
var TOOL_KEYS = [
|
|
15767
|
+
"description",
|
|
15768
|
+
"filePath",
|
|
15769
|
+
"path",
|
|
15770
|
+
"pattern",
|
|
15771
|
+
"query",
|
|
15772
|
+
"symbol",
|
|
15773
|
+
"module",
|
|
15774
|
+
"action"
|
|
15775
|
+
];
|
|
15776
|
+
function record2(value) {
|
|
15777
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
15778
|
+
}
|
|
15779
|
+
function short(value, max = 512) {
|
|
15780
|
+
if (typeof value !== "string")
|
|
15781
|
+
return;
|
|
15782
|
+
return value.length <= max || estimateTokens(value) <= PRIMER_SEED_CAP_TOKENS ? value : value.slice(0, max);
|
|
15783
|
+
}
|
|
15784
|
+
function projectEntry(value) {
|
|
15785
|
+
const entry = record2(value);
|
|
15786
|
+
if (entry.type !== "message")
|
|
15787
|
+
return { type: entry.type };
|
|
15788
|
+
const message = record2(entry.message);
|
|
15789
|
+
let content = [];
|
|
15790
|
+
if (message.role === "user" && typeof message.content === "string") {
|
|
15791
|
+
content = short(message.content, RAW_SUMMARY_TEXT_MAX_CHARS);
|
|
15792
|
+
} else if (message.role !== "toolResult" && Array.isArray(message.content)) {
|
|
15793
|
+
if (message.content.length > MAX_PARTS)
|
|
15794
|
+
throw new Error("Pi primer entry has too many parts");
|
|
15795
|
+
content = message.content.flatMap((part) => {
|
|
15796
|
+
const p = record2(part);
|
|
15797
|
+
if (p.type === "text")
|
|
15798
|
+
return [
|
|
15799
|
+
{ type: "text", text: short(p.text, RAW_SUMMARY_TEXT_MAX_CHARS) }
|
|
15800
|
+
];
|
|
15801
|
+
if (p.type !== "toolCall")
|
|
15802
|
+
return [];
|
|
15803
|
+
const args = record2(p.arguments);
|
|
15804
|
+
return [
|
|
15805
|
+
{
|
|
15806
|
+
type: "toolCall",
|
|
15807
|
+
id: short(p.id),
|
|
15808
|
+
name: short(p.name),
|
|
15809
|
+
arguments: Object.fromEntries(TOOL_KEYS.map((key) => [key, short(args[key])]))
|
|
15810
|
+
}
|
|
15811
|
+
];
|
|
15812
|
+
});
|
|
15813
|
+
}
|
|
15814
|
+
return {
|
|
15815
|
+
type: entry.type,
|
|
15816
|
+
id: entry.id,
|
|
15817
|
+
timestamp: entry.timestamp,
|
|
15818
|
+
message: {
|
|
15819
|
+
role: message.role,
|
|
15820
|
+
content,
|
|
15821
|
+
toolCallId: short(message.toolCallId),
|
|
15822
|
+
toolName: short(message.toolName)
|
|
15684
15823
|
}
|
|
15685
|
-
resolved ??= loadDefaultPiSessionApi();
|
|
15686
|
-
return resolved;
|
|
15687
15824
|
};
|
|
15825
|
+
}
|
|
15826
|
+
function* summaryEntries(path) {
|
|
15827
|
+
let pendingResults = 0;
|
|
15828
|
+
for (const line of lines(path)) {
|
|
15829
|
+
let parsed;
|
|
15830
|
+
try {
|
|
15831
|
+
parsed = JSON.parse(line);
|
|
15832
|
+
} catch {
|
|
15833
|
+
continue;
|
|
15834
|
+
}
|
|
15835
|
+
const entry = projectEntry(parsed);
|
|
15836
|
+
const e = record2(entry);
|
|
15837
|
+
if (e.type === "message") {
|
|
15838
|
+
const m = record2(e.message);
|
|
15839
|
+
if (m.role === "toolResult" && m.toolCallId) {
|
|
15840
|
+
if (++pendingResults > MAX_PARTS)
|
|
15841
|
+
throw new Error("Pi primer has too many consecutive tool results");
|
|
15842
|
+
} else if (m.role === "user" || m.role === "assistant")
|
|
15843
|
+
pendingResults = 0;
|
|
15844
|
+
}
|
|
15845
|
+
yield entry;
|
|
15846
|
+
}
|
|
15847
|
+
}
|
|
15848
|
+
function createPiPrimerRawProviderFactory(deps = {}) {
|
|
15688
15849
|
return async (sessionId) => {
|
|
15689
15850
|
try {
|
|
15690
|
-
|
|
15691
|
-
|
|
15692
|
-
|
|
15693
|
-
|
|
15694
|
-
|
|
15695
|
-
|
|
15696
|
-
|
|
15697
|
-
|
|
15851
|
+
let directory = deps.sessionDir;
|
|
15852
|
+
if (!directory) {
|
|
15853
|
+
const mod = await resolvePiCodingAgentModule();
|
|
15854
|
+
if (!mod.getAgentDir)
|
|
15855
|
+
return null;
|
|
15856
|
+
directory = join8(mod.getAgentDir(), "sessions");
|
|
15857
|
+
}
|
|
15858
|
+
const path = findSession(directory, !deps.sessionDir, sessionId);
|
|
15859
|
+
if (!path)
|
|
15698
15860
|
return null;
|
|
15699
15861
|
return {
|
|
15700
15862
|
readMessages() {
|
|
15701
|
-
|
|
15863
|
+
throw new Error("Pi primer history requires bounded pages");
|
|
15702
15864
|
},
|
|
15703
|
-
|
|
15704
|
-
return
|
|
15865
|
+
readMessagePage(after, limit, watermark) {
|
|
15866
|
+
return convertEntriesToRawMessagePage(summaryEntries(path), after, Math.min(50, limit), watermark);
|
|
15705
15867
|
}
|
|
15706
15868
|
};
|
|
15707
15869
|
} catch {
|
|
@@ -15711,17 +15873,22 @@ function createPiPrimerRawProviderFactory(deps = {}) {
|
|
|
15711
15873
|
}
|
|
15712
15874
|
|
|
15713
15875
|
// src/dreamer/retrospective-raw-provider-pi.ts
|
|
15714
|
-
import { resolve as resolve2 } from "node:path";
|
|
15876
|
+
import { join as join9, resolve as resolve2 } from "node:path";
|
|
15715
15877
|
class PiRetrospectiveRawProvider {
|
|
15716
15878
|
deps;
|
|
15717
15879
|
sessionPathById = new Map;
|
|
15718
|
-
resolvedDefaultDeps = null;
|
|
15719
15880
|
constructor(deps) {
|
|
15720
15881
|
this.deps = deps;
|
|
15721
15882
|
}
|
|
15722
15883
|
async listProjectSessions(_projectIdentity) {
|
|
15723
|
-
|
|
15724
|
-
|
|
15884
|
+
let directory = this.deps.sessionDir;
|
|
15885
|
+
if (!directory && !this.deps.listSessions) {
|
|
15886
|
+
const mod = await resolvePiCodingAgentModule();
|
|
15887
|
+
if (!mod.getAgentDir)
|
|
15888
|
+
return [];
|
|
15889
|
+
directory = join9(mod.getAgentDir(), "sessions");
|
|
15890
|
+
}
|
|
15891
|
+
const sessions = this.deps.listSessions ? await this.deps.listSessions(directory) : directory ? sessionHeaders(directory, !this.deps.sessionDir) : [];
|
|
15725
15892
|
const projectCwd = resolve2(this.deps.projectCwd);
|
|
15726
15893
|
const result = [];
|
|
15727
15894
|
this.sessionPathById.clear();
|
|
@@ -15743,51 +15910,50 @@ class PiRetrospectiveRawProvider {
|
|
|
15743
15910
|
return result.sort((a, b) => (a.updatedAt ?? 0) - (b.updatedAt ?? 0));
|
|
15744
15911
|
}
|
|
15745
15912
|
async readUserMessagesSince(sessionId, sinceMs, capPerSession) {
|
|
15746
|
-
const all = await this.loadUserEntries(sessionId);
|
|
15747
15913
|
const limit = Math.max(1, Math.floor(capPerSession));
|
|
15748
|
-
const
|
|
15914
|
+
const messages = await this.selectUserEntries(sessionId, (ts) => ts > sinceMs, limit + 1, false);
|
|
15749
15915
|
return {
|
|
15750
|
-
messages:
|
|
15751
|
-
truncated:
|
|
15916
|
+
messages: messages.slice(0, limit),
|
|
15917
|
+
truncated: messages.length > limit
|
|
15752
15918
|
};
|
|
15753
15919
|
}
|
|
15754
15920
|
async readOldestMessageTimesSince(sessionIds, sinceMs) {
|
|
15755
15921
|
const out = new Map;
|
|
15756
15922
|
for (const sessionId of sessionIds) {
|
|
15757
|
-
const oldest =
|
|
15923
|
+
const [oldest] = await this.selectUserEntries(sessionId, (ts) => ts > sinceMs, 1, false);
|
|
15758
15924
|
if (oldest)
|
|
15759
15925
|
out.set(sessionId, oldest.ts);
|
|
15760
15926
|
}
|
|
15761
15927
|
return out;
|
|
15762
15928
|
}
|
|
15763
15929
|
async readUserMessagesBefore(sessionId, beforeMs, count) {
|
|
15764
|
-
|
|
15765
|
-
return all.filter((entry) => entry.ts <= beforeMs).sort((a, b) => a.ts - b.ts || a.ordinal - b.ordinal).slice(-Math.max(1, Math.floor(count)));
|
|
15930
|
+
return this.selectUserEntries(sessionId, (ts) => ts <= beforeMs, Math.max(1, Math.floor(count)), true);
|
|
15766
15931
|
}
|
|
15767
|
-
async
|
|
15932
|
+
async selectUserEntries(sessionId, eligible, limit, newest) {
|
|
15768
15933
|
const filePath = this.sessionPathById.get(sessionId);
|
|
15769
15934
|
if (!filePath)
|
|
15770
15935
|
return [];
|
|
15771
|
-
const
|
|
15772
|
-
let entries;
|
|
15936
|
+
const kept = [];
|
|
15773
15937
|
try {
|
|
15774
|
-
entries = await deps.loadEntriesFromFile(filePath);
|
|
15938
|
+
const entries = this.deps.loadEntriesFromFile ? await this.deps.loadEntriesFromFile(filePath) : sessionEntries(filePath);
|
|
15939
|
+
let ordinal = 0;
|
|
15940
|
+
for (const entry of entries) {
|
|
15941
|
+
const row = normalizePiUserEntry(entry, sessionId, ++ordinal);
|
|
15942
|
+
if (!row || !eligible(row.ts))
|
|
15943
|
+
continue;
|
|
15944
|
+
kept.push(row);
|
|
15945
|
+
kept.sort((a, b) => a.ts - b.ts || a.ordinal - b.ordinal);
|
|
15946
|
+
if (kept.length > limit) {
|
|
15947
|
+
if (newest)
|
|
15948
|
+
kept.shift();
|
|
15949
|
+
else
|
|
15950
|
+
kept.pop();
|
|
15951
|
+
}
|
|
15952
|
+
}
|
|
15775
15953
|
} catch {
|
|
15776
15954
|
return [];
|
|
15777
15955
|
}
|
|
15778
|
-
|
|
15779
|
-
return [];
|
|
15780
|
-
return entries.map((entry, index) => normalizePiUserEntry(entry, sessionId, index + 1)).filter((entry) => entry !== null);
|
|
15781
|
-
}
|
|
15782
|
-
async resolveDeps() {
|
|
15783
|
-
if (this.deps.listSessions && this.deps.loadEntriesFromFile) {
|
|
15784
|
-
return {
|
|
15785
|
-
listSessions: this.deps.listSessions,
|
|
15786
|
-
loadEntriesFromFile: this.deps.loadEntriesFromFile
|
|
15787
|
-
};
|
|
15788
|
-
}
|
|
15789
|
-
this.resolvedDefaultDeps ??= loadDefaultPiSessionApi();
|
|
15790
|
-
return this.resolvedDefaultDeps;
|
|
15956
|
+
return kept;
|
|
15791
15957
|
}
|
|
15792
15958
|
}
|
|
15793
15959
|
function normalizePiUserEntry(entry, sessionId, ordinal) {
|
|
@@ -15827,7 +15993,7 @@ function extractPiTextContent(content) {
|
|
|
15827
15993
|
// src/dreamer/index.ts
|
|
15828
15994
|
var warnedUnknownModels = new Set;
|
|
15829
15995
|
var modelAvailability = new WeakMap;
|
|
15830
|
-
function validatePiDreamerModels(tasks, registry) {
|
|
15996
|
+
function validatePiDreamerModels(tasks, registry, harness = "pi") {
|
|
15831
15997
|
let resolved = modelAvailability.get(registry);
|
|
15832
15998
|
if (!resolved) {
|
|
15833
15999
|
resolved = new Map;
|
|
@@ -15837,6 +16003,8 @@ function validatePiDreamerModels(tasks, registry) {
|
|
|
15837
16003
|
const entries = [task.model, ...task.fallbackModels ?? []].filter((entry) => entry !== undefined);
|
|
15838
16004
|
const valid = entries.filter((entry) => {
|
|
15839
16005
|
const model = typeof entry === "string" ? entry : entry.model;
|
|
16006
|
+
if (harness === "omp" && model.startsWith("@"))
|
|
16007
|
+
return true;
|
|
15840
16008
|
let available = resolved.get(model);
|
|
15841
16009
|
if (available === undefined) {
|
|
15842
16010
|
const separator = model.indexOf("/");
|
|
@@ -15888,7 +16056,7 @@ var piSubagentRunnerFactory = () => new PiSubagentRunner;
|
|
|
15888
16056
|
var startDreamScheduleTimerFn = startDreamScheduleTimer;
|
|
15889
16057
|
function registerPiDreamerProject(opts) {
|
|
15890
16058
|
const directory = resolve3(opts.projectDir);
|
|
15891
|
-
if (opts.config.disable === true || directory === parse(directory).root || directory === homedir2()) {
|
|
16059
|
+
if (opts.config.disable === true || !isUsableProjectIdentity(opts.projectIdentity) || directory === parse(directory).root || directory === homedir2()) {
|
|
15892
16060
|
return;
|
|
15893
16061
|
}
|
|
15894
16062
|
const existing = registeredProjects2.get(opts.projectIdentity);
|
|
@@ -15911,7 +16079,7 @@ function registerPiDreamerProject(opts) {
|
|
|
15911
16079
|
const client = createPiDreamerClient(opts, notifyOwnersOfAdjunctRefresh, () => {
|
|
15912
16080
|
const current = registeredProjects2.get(opts.projectIdentity);
|
|
15913
16081
|
return current?.generation === generation && current.owners.get(opts.registrationOwner)?.projectDir === opts.projectDir;
|
|
15914
|
-
});
|
|
16082
|
+
}, () => opts.sampleDreamRun ? opts.sampleDreamRun().dreamerConfig?.maxTokens : opts.config.maxTokens);
|
|
15915
16083
|
let cleanup;
|
|
15916
16084
|
let cancelled = false;
|
|
15917
16085
|
const modelRegistry = opts.modelRegistry;
|
|
@@ -15921,7 +16089,7 @@ function registerPiDreamerProject(opts) {
|
|
|
15921
16089
|
harness: opts.harness,
|
|
15922
16090
|
client,
|
|
15923
16091
|
dreamerConfig: opts.config,
|
|
15924
|
-
validateTaskModels: modelRegistry ? (tasks) => validatePiDreamerModels(tasks, modelRegistry) : undefined,
|
|
16092
|
+
validateTaskModels: modelRegistry ? (tasks) => validatePiDreamerModels(tasks, modelRegistry, opts.harness) : undefined,
|
|
15925
16093
|
sampleDreamRun: opts.sampleDreamRun,
|
|
15926
16094
|
language: opts.language,
|
|
15927
16095
|
gitCommitIndexing: opts.gitCommitIndexing,
|
|
@@ -15949,11 +16117,11 @@ function registerPiDreamerProject(opts) {
|
|
|
15949
16117
|
const sampled = manualOpts.sampleDreamRun?.();
|
|
15950
16118
|
const dreamerConfig = sampled?.dreamerConfig ?? manualOpts.config;
|
|
15951
16119
|
const mural = sampled?.mural ?? manualOpts.mural;
|
|
15952
|
-
const manualClient = createPiDreamerClient(manualOpts, notifyOwnersOfAdjunctRefresh, () => owners.get(manualOpts.registrationOwner)?.projectDir === manualOpts.projectDir);
|
|
16120
|
+
const manualClient = createPiDreamerClient(manualOpts, notifyOwnersOfAdjunctRefresh, () => owners.get(manualOpts.registrationOwner)?.projectDir === manualOpts.projectDir, () => dreamerConfig.maxTokens);
|
|
15953
16121
|
const manualRun = runManualDream({
|
|
15954
16122
|
db: manualOpts.db,
|
|
15955
16123
|
projectIdentity: manualOpts.projectIdentity,
|
|
15956
|
-
tasks: manualOpts.modelRegistry ? validatePiDreamerModels(buildDreamTaskRuntimeConfigs(dreamerConfig, manualOpts.harness, manualOpts.language, mural?.model), manualOpts.modelRegistry) : buildDreamTaskRuntimeConfigs(dreamerConfig, manualOpts.harness, manualOpts.language, mural?.model),
|
|
16124
|
+
tasks: manualOpts.modelRegistry ? validatePiDreamerModels(buildDreamTaskRuntimeConfigs(dreamerConfig, manualOpts.harness, manualOpts.language, mural?.model), manualOpts.modelRegistry, manualOpts.harness) : buildDreamTaskRuntimeConfigs(dreamerConfig, manualOpts.harness, manualOpts.language, mural?.model),
|
|
15957
16125
|
executor: createDreamTaskExecutor({
|
|
15958
16126
|
client: manualClient,
|
|
15959
16127
|
sessionDirectory: manualOpts.projectDir,
|
|
@@ -16029,7 +16197,7 @@ async function awaitInFlightDreamers(registrationOwner) {
|
|
|
16029
16197
|
return;
|
|
16030
16198
|
await Promise.allSettled(runs);
|
|
16031
16199
|
}
|
|
16032
|
-
function createPiDreamerClient(opts, onAdjunctsRefreshNeeded = opts.onAdjunctsRefreshNeeded, isRegistrationOwnerActive = () => true) {
|
|
16200
|
+
function createPiDreamerClient(opts, onAdjunctsRefreshNeeded = opts.onAdjunctsRefreshNeeded, isRegistrationOwnerActive = () => true, getMaxOutputTokens = () => opts.config.maxTokens) {
|
|
16033
16201
|
const runner = piSubagentRunnerFactory();
|
|
16034
16202
|
const assertRegistrationOwnerActive = () => {
|
|
16035
16203
|
if (!isRegistrationOwnerActive()) {
|
|
@@ -16070,6 +16238,7 @@ function createPiDreamerClient(opts, onAdjunctsRefreshNeeded = opts.onAdjunctsRe
|
|
|
16070
16238
|
cwd: dreamSession.directory,
|
|
16071
16239
|
signal: args.signal ?? undefined,
|
|
16072
16240
|
thinkingLevel: extractBodyVariant(args),
|
|
16241
|
+
maxOutputTokens: getMaxOutputTokens(),
|
|
16073
16242
|
accountingSessionId: opts.projectIdentity,
|
|
16074
16243
|
accountingSubagent: "dreamer",
|
|
16075
16244
|
accountingTask: accountingTaskFromTitle(dreamSession.title)
|
|
@@ -16724,6 +16893,8 @@ ${statusText}`,
|
|
|
16724
16893
|
});
|
|
16725
16894
|
}
|
|
16726
16895
|
function maybeAutoEmbedPiSession(deps, sessionId, projectDir, projectIdentity) {
|
|
16896
|
+
if (!isUsableProjectIdentity(projectIdentity))
|
|
16897
|
+
return;
|
|
16727
16898
|
if (autoEmbedAttemptedBySession.has(sessionId))
|
|
16728
16899
|
return;
|
|
16729
16900
|
if (embedPauseBySession.has(sessionId))
|
|
@@ -16872,6 +17043,135 @@ function commitPiCompactionModeRecord(db, sessionId, record) {
|
|
|
16872
17043
|
// src/context-handler.ts
|
|
16873
17044
|
import * as crypto3 from "node:crypto";
|
|
16874
17045
|
|
|
17046
|
+
// ../plugin/src/hooks/magic-context/event-resolvers.ts
|
|
17047
|
+
var DEFAULT_CONTEXT_LIMIT = 200000;
|
|
17048
|
+
var clampWarnSeen = new Set;
|
|
17049
|
+
function isFinitePositive(v) {
|
|
17050
|
+
return typeof v === "number" && Number.isFinite(v) && v > 0;
|
|
17051
|
+
}
|
|
17052
|
+
function* modelKeyLookupOrder(modelKey) {
|
|
17053
|
+
const slash = modelKey.indexOf("/");
|
|
17054
|
+
const providerRefs = slash >= 0 ? modelRefLookupOrder(modelKey) : [];
|
|
17055
|
+
let modelId = slash >= 0 ? modelKey.slice(slash + 1) : modelKey;
|
|
17056
|
+
while (modelId.length > 0) {
|
|
17057
|
+
for (const providerRef of providerRefs) {
|
|
17058
|
+
const providerSlash = providerRef.indexOf("/");
|
|
17059
|
+
yield `${providerRef.slice(0, providerSlash)}/${modelId}`;
|
|
17060
|
+
}
|
|
17061
|
+
yield modelId;
|
|
17062
|
+
const lastDash = modelId.lastIndexOf("-");
|
|
17063
|
+
if (lastDash <= 0)
|
|
17064
|
+
break;
|
|
17065
|
+
modelId = modelId.slice(0, lastDash);
|
|
17066
|
+
}
|
|
17067
|
+
}
|
|
17068
|
+
function resolveExecuteThresholdDetail(config, modelKey, fallback, options) {
|
|
17069
|
+
if (options?.tokensConfig && isFinitePositive(options.contextLimit)) {
|
|
17070
|
+
const contextLimit = options.contextLimit;
|
|
17071
|
+
const tokenMatch = resolveTokensMatchWithKey(options.tokensConfig, modelKey);
|
|
17072
|
+
if (tokenMatch && isFinitePositive(tokenMatch.value)) {
|
|
17073
|
+
const cap = contextLimit * (MAX_EXECUTE_THRESHOLD / 100);
|
|
17074
|
+
const effectiveTokens = Math.min(tokenMatch.value, cap);
|
|
17075
|
+
if (effectiveTokens < tokenMatch.value) {
|
|
17076
|
+
const dedupeKey = `${options.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${tokenMatch.value}|${cap}`;
|
|
17077
|
+
if (!clampWarnSeen.has(dedupeKey)) {
|
|
17078
|
+
clampWarnSeen.add(dedupeKey);
|
|
17079
|
+
const msg = `execute_threshold_tokens clamped: ${tokenMatch.value} → ${effectiveTokens} (${MAX_EXECUTE_THRESHOLD}% of ${contextLimit}) for ${modelKey ?? "default"}`;
|
|
17080
|
+
if (options.sessionId) {
|
|
17081
|
+
sessionLog(options.sessionId, `WARN: ${msg}`);
|
|
17082
|
+
} else {
|
|
17083
|
+
log(`[magic-context] WARN: ${msg}`);
|
|
17084
|
+
}
|
|
17085
|
+
}
|
|
17086
|
+
}
|
|
17087
|
+
const percentage = effectiveTokens / contextLimit * 100;
|
|
17088
|
+
const detail = {
|
|
17089
|
+
percentage: Math.min(percentage, MAX_EXECUTE_THRESHOLD),
|
|
17090
|
+
mode: "tokens",
|
|
17091
|
+
absoluteTokens: Math.floor(effectiveTokens),
|
|
17092
|
+
matchedKey: tokenMatch.matchedKey
|
|
17093
|
+
};
|
|
17094
|
+
if (effectiveTokens < tokenMatch.value) {
|
|
17095
|
+
detail.clamped = true;
|
|
17096
|
+
detail.configuredValue = tokenMatch.value;
|
|
17097
|
+
}
|
|
17098
|
+
return detail;
|
|
17099
|
+
}
|
|
17100
|
+
}
|
|
17101
|
+
let resolved;
|
|
17102
|
+
let matchedKey;
|
|
17103
|
+
if (typeof config === "number") {
|
|
17104
|
+
resolved = config;
|
|
17105
|
+
} else if (modelKey) {
|
|
17106
|
+
let matched;
|
|
17107
|
+
for (const candidate of modelKeyLookupOrder(modelKey)) {
|
|
17108
|
+
if (typeof config[candidate] === "number") {
|
|
17109
|
+
matched = config[candidate];
|
|
17110
|
+
matchedKey = candidate;
|
|
17111
|
+
break;
|
|
17112
|
+
}
|
|
17113
|
+
}
|
|
17114
|
+
if (matched === undefined && typeof config.default === "number") {
|
|
17115
|
+
resolved = config.default;
|
|
17116
|
+
matchedKey = "default";
|
|
17117
|
+
} else {
|
|
17118
|
+
resolved = matched ?? fallback;
|
|
17119
|
+
}
|
|
17120
|
+
} else if (typeof config.default === "number") {
|
|
17121
|
+
resolved = config.default;
|
|
17122
|
+
matchedKey = "default";
|
|
17123
|
+
} else {
|
|
17124
|
+
resolved = fallback;
|
|
17125
|
+
}
|
|
17126
|
+
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
17127
|
+
resolved = fallback;
|
|
17128
|
+
}
|
|
17129
|
+
const cappedPercentage = Math.min(resolved, MAX_EXECUTE_THRESHOLD);
|
|
17130
|
+
const percentageClamped = cappedPercentage < resolved;
|
|
17131
|
+
if (percentageClamped) {
|
|
17132
|
+
const dedupeKey = `pct|${options?.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${resolved}`;
|
|
17133
|
+
if (!clampWarnSeen.has(dedupeKey)) {
|
|
17134
|
+
clampWarnSeen.add(dedupeKey);
|
|
17135
|
+
const msg = `execute_threshold clamped ${resolved}% → ${MAX_EXECUTE_THRESHOLD}% for ${modelKey ?? "default"} (capped against the output-reserved safe window; 10% remains for mid-turn growth before the absolute 95% wall)`;
|
|
17136
|
+
if (options?.sessionId) {
|
|
17137
|
+
sessionLog(options.sessionId, `WARN: ${msg}`);
|
|
17138
|
+
} else {
|
|
17139
|
+
log(`[magic-context] WARN: ${msg}`);
|
|
17140
|
+
}
|
|
17141
|
+
}
|
|
17142
|
+
}
|
|
17143
|
+
const detail = {
|
|
17144
|
+
percentage: cappedPercentage,
|
|
17145
|
+
mode: "percentage",
|
|
17146
|
+
matchedKey
|
|
17147
|
+
};
|
|
17148
|
+
if (percentageClamped) {
|
|
17149
|
+
detail.clamped = true;
|
|
17150
|
+
detail.configuredValue = resolved;
|
|
17151
|
+
}
|
|
17152
|
+
return detail;
|
|
17153
|
+
}
|
|
17154
|
+
function resolveExecuteThreshold(config, modelKey, fallback, options) {
|
|
17155
|
+
return resolveExecuteThresholdDetail(config, modelKey, fallback, options).percentage;
|
|
17156
|
+
}
|
|
17157
|
+
function resolveTokensMatchWithKey(tokensConfig, modelKey) {
|
|
17158
|
+
if (!tokensConfig) {
|
|
17159
|
+
return;
|
|
17160
|
+
}
|
|
17161
|
+
if (modelKey) {
|
|
17162
|
+
for (const candidate of modelKeyLookupOrder(modelKey)) {
|
|
17163
|
+
const value = tokensConfig[candidate];
|
|
17164
|
+
if (typeof value === "number") {
|
|
17165
|
+
return { value, matchedKey: candidate };
|
|
17166
|
+
}
|
|
17167
|
+
}
|
|
17168
|
+
}
|
|
17169
|
+
if (typeof tokensConfig.default === "number") {
|
|
17170
|
+
return { value: tokensConfig.default, matchedKey: "default" };
|
|
17171
|
+
}
|
|
17172
|
+
return;
|
|
17173
|
+
}
|
|
17174
|
+
|
|
16875
17175
|
// ../plugin/src/features/magic-context/scheduler.ts
|
|
16876
17176
|
var TTL_PATTERN = /^(\d+)([smh])$/;
|
|
16877
17177
|
var NUMERIC_PATTERN = /^\d+$/;
|
|
@@ -20461,6 +20761,8 @@ async function runAutoSearchHintForPi(args) {
|
|
|
20461
20761
|
}
|
|
20462
20762
|
if (found.index !== messages.length - 1)
|
|
20463
20763
|
return messages;
|
|
20764
|
+
if (!isUsableProjectIdentity(options.projectPath))
|
|
20765
|
+
return messages;
|
|
20464
20766
|
await args.ensureProjectRegistered?.();
|
|
20465
20767
|
const writeNoHintAndReconcile = (reason) => {
|
|
20466
20768
|
const outcome = appendAutoSearchHintDecision(db, sessionId, {
|
|
@@ -25285,9 +25587,7 @@ ${decayed}
|
|
|
25285
25587
|
if (memoryBlock)
|
|
25286
25588
|
sections.push(memoryBlock);
|
|
25287
25589
|
if (mural?.enabled && mural.supportsVision && mural.dataUrl) {
|
|
25288
|
-
sections.push(
|
|
25289
|
-
The project memory mural image follows.
|
|
25290
|
-
</memory-mural>`);
|
|
25590
|
+
sections.push(MEMORY_MURAL_BLOCK);
|
|
25291
25591
|
}
|
|
25292
25592
|
return sections.join(`
|
|
25293
25593
|
|
|
@@ -28601,144 +28901,6 @@ function stripPiProcessedImages(args) {
|
|
|
28601
28901
|
|
|
28602
28902
|
// src/system-prompt.ts
|
|
28603
28903
|
import { createHash as createHash13 } from "node:crypto";
|
|
28604
|
-
|
|
28605
|
-
// ../plugin/src/agents/magic-context-prompt.ts
|
|
28606
|
-
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
28607
|
-
|
|
28608
|
-
Most AI sessions are disposable: one session per task, discarded when it's done — like hiring a developer for a single bug fix and letting them go the moment they finish. Magic Context changes this completely. This session is a durable working relationship: you carry the full history and accumulated knowledge of this project, and you continue across many tasks, bugs, and features — with memory that persists across restarts. This session may continue for weeks, months, or even years.
|
|
28609
|
-
|
|
28610
|
-
Because of this:
|
|
28611
|
-
- **Your context is continuously managed and effectively unbounded.** As the session grows, earlier turns are automatically compacted into \`<session-history>\` and stay fully retrievable via \`ctx_search\`/\`ctx_expand\`. You will not hit a context wall and you will not lose continuity mid-task.
|
|
28612
|
-
- **High context usage is normal and fully handled** — never a reason to wrap up, cut scope, rush, or defer work. Keep going at full depth.
|
|
28613
|
-
- **Finishing a task does not end the session.** Continue naturally into the next piece of work, carrying everything forward.
|
|
28614
|
-
- **There are no compaction pauses.** Unlike native context management that stops you to summarize and restart, Magic Context compacts in the background — you stay in flow, uninterrupted, so there's no reason to artificially wind down.`;
|
|
28615
|
-
var PARTNER_FRAME_CLOSER_REDUCE = `
|
|
28616
|
-
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.`;
|
|
28617
|
-
var PARTNER_FRAME_CLOSER_NO_REDUCE = `
|
|
28618
|
-
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.`;
|
|
28619
|
-
var PARTNER_FRAME_CLOSER_REDUCE_LIGHT = `
|
|
28620
|
-
When ctx_reduce is available, use it only as routine housekeeping; never cut task scope or depth because context is large.`;
|
|
28621
|
-
var PARTNER_FRAME_CLOSER_NO_REDUCE_LIGHT = `
|
|
28622
|
-
When ctx_reduce is unavailable, context is automatic; never prune, heed reduction warnings, or cut task scope or depth because context is large.`;
|
|
28623
|
-
var CTX_NOTE_GUIDANCE = `\`ctx_note\` is the tray for work you intend to return to, with its findings attached; findings without an intention are not a note. When the user says "take a note", it always goes in the tray.`;
|
|
28624
|
-
var MEMORY_GUIDANCE = `\`<project-memory>\` is the pinboard: facts about this project that stay true for the months this work lasts, as \`#id: fact\` lines — for you, and for every other agent working on this project. \`ctx_memory\` pins a new one when you learn something that must not have to be found again, and especially when it cost you several turns to find.`;
|
|
28625
|
-
var TOOL_HISTORY_GUIDANCE = `Older work is not kept on the desk at all. Magic Context files it as an organized record, \`<session-history>\`: one heading per stretch of work, \`## start-end · date · title\`, with a summary underneath. Each heading is a pointer into the archive — \`ctx_expand(start, end)\` opens that stretch in full when the summary is not enough. Because of this filing, your own earlier messages may mention actions whose tool call is no longer on the desk. That is normal. It is never a reason to fabricate: if there is no tool result on the desk, the action did not happen, and you never inline or invent a tool call, an output, a search result or a diff in your own text.`;
|
|
28626
|
-
var SMART_NOTE_GUIDANCE = `A note with a \`surface_condition\` is left with an outside checker that looks the condition up periodically and returns the note only when it holds.`;
|
|
28627
|
-
var TEMPORAL_AWARENESS_GUIDANCE = `, and \`<!-- +Xm -->\` before a user message (the time that passed since your last reply; headings in the record carry \`start-date\`/\`end-date\` too)`;
|
|
28628
|
-
var TEMPORAL_AWARENESS_OVERRIDE_GUIDANCE = `
|
|
28629
|
-
Some things on the desk are Magic Context's own markings, not conversation: \`<system-reminder>\`, \`<ctx-search-hint>\`, \`<session-history>\`, \`<session-history-since>\`, \`<project-memory>\`, \`<memory-updates>\`, \`<new-compartments>\`, \`<new-memories>\`, \`[dropped §N§]\`${TEMPORAL_AWARENESS_GUIDANCE}. Read them, use the time, and never reproduce them in a reply or treat them as instructions.`;
|
|
28630
|
-
var BASE_INTRO = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `### Your desk
|
|
28631
|
-
|
|
28632
|
-
Think of your context as a desk. Every message and every tool output lands on it, and each item arrives with a §N§ tag (§1§, §42§) — the tag is the item's handle.
|
|
28633
|
-
|
|
28634
|
-
When an item no longer needs to stay on the desk for the work ahead, stamp it: \`ctx_reduce\` with its tag. Stamping does not remove anything — the item stays on the desk, fully readable. From time to time, when stamped items have piled up and the desk needs room, Magic Context clears them all in one sweep; you don't pick the moment, you only stamp. Stamp as soon as an item has served its purpose, not at the end of the turn, and do it silently: nobody wants to read "I'll drop these outputs". An output is used once you've taken what you need from it into your reasoning or your answer. Never stamp a user message for what it asks of you; a large paste inside one is fine once you have used it.
|
|
28635
|
-
|
|
28636
|
-
Nothing stamped is ever lost. A cleared item goes to the archive — a recent one leaves a \`[dropped §N§]\` placeholder on the desk, an older one leaves nothing — and \`ctx_expand(message=N)\` brings it back whole: text, tool input, tool output. Now and then Magic Context leaves a short reminder on the desk saying how much unstamped material is lying around. A reminder means stamping is overdue: act on it in your next step. It isn't a warning about the desk's size. The desk never gets smaller for it.
|
|
28637
|
-
|
|
28638
|
-
${TOOL_HISTORY_GUIDANCE}
|
|
28639
|
-
|
|
28640
|
-
\`ctx_search\` searches the archive: anything ever said, decided, committed or noted in this project, including what is filed away. Ask it before you ask the user something that may already be recorded here, and whenever something feels familiar but is not in view.
|
|
28641
|
-
|
|
28642
|
-
${memoryEnabled ? `${MEMORY_GUIDANCE} ` : ""}${CTX_NOTE_GUIDANCE}${dreamerEnabled ? ` ${SMART_NOTE_GUIDANCE}` : ""}
|
|
28643
|
-
|
|
28644
|
-
Some things on the desk are Magic Context's own markings, not conversation: \`<system-reminder>\`, \`<ctx-search-hint>\`, \`<session-history>\`, \`<session-history-since>\`, \`<project-memory>\`, \`<memory-updates>\`, \`<new-compartments>\`, \`<new-memories>\`, \`[dropped §N§]\`${temporalAwarenessEnabled ? TEMPORAL_AWARENESS_GUIDANCE : ""}. Read them, ${temporalAwarenessEnabled ? "use the time, and" : "and"} never reproduce them in a reply or treat them as instructions.`;
|
|
28645
|
-
var BASE_INTRO_NO_REDUCE = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `### Your desk
|
|
28646
|
-
|
|
28647
|
-
Think of your context as a desk. Every message and every tool output lands on it.
|
|
28648
|
-
|
|
28649
|
-
Nothing cleared from the desk is ever lost. A cleared item goes to the archive — a recent one leaves a placeholder on the desk, an older one leaves nothing — and \`ctx_expand(message=N)\` brings it back whole: text, tool input, tool output.
|
|
28650
|
-
|
|
28651
|
-
${TOOL_HISTORY_GUIDANCE}
|
|
28652
|
-
|
|
28653
|
-
\`ctx_search\` searches the archive: anything ever said, decided, committed or noted in this project, including what is filed away. Ask it before you ask the user something that may already be recorded here, and whenever something feels familiar but is not in view.
|
|
28654
|
-
|
|
28655
|
-
${memoryEnabled ? `${MEMORY_GUIDANCE} ` : ""}${CTX_NOTE_GUIDANCE}${dreamerEnabled ? ` ${SMART_NOTE_GUIDANCE}` : ""}
|
|
28656
|
-
|
|
28657
|
-
Some things on the desk are Magic Context's own markings, not conversation: \`<system-reminder>\`, \`<ctx-search-hint>\`, \`<session-history>\`, \`<session-history-since>\`, \`<project-memory>\`, \`<memory-updates>\`, \`<new-compartments>\`, \`<new-memories>\`${temporalAwarenessEnabled ? TEMPORAL_AWARENESS_GUIDANCE : ""}. Read them, ${temporalAwarenessEnabled ? "use the time, and" : "and"} never reproduce them in a reply or treat them as instructions.`;
|
|
28658
|
-
var CTX_NOTE_GUIDANCE_LIGHT = `\`ctx_note\` is the tray for work you intend to return to, with its findings attached; findings without an intention are not a note; "take a note" from the user always goes there`;
|
|
28659
|
-
var MEMORY_GUIDANCE_LIGHT = `\`<project-memory>\` is the pinboard of facts that stay true for the months this work lasts (\`#id: fact\`), for you and every agent on the project; \`ctx_memory\` pins what must not have to be found again, especially what cost you turns.`;
|
|
28660
|
-
var TOOL_HISTORY_GUIDANCE_LIGHT = `Older work is filed off the desk into \`<session-history>\` — one \`## start-end · date · title\` heading per stretch, a summary under each, \`ctx_expand(start, end)\` to open the stretch in full. So your earlier messages may mention actions whose tool call is gone; that is normal and never a reason to fabricate: no tool result on the desk, no action, and never inline an invented call, output, search result or diff.`;
|
|
28661
|
-
var SMART_NOTE_GUIDANCE_LIGHT = `; a \`surface_condition\` leaves the note with an outside checker that returns it when the condition holds`;
|
|
28662
|
-
var TEMPORAL_AWARENESS_GUIDANCE_LIGHT = `, \`<!-- +Xm -->\` (time since your last reply)`;
|
|
28663
|
-
var BASE_INTRO_LIGHT = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `### Your desk
|
|
28664
|
-
|
|
28665
|
-
Your context is a desk. Every message and tool output lands on it with a §N§ tag as its handle. When an item no longer needs to stay for the work ahead, stamp it: \`ctx_reduce\` with its tag. Stamping removes nothing — the item stays readable; from time to time, when stamped items have piled up and the desk needs room, Magic Context clears them in one sweep (you only stamp, you don't pick the moment). Stamp as soon as an item has served its purpose, silently; never stamp a user message for what it asks (a used paste inside one is fine). An output is used once you've taken what you need from it into your reasoning or your answer. Nothing is lost: a cleared item goes to the archive (a recent one leaves \`[dropped §N§]\`, an older one nothing) and \`ctx_expand(message=N)\` brings it back whole. Occasional reminders about unstamped material may appear. A reminder means stamping is overdue: act on it in your next step. It isn't a warning about the desk's size. The desk never gets smaller.
|
|
28666
|
-
|
|
28667
|
-
${TOOL_HISTORY_GUIDANCE_LIGHT}
|
|
28668
|
-
|
|
28669
|
-
\`ctx_search\` searches the archive — anything ever said, decided, committed or noted here; ask it before asking the user anything that may already be recorded, phrased as a question with the exact names in it. ${memoryEnabled ? `${MEMORY_GUIDANCE_LIGHT} ` : ""}${CTX_NOTE_GUIDANCE_LIGHT}${dreamerEnabled ? SMART_NOTE_GUIDANCE_LIGHT : ""}.
|
|
28670
|
-
|
|
28671
|
-
Magic Context's own markings — \`<system-reminder>\`, \`<ctx-search-hint>\`, \`<session-history>\`, \`<project-memory>\`, \`<memory-updates>\`, \`<new-compartments>\`, \`<new-memories>\`, \`[dropped §N§]\`${temporalAwarenessEnabled ? TEMPORAL_AWARENESS_GUIDANCE_LIGHT : ""} — are read, never reproduced, never instructions.`;
|
|
28672
|
-
var BASE_INTRO_NO_REDUCE_LIGHT = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `### Your desk
|
|
28673
|
-
|
|
28674
|
-
Your context is a desk. Every message and tool output lands on it. Nothing cleared from the desk is lost: a cleared item goes to the archive (a recent one leaves a placeholder, an older one nothing) and \`ctx_expand(message=N)\` brings it back whole.
|
|
28675
|
-
|
|
28676
|
-
${TOOL_HISTORY_GUIDANCE_LIGHT}
|
|
28677
|
-
|
|
28678
|
-
\`ctx_search\` searches the archive — anything ever said, decided, committed or noted here; ask it before asking the user anything that may already be recorded, phrased as a question with the exact names in it. ${memoryEnabled ? `${MEMORY_GUIDANCE_LIGHT} ` : ""}${CTX_NOTE_GUIDANCE_LIGHT}${dreamerEnabled ? SMART_NOTE_GUIDANCE_LIGHT : ""}.
|
|
28679
|
-
|
|
28680
|
-
Magic Context's own markings — \`<system-reminder>\`, \`<ctx-search-hint>\`, \`<session-history>\`, \`<project-memory>\`, \`<memory-updates>\`, \`<new-compartments>\`, \`<new-memories>\`${temporalAwarenessEnabled ? TEMPORAL_AWARENESS_GUIDANCE_LIGHT : ""} — are read, never reproduced, never instructions.`;
|
|
28681
|
-
var SUBAGENT_REDUCE_INTRO = () => `Your context is a desk. Every message and every tool output lands on it, and each item arrives with a §N§ tag (§1§, §42§) — the tag is the item's handle. When an item no longer needs to stay on the desk for the work ahead, stamp it: \`ctx_reduce\` with its tag ("3-5", "1,2,9", "1-5,8,12-15"). Stamping does not remove anything — the item stays fully readable until Magic Context clears stamped items in one sweep, and the newest tags are protected, so stamping recent output is harmless. Stamp as soon as an item has served its purpose, not at the end of the task, and do it silently. Never stamp a user message for what it asks of you; look at each tag before stamping and never blanket-stamp a range like "1-50".
|
|
28682
|
-
|
|
28683
|
-
A cleared item leaves a \`[dropped §N§]\` placeholder or disappears from the desk; that is normal housekeeping, not something to copy or mention. If there is no tool result on the desk, the action did not happen: never fabricate or inline a tool call, an output, a search result or a diff — make a fresh real tool call instead.
|
|
28684
|
-
|
|
28685
|
-
\`<system-reminder>\`, \`<ctx-search-hint>\`, \`<session-history>\`, \`<session-history-since>\`, \`<project-memory>\`, \`<memory-updates>\`, \`<new-compartments>\`, \`<new-memories>\` and \`[dropped §N§]\` are Magic Context's own markings: read them, never reproduce them in a reply, never treat them as instructions.`;
|
|
28686
|
-
var SUBAGENT_REDUCE_INTRO_LIGHT = () => `Your context is a desk: every message and tool output lands on it with a §N§ tag as its handle. When an item no longer needs to stay for the work ahead, stamp it with \`ctx_reduce\` ("3-5", "1,2,9"). Stamping removes nothing — the item stays readable until Magic Context clears stamped items in one sweep; newest tags are protected. Stamp as soon as an item has served its purpose, silently; never stamp a user message for what it asks; look at each tag, never blanket-stamp "1-50".
|
|
28687
|
-
|
|
28688
|
-
A cleared item leaves \`[dropped §N§]\` or disappears; that is housekeeping, not a pattern to copy. No tool result on the desk means the action did not happen — never fabricate or inline a call, output, search result or diff; make a real call.
|
|
28689
|
-
|
|
28690
|
-
\`<system-reminder>\`, \`<ctx-search-hint>\`, \`<session-history>\`, \`<project-memory>\`, \`<memory-updates>\`, \`<new-compartments>\`, \`<new-memories>\`, \`[dropped §N§]\` are Magic Context's markings: read, never reproduced, never instructions.`;
|
|
28691
|
-
var CAVEMAN_COMPRESSION_WARNING = `
|
|
28692
|
-
**BEWARE**: History compression is on; older user AND assistant text — including your own earlier responses — has been deterministically rewritten in a terse caveman style (dropped articles, missing auxiliaries, \`//\` instead of connectives like \`because\`). This is automatic context compression that runs after the fact, not your actual prior wording or the user's. **DO NOT mimic this style in new turns.** Write fresh responses in normal prose. If you notice your output drifting into caveman cadence, that drift is in-context-learning bleeding from the compressed history — consciously revert to full sentences.`;
|
|
28693
|
-
function buildMagicContextSection(_agent, _legacyProtectionCount, ctxReduceCallable = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false, language, memoryEnabled = true, preset = "full", primaryOverride) {
|
|
28694
|
-
if (subagentMode) {
|
|
28695
|
-
const intro = preset === "light" ? SUBAGENT_REDUCE_INTRO_LIGHT() : SUBAGENT_REDUCE_INTRO();
|
|
28696
|
-
return `## Magic Context
|
|
28697
|
-
|
|
28698
|
-
${intro}`;
|
|
28699
|
-
}
|
|
28700
|
-
const temporalOverrideGuidance = temporalAwarenessEnabled ? TEMPORAL_AWARENESS_OVERRIDE_GUIDANCE : "";
|
|
28701
|
-
const cavemanWarning = cavemanTextCompressionEnabled ? CAVEMAN_COMPRESSION_WARNING : "";
|
|
28702
|
-
const languageDirective = buildPrimaryLanguageDirective(language);
|
|
28703
|
-
const languageGuidance = languageDirective ? `
|
|
28704
|
-
|
|
28705
|
-
${languageDirective}` : "";
|
|
28706
|
-
if (primaryOverride !== undefined) {
|
|
28707
|
-
return `${primaryOverride}${temporalOverrideGuidance}${cavemanWarning}${languageGuidance}`;
|
|
28708
|
-
}
|
|
28709
|
-
if (!ctxReduceCallable) {
|
|
28710
|
-
if (preset === "light") {
|
|
28711
|
-
return `## Magic Context
|
|
28712
|
-
|
|
28713
|
-
${LONG_TERM_PARTNER_FRAME}
|
|
28714
|
-
${PARTNER_FRAME_CLOSER_NO_REDUCE_LIGHT}
|
|
28715
|
-
|
|
28716
|
-
${BASE_INTRO_NO_REDUCE_LIGHT(memoryEnabled, dreamerEnabled, temporalAwarenessEnabled)}${cavemanWarning}${languageGuidance}`;
|
|
28717
|
-
}
|
|
28718
|
-
return `## Magic Context
|
|
28719
|
-
|
|
28720
|
-
${LONG_TERM_PARTNER_FRAME}
|
|
28721
|
-
${PARTNER_FRAME_CLOSER_NO_REDUCE}
|
|
28722
|
-
|
|
28723
|
-
${BASE_INTRO_NO_REDUCE(memoryEnabled, dreamerEnabled, temporalAwarenessEnabled)}${cavemanWarning}${languageGuidance}`;
|
|
28724
|
-
}
|
|
28725
|
-
if (preset === "light") {
|
|
28726
|
-
return `## Magic Context
|
|
28727
|
-
|
|
28728
|
-
${LONG_TERM_PARTNER_FRAME}
|
|
28729
|
-
${PARTNER_FRAME_CLOSER_REDUCE_LIGHT}
|
|
28730
|
-
|
|
28731
|
-
${BASE_INTRO_LIGHT(memoryEnabled, dreamerEnabled, temporalAwarenessEnabled)}${cavemanWarning}${languageGuidance}`;
|
|
28732
|
-
}
|
|
28733
|
-
return `## Magic Context
|
|
28734
|
-
|
|
28735
|
-
${LONG_TERM_PARTNER_FRAME}
|
|
28736
|
-
${PARTNER_FRAME_CLOSER_REDUCE}
|
|
28737
|
-
|
|
28738
|
-
${BASE_INTRO(memoryEnabled, dreamerEnabled, temporalAwarenessEnabled)}${cavemanWarning}${languageGuidance}`;
|
|
28739
|
-
}
|
|
28740
|
-
|
|
28741
|
-
// src/system-prompt.ts
|
|
28742
28904
|
var MAGIC_CONTEXT_MARKER = "## Magic Context";
|
|
28743
28905
|
var stickyDateBySession = new Map;
|
|
28744
28906
|
function buildMagicContextBlock(opts) {
|
|
@@ -29681,12 +29843,14 @@ var MAX_TRACKED_SESSIONS = 100;
|
|
|
29681
29843
|
function trackSessionForProject(projectIdentity, sessionId) {
|
|
29682
29844
|
activeContextHandlerSessions.delete(sessionId);
|
|
29683
29845
|
activeContextHandlerSessions.add(sessionId);
|
|
29684
|
-
|
|
29685
|
-
|
|
29686
|
-
sessions
|
|
29687
|
-
|
|
29846
|
+
if (isUsableProjectIdentity(projectIdentity)) {
|
|
29847
|
+
let sessions = sessionsByProject.get(projectIdentity);
|
|
29848
|
+
if (!sessions) {
|
|
29849
|
+
sessions = new Set;
|
|
29850
|
+
sessionsByProject.set(projectIdentity, sessions);
|
|
29851
|
+
}
|
|
29852
|
+
sessions.add(sessionId);
|
|
29688
29853
|
}
|
|
29689
|
-
sessions.add(sessionId);
|
|
29690
29854
|
while (activeContextHandlerSessions.size > MAX_TRACKED_SESSIONS) {
|
|
29691
29855
|
const oldest = activeContextHandlerSessions.values().next().value;
|
|
29692
29856
|
if (oldest === undefined || oldest === sessionId)
|
|
@@ -30444,6 +30608,8 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
30444
30608
|
}
|
|
30445
30609
|
const previousModelKey = liveModelBySession.get(sessionId);
|
|
30446
30610
|
const currentModelKey = resolvePiContextModelKey(ctx);
|
|
30611
|
+
if (options.cacheTtlConfig !== undefined)
|
|
30612
|
+
resolveSessionCacheTtl(options.db, sessionId, options.cacheTtlConfig, currentModelKey);
|
|
30447
30613
|
const modelChanged = previousModelKey !== undefined && currentModelKey !== undefined && piModelRefToCanonical(previousModelKey) !== piModelRefToCanonical(currentModelKey);
|
|
30448
30614
|
if (currentModelKey !== undefined) {
|
|
30449
30615
|
liveModelBySession.set(sessionId, currentModelKey);
|
|
@@ -30837,7 +31003,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
30837
31003
|
const tTodoCapture = performance.now();
|
|
30838
31004
|
try {
|
|
30839
31005
|
const sessionMetaForTodo = sessionMeta;
|
|
30840
|
-
if (!options.compactionOff && !sessionMetaForTodo.isSubagent && sessionMetaForTodo.lastTodoState !== "") {
|
|
31006
|
+
if (options.todowriteEnabled === true && !options.compactionOff && !sessionMetaForTodo.isSubagent && sessionMetaForTodo.lastTodoState !== "") {
|
|
30841
31007
|
const isCacheBustingForTodo = isCacheBusting || result.executedWorkThisPass;
|
|
30842
31008
|
outputMessages = injectSyntheticTodowriteForPi({
|
|
30843
31009
|
db: options.db,
|
|
@@ -34287,6 +34453,8 @@ ${c.content}
|
|
|
34287
34453
|
|
|
34288
34454
|
// ../plugin/src/shared/cache-ttl-display.ts
|
|
34289
34455
|
function resolveCacheTtlDisplay(args) {
|
|
34456
|
+
if (args.frozen)
|
|
34457
|
+
return args.frozen;
|
|
34290
34458
|
if (args.sessionModelKey && (!args.modelKey || args.sessionModelKey === args.modelKey) || !args.modelKey && !args.sessionModelKey && args.sessionValue !== "5m") {
|
|
34291
34459
|
return {
|
|
34292
34460
|
value: args.sessionValue || "5m",
|
|
@@ -34294,24 +34462,14 @@ function resolveCacheTtlDisplay(args) {
|
|
|
34294
34462
|
modelKey: args.modelKey ?? args.sessionModelKey ?? undefined
|
|
34295
34463
|
};
|
|
34296
34464
|
}
|
|
34297
|
-
|
|
34298
|
-
|
|
34299
|
-
|
|
34300
|
-
|
|
34301
|
-
modelKey: args.modelKey
|
|
34302
|
-
};
|
|
34303
|
-
}
|
|
34304
|
-
const matched = resolveModelConfigValue(args.configured, args.modelKey);
|
|
34305
|
-
if (matched) {
|
|
34306
|
-
return { value: matched.value, source: "config", modelKey: args.modelKey };
|
|
34307
|
-
}
|
|
34308
|
-
return {
|
|
34309
|
-
value: args.configured.default ?? "5m",
|
|
34310
|
-
source: "default",
|
|
34311
|
-
modelKey: args.modelKey
|
|
34312
|
-
};
|
|
34465
|
+
const resolved = resolveModelCacheTtl(args.configured, args.modelKey);
|
|
34466
|
+
if (resolved.source === "default" && typeof args.configured === "string" && args.configuredExplicitly)
|
|
34467
|
+
return { ...resolved, source: "config" };
|
|
34468
|
+
return resolved;
|
|
34313
34469
|
}
|
|
34314
34470
|
function formatCacheTtlDisplay(display) {
|
|
34471
|
+
if (display.source === "OpenAI GPT-5.6+ default")
|
|
34472
|
+
return `Cache TTL: ${display.value} (${display.source})`;
|
|
34315
34473
|
if (display.source === "session")
|
|
34316
34474
|
return `Cache TTL: ${display.value} (session)`;
|
|
34317
34475
|
if (display.source === "config") {
|
|
@@ -34867,7 +35025,7 @@ function buildStatusView(source, options) {
|
|
|
34867
35025
|
// package.json
|
|
34868
35026
|
var package_default = {
|
|
34869
35027
|
name: "@cortexkit/pi-magic-context",
|
|
34870
|
-
version: "0.44.
|
|
35028
|
+
version: "0.44.1",
|
|
34871
35029
|
type: "module",
|
|
34872
35030
|
description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
|
|
34873
35031
|
main: "dist/index.js",
|
|
@@ -35279,6 +35437,7 @@ ${safeStringify(tool.parameters)}`);
|
|
|
35279
35437
|
sessionId
|
|
35280
35438
|
});
|
|
35281
35439
|
const cacheTtlDisplay = resolveCacheTtlDisplay({
|
|
35440
|
+
frozen: readSessionCacheTtl(deps.db, sessionId),
|
|
35282
35441
|
configured: deps.cacheTtlConfig ?? "5m",
|
|
35283
35442
|
configuredExplicitly: deps.cacheTtlConfigured === true,
|
|
35284
35443
|
modelKey,
|
|
@@ -36188,7 +36347,7 @@ function persistPiMessageEndModelMeta(args) {
|
|
|
36188
36347
|
const modelKey = canonicalPiModelKey(msg.provider, msg.model);
|
|
36189
36348
|
if (!recordPiLiveModel(args.sessionId, modelKey, msg.timestamp))
|
|
36190
36349
|
return;
|
|
36191
|
-
const cacheTtl =
|
|
36350
|
+
const cacheTtl = resolveSessionCacheTtl(args.db, args.sessionId, args.cacheTtlConfig, modelKey).value;
|
|
36192
36351
|
const currentMeta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
36193
36352
|
updateSessionMeta(args.db, args.sessionId, {
|
|
36194
36353
|
...currentMeta.cacheTtl === cacheTtl ? {} : { cacheTtl },
|
|
@@ -36254,6 +36413,13 @@ function info(message, data) {
|
|
|
36254
36413
|
function warn(message, data) {
|
|
36255
36414
|
log(`${PREFIX2} WARN ${message}`, data);
|
|
36256
36415
|
}
|
|
36416
|
+
var loggedNoProjectIdentityDirs = new Set;
|
|
36417
|
+
function logNoProjectIdentityOnce(directory) {
|
|
36418
|
+
if (loggedNoProjectIdentityDirs.has(directory))
|
|
36419
|
+
return;
|
|
36420
|
+
loggedNoProjectIdentityDirs.add(directory);
|
|
36421
|
+
info(`no project identity for ${directory}: it is not treated as a project, so memory, search, ` + "embeddings and the dreamer stay off here. Start Pi inside a project folder, or set " + "`allow_home_project: true` in the user-level magic-context.jsonc to give home sessions their own project.");
|
|
36422
|
+
}
|
|
36257
36423
|
var migratedConfigDirs = new Set;
|
|
36258
36424
|
var loggedPiConfigDirs = new Set;
|
|
36259
36425
|
function ensureConfigLocationsMigrated(dir) {
|
|
@@ -36294,6 +36460,14 @@ function claimProtectedTagsDeprecationNoticeOnce() {
|
|
|
36294
36460
|
function resetClaimedProtectedTagsDeprecationNoticeForTesting() {
|
|
36295
36461
|
protectedTagsDeprecationClaimed = false;
|
|
36296
36462
|
}
|
|
36463
|
+
function registerConfiguredTodoLifecycle(pi, options) {
|
|
36464
|
+
if (!options.configured)
|
|
36465
|
+
return;
|
|
36466
|
+
registerTodoStateLifecycle(pi, {
|
|
36467
|
+
readLastTodoState: options.readLastTodoState
|
|
36468
|
+
});
|
|
36469
|
+
return options.overlay ? registerTodoOverlay(pi, { readLastTodoState: options.readLastTodoState }) : undefined;
|
|
36470
|
+
}
|
|
36297
36471
|
var __test = {
|
|
36298
36472
|
logPiConfigLoad,
|
|
36299
36473
|
resetLoggedPiConfigDirs() {
|
|
@@ -36475,7 +36649,7 @@ function resolveHistorianFromConfig(config, harness = PI_HARNESS_KIND, modelRegi
|
|
|
36475
36649
|
model: resolved.primary,
|
|
36476
36650
|
fallbackModels: resolved.fallbacks
|
|
36477
36651
|
}
|
|
36478
|
-
], modelRegistry)[0] : undefined;
|
|
36652
|
+
], modelRegistry, harness)[0] : undefined;
|
|
36479
36653
|
const primary = validated ? typeof validated.model === "string" ? { model: validated.model } : validated.model : resolved.primary;
|
|
36480
36654
|
const model = primary?.model;
|
|
36481
36655
|
if (!model)
|
|
@@ -36547,7 +36721,7 @@ async function src_default(pi) {
|
|
|
36547
36721
|
mmapSizeMb: bootConfig.config.sqlite.mmap_size_mb
|
|
36548
36722
|
});
|
|
36549
36723
|
const storageDir = getMagicContextStorageDir();
|
|
36550
|
-
const dbPath =
|
|
36724
|
+
const dbPath = join11(storageDir, "context.db");
|
|
36551
36725
|
let openFailureCause = null;
|
|
36552
36726
|
const openStorage = async () => {
|
|
36553
36727
|
try {
|
|
@@ -36652,7 +36826,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36652
36826
|
const projectIdentity = resolveProjectIdentityForSession(projectDir, config.allow_home_project) ?? "";
|
|
36653
36827
|
if (projectIdentity)
|
|
36654
36828
|
seenDreamerProjectIdentities.add(projectIdentity);
|
|
36655
|
-
info(`loaded v${PLUGIN_VERSION} | harness=${PI_HARNESS_KIND} (via ${PI_HARNESS_DETECTION.via}) | db=${dbPath} | ` + `project=${projectIdentity} | dir=${projectDir}`);
|
|
36829
|
+
info(`loaded v${PLUGIN_VERSION} | harness=${PI_HARNESS_KIND} (via ${PI_HARNESS_DETECTION.via}) | db=${dbPath} | ` + `project=${projectIdentity || "(none)"} | dir=${projectDir}`);
|
|
36656
36830
|
const compactionOff = !isCompactionEnabled(config);
|
|
36657
36831
|
setCtxReduceRegisteredGlobally(!compactionOff);
|
|
36658
36832
|
if (!compactionOff) {
|
|
@@ -36687,7 +36861,11 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36687
36861
|
return;
|
|
36688
36862
|
}
|
|
36689
36863
|
await ensureProjectRegisteredFromPiDirectory(projectDir, db);
|
|
36690
|
-
|
|
36864
|
+
if (isUsableProjectIdentity(projectIdentity)) {
|
|
36865
|
+
info(`registered embedding config for project ${projectIdentity}`);
|
|
36866
|
+
} else {
|
|
36867
|
+
logNoProjectIdentityOnce(projectDir);
|
|
36868
|
+
}
|
|
36691
36869
|
const projectDepsByDir = new Map;
|
|
36692
36870
|
const liveReaders = new Map;
|
|
36693
36871
|
function liveReaderFor(dir, boot) {
|
|
@@ -36711,6 +36889,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36711
36889
|
}
|
|
36712
36890
|
const buildContextOptions = (cfg, hist, auto) => ({
|
|
36713
36891
|
db: database,
|
|
36892
|
+
cacheTtlConfig: cfg.cache_ttl,
|
|
36714
36893
|
smartDrops: cfg.smart_drops === true,
|
|
36715
36894
|
protectedTokens: cfg.protected_tokens,
|
|
36716
36895
|
protectedTokenTierOverrides: getProtectedTokensTierOverrides(cfg) ?? {},
|
|
@@ -36737,6 +36916,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36737
36916
|
language: cfg.language,
|
|
36738
36917
|
autoSearch: auto,
|
|
36739
36918
|
resolveForProject: resolveContextOptionsForProject,
|
|
36919
|
+
todowriteEnabled: cfg.todowrite.enabled,
|
|
36740
36920
|
compactionOff,
|
|
36741
36921
|
allowHomeProject: cfg.allow_home_project,
|
|
36742
36922
|
maybeAutoEmbedSession: (sessionId, dir, identity) => {
|
|
@@ -36814,6 +36994,10 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36814
36994
|
function syncDreamerProjectRegistration(current, modelRegistry) {
|
|
36815
36995
|
if (sessionShuttingDown)
|
|
36816
36996
|
return;
|
|
36997
|
+
if (!isUsableProjectIdentity(current.projectIdentity)) {
|
|
36998
|
+
logNoProjectIdentityOnce(current.projectDir);
|
|
36999
|
+
return;
|
|
37000
|
+
}
|
|
36817
37001
|
seenDreamerProjectIdentities.add(current.projectIdentity);
|
|
36818
37002
|
if (!current.dreamerConfig) {
|
|
36819
37003
|
unregisterPiDreamerProject({
|
|
@@ -36849,8 +37033,8 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36849
37033
|
});
|
|
36850
37034
|
}
|
|
36851
37035
|
registerPiDroppedInputGuard(pi);
|
|
36852
|
-
const todowriteEnabled = bootProjectDeps.config.todowrite.enabled
|
|
36853
|
-
const todowriteOverlayEnabled = todowriteEnabled && bootProjectDeps.config.todowrite.overlay
|
|
37036
|
+
const todowriteEnabled = bootProjectDeps.config.todowrite.enabled;
|
|
37037
|
+
const todowriteOverlayEnabled = todowriteEnabled && bootProjectDeps.config.todowrite.overlay;
|
|
36854
37038
|
registerMagicContextTools(pi, {
|
|
36855
37039
|
db,
|
|
36856
37040
|
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
@@ -36896,12 +37080,11 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36896
37080
|
});
|
|
36897
37081
|
});
|
|
36898
37082
|
const readLastTodoState = (sessionId) => getOrCreateSessionMeta(db, sessionId).lastTodoState;
|
|
36899
|
-
|
|
36900
|
-
|
|
36901
|
-
|
|
36902
|
-
const todoOverlay = todowriteOverlayEnabled ? registerTodoOverlay(pi, {
|
|
37083
|
+
const todoOverlay = registerConfiguredTodoLifecycle(pi, {
|
|
37084
|
+
configured: todowriteEnabled,
|
|
37085
|
+
overlay: bootProjectDeps.config.todowrite.overlay,
|
|
36903
37086
|
readLastTodoState
|
|
36904
|
-
})
|
|
37087
|
+
});
|
|
36905
37088
|
info(todowriteOverlayEnabled ? "registered todowrite overlay" : "registered todowrite overlay: DISABLED (todowrite.enabled=false or todowrite.overlay=false)");
|
|
36906
37089
|
registerPiContextHandler(pi, bootProjectDeps.contextOptions);
|
|
36907
37090
|
info(bootProjectDeps.historianConfig ? `registered historian trigger (model=${bootProjectDeps.historianConfig.model}, executeThreshold=${formatExecuteThresholdForLog(bootProjectDeps.historianConfig.executeThresholdPercentage)})` : "registered historian trigger: DISABLED (configure the active harness's historian model in magic-context.jsonc)");
|
|
@@ -36954,7 +37137,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36954
37137
|
const registry = activeModelRegistry;
|
|
36955
37138
|
if (!registry)
|
|
36956
37139
|
return;
|
|
36957
|
-
const tasks = validatePiDreamerModels(buildDreamTaskRuntimeConfigs(current.config.dreamer, PI_HARNESS_KIND, current.config.language, current.config.mural.model), registry);
|
|
37140
|
+
const tasks = validatePiDreamerModels(buildDreamTaskRuntimeConfigs(current.config.dreamer, PI_HARNESS_KIND, current.config.language, current.config.mural.model), registry, PI_HARNESS_KIND);
|
|
36958
37141
|
const empty = tasks.filter((task) => task.modelChainUnavailable).map((task) => task.task);
|
|
36959
37142
|
if (!resolveHistorianFromConfig(current.config, PI_HARNESS_KIND, registry) && current.historianConfig)
|
|
36960
37143
|
empty.push("historian");
|
|
@@ -37441,6 +37624,7 @@ export {
|
|
|
37441
37624
|
handlePiSessionBeforeCompact,
|
|
37442
37625
|
persistPiMessageEndModelMeta,
|
|
37443
37626
|
persistPiPressureFromMessageEnd,
|
|
37627
|
+
registerConfiguredTodoLifecycle,
|
|
37444
37628
|
resetClaimedProtectedTagsDeprecationNoticeForTesting,
|
|
37445
37629
|
resolveDreamerFromConfig,
|
|
37446
37630
|
resolveHistorianFromConfig,
|