@cortexkit/pi-magic-context 0.43.2 → 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-bfd52y8p.js → index-59dmj4zs.js} +26 -7
- package/dist/{index-5v60m046.js → index-5fw91enm.js} +1 -1
- package/dist/{index-17102c1m.js → index-97e5fzy3.js} +1 -1
- package/dist/{index-bkrh6jhp.js → index-mwpk0wn9.js} +738 -458
- package/dist/{index-mea04n1j.js → index-nm3c0sn8.js} +191 -37
- package/dist/index.js +1754 -792
- package/dist/{message-time-backfill-f0v3yvza.js → message-time-backfill-5yrp95cx.js} +3 -3
- package/dist/{read-session-chunk-ky2sprnf.js → read-session-chunk-ka7n4kah.js} +6 -2
- package/dist/{safe-notification-target-d7f3t5qk.js → safe-notification-target-y3hg2m7p.js} +2 -2
- package/dist/subagent-entry.js +6 -6
- package/package.json +4 -2
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,40 +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
|
-
drainMirrorPages,
|
|
104
|
-
parseCompartmentOutput,
|
|
105
|
-
resolveWorkspaceShareCategories,
|
|
106
|
-
resolveWorkspaceIdentitySet,
|
|
107
|
-
expandWorkspaceIdentitySetWithAliases,
|
|
108
|
-
sourceNameForMemory,
|
|
109
|
-
computeWorkspaceEpochFingerprint,
|
|
110
|
-
readProjectDocsCanonical,
|
|
111
77
|
MAX_EXECUTE_THRESHOLD,
|
|
112
78
|
escalationBands,
|
|
113
79
|
HYGIENE_PROVIDER_UNITS_VERSION,
|
|
@@ -116,6 +82,10 @@ import {
|
|
|
116
82
|
computeProtectionWindow,
|
|
117
83
|
readEpochFloorSnapshot,
|
|
118
84
|
getProtectionWindowForSession,
|
|
85
|
+
persistCachedM0,
|
|
86
|
+
clearCachedM0M1,
|
|
87
|
+
readReplayDocument,
|
|
88
|
+
updateReplayDocument,
|
|
119
89
|
isProviderOverflowFailClosedProven,
|
|
120
90
|
describeProtectedTailDrainBudgetSkip,
|
|
121
91
|
loadProtectedTailMeta,
|
|
@@ -172,8 +142,8 @@ import {
|
|
|
172
142
|
clearDetectedContextLimit,
|
|
173
143
|
getStrippedPlaceholderIds,
|
|
174
144
|
applyStrippedPlaceholderDelta,
|
|
175
|
-
NEWEST_REASONING_BEARING_ASSISTANT,
|
|
176
145
|
THINKING_BINDING_RECOVERY_FROZEN_PREFIX,
|
|
146
|
+
THINKING_BINDING_STRIP_ORDER_END_MARKER,
|
|
177
147
|
thinkingBindingRecoveryFrozenId,
|
|
178
148
|
getThinkingBindingRecoveryTarget,
|
|
179
149
|
armThinkingBindingRecovery,
|
|
@@ -192,6 +162,45 @@ import {
|
|
|
192
162
|
setSessionWorkMetrics,
|
|
193
163
|
getSessionWorkMetrics,
|
|
194
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,
|
|
195
204
|
BoundedSessionMap,
|
|
196
205
|
registerLkgPersistence,
|
|
197
206
|
signatureForFields,
|
|
@@ -229,11 +238,6 @@ import {
|
|
|
229
238
|
getMemoryMutationsForRenderByProjects,
|
|
230
239
|
getMaxMemoryMutationId,
|
|
231
240
|
getMaxMemoryMutationIdForProjects,
|
|
232
|
-
getOrCreateSessionMeta,
|
|
233
|
-
updateSessionMeta,
|
|
234
|
-
advanceToolReclaimWatermark,
|
|
235
|
-
retryPendingSessionCleanups,
|
|
236
|
-
retryPendingRustSessionCleanupsForProject,
|
|
237
241
|
getNotes,
|
|
238
242
|
getSessionNotes,
|
|
239
243
|
getPendingSmartNotes,
|
|
@@ -372,6 +376,8 @@ import {
|
|
|
372
376
|
ensureProjectRegisteredFromPiDirectory,
|
|
373
377
|
resolvePiHarnessDetection,
|
|
374
378
|
resolvePiHarnessKind,
|
|
379
|
+
MEMORY_MURAL_BLOCK,
|
|
380
|
+
buildMagicContextSection,
|
|
375
381
|
resolveMuralWire,
|
|
376
382
|
updateCompactionMarkerAfterPublication,
|
|
377
383
|
COMPARTMENT_RENDER_EPOCH,
|
|
@@ -402,7 +408,7 @@ import {
|
|
|
402
408
|
registerTodoStateLifecycle,
|
|
403
409
|
syncCtxMemoryToolEnabled,
|
|
404
410
|
registerMagicContextTools
|
|
405
|
-
} from "./index-
|
|
411
|
+
} from "./index-mwpk0wn9.js";
|
|
406
412
|
import {
|
|
407
413
|
CTX_REDUCE_KEEP,
|
|
408
414
|
newestCtxReduceTagNumbers,
|
|
@@ -481,6 +487,7 @@ import {
|
|
|
481
487
|
claimOpenCodeDbDiagnosticOnce,
|
|
482
488
|
Database,
|
|
483
489
|
closeQuietly,
|
|
490
|
+
RAW_SUMMARY_TEXT_MAX_CHARS,
|
|
484
491
|
completedToolArcCrossesBoundary,
|
|
485
492
|
estimateTrueRawMessageTokens,
|
|
486
493
|
buildToolArcs,
|
|
@@ -497,12 +504,15 @@ import {
|
|
|
497
504
|
localBudget,
|
|
498
505
|
calibrationForModelKey,
|
|
499
506
|
historyLocalBudget,
|
|
507
|
+
SKELETON_REAL_INPUT_MAX_BYTES,
|
|
508
|
+
toolInputStringBytes,
|
|
500
509
|
setRawMessageProvider2,
|
|
501
510
|
withRawMessageProvider2,
|
|
502
511
|
cleanUserText2,
|
|
503
512
|
withRawSessionMessageCache2,
|
|
504
513
|
readRawSessionMessages2,
|
|
505
514
|
getRawSessionMessageOrdinalCount2,
|
|
515
|
+
visitRawSessionMessages2,
|
|
506
516
|
readRawSessionMessageRange2,
|
|
507
517
|
primeTailRawMessageCache2,
|
|
508
518
|
getCachedAbsoluteMessageCount2,
|
|
@@ -512,14 +522,14 @@ import {
|
|
|
512
522
|
getRawSessionTagKeysThrough2,
|
|
513
523
|
getLegacyProtectedTailStartOrdinal2,
|
|
514
524
|
readSessionChunk2
|
|
515
|
-
} from "./index-
|
|
525
|
+
} from "./index-nm3c0sn8.js";
|
|
516
526
|
import {
|
|
517
527
|
pushNotification2
|
|
518
528
|
} from "./index-b3eqj1g6.js";
|
|
519
|
-
import"./index-
|
|
529
|
+
import"./index-5fw91enm.js";
|
|
520
530
|
import {
|
|
521
531
|
logSlowWriteTransaction
|
|
522
|
-
} from "./index-
|
|
532
|
+
} from "./index-97e5fzy3.js";
|
|
523
533
|
import {
|
|
524
534
|
__toESM
|
|
525
535
|
} from "./index-22jkk6wg.js";
|
|
@@ -527,7 +537,7 @@ import {
|
|
|
527
537
|
// src/index.ts
|
|
528
538
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
529
539
|
import { createRequire as createRequire2 } from "node:module";
|
|
530
|
-
import { join as
|
|
540
|
+
import { join as join11, resolve as resolve4 } from "node:path";
|
|
531
541
|
|
|
532
542
|
// ../plugin/src/config/live-snapshot.ts
|
|
533
543
|
import { createHash } from "node:crypto";
|
|
@@ -1141,7 +1151,9 @@ var OVERFLOW_PATTERNS = [
|
|
|
1141
1151
|
/prompt too long; exceeded (?:max )?context length/i,
|
|
1142
1152
|
/too large for model with \d+ maximum context length/i,
|
|
1143
1153
|
/model_context_window_exceeded/i,
|
|
1144
|
-
/context size has been exceeded/i
|
|
1154
|
+
/context size has been exceeded/i,
|
|
1155
|
+
/prepared prompt exceeds engine max_context/i,
|
|
1156
|
+
/prompt exceeds (?:the )?.{0,32}\bmax_context\b/i
|
|
1145
1157
|
];
|
|
1146
1158
|
var LIMIT_EXTRACTION_PATTERNS = [
|
|
1147
1159
|
{ pattern: /maximum prompt length is (\d+)/i, provenance: "prompt_only" },
|
|
@@ -1162,11 +1174,15 @@ var LIMIT_EXTRACTION_PATTERNS = [
|
|
|
1162
1174
|
pattern: />\s*(\d+)\s*(?:tokens?\s*)?(?:maximum|max|limit)\b/i,
|
|
1163
1175
|
provenance: "prompt_only"
|
|
1164
1176
|
},
|
|
1177
|
+
{ pattern: /prepared prompt exceeds engine max_context\s+(\d+)/i, provenance: "unknown" },
|
|
1178
|
+
{ pattern: /prompt exceeds (?:the )?.{0,32}\bmax_context\s+(\d+)/i, provenance: "unknown" },
|
|
1165
1179
|
{ pattern: /max(?:imum)?.*context.*?(\d+)/i, provenance: "unknown" }
|
|
1166
1180
|
];
|
|
1167
1181
|
var MIN_PLAUSIBLE_LIMIT = 1024;
|
|
1168
1182
|
var MAX_PLAUSIBLE_LIMIT = 1e7;
|
|
1169
1183
|
var THINKING_BINDING_MISMATCH_PATTERN = /bound to a different conversation/i;
|
|
1184
|
+
var THINKING_BINDING_FAILING_PATH_PATTERN = /^\s*(messages\.\d+\.content\.\d+):/;
|
|
1185
|
+
var THINKING_BINDING_FIRST_CHANGED_PATTERN = /first at `?(messages\.\d+\.content\.\d+)`?/;
|
|
1170
1186
|
function extractErrorMessage(error) {
|
|
1171
1187
|
if (!error)
|
|
1172
1188
|
return "";
|
|
@@ -1195,29 +1211,6 @@ function extractErrorMessage(error) {
|
|
|
1195
1211
|
}
|
|
1196
1212
|
return String(error);
|
|
1197
1213
|
}
|
|
1198
|
-
function extractThinkingBindingMessageId(error) {
|
|
1199
|
-
if (!error || typeof error !== "object")
|
|
1200
|
-
return;
|
|
1201
|
-
const seen = new Set;
|
|
1202
|
-
const queue = [error];
|
|
1203
|
-
while (queue.length > 0) {
|
|
1204
|
-
const current = queue.shift();
|
|
1205
|
-
if (!current || seen.has(current))
|
|
1206
|
-
continue;
|
|
1207
|
-
seen.add(current);
|
|
1208
|
-
const record = current;
|
|
1209
|
-
for (const key of ["message_id", "messageID", "messageId"]) {
|
|
1210
|
-
const value = record[key];
|
|
1211
|
-
if (typeof value === "string" && value.length > 0)
|
|
1212
|
-
return value;
|
|
1213
|
-
}
|
|
1214
|
-
for (const value of Object.values(record)) {
|
|
1215
|
-
if (value && typeof value === "object")
|
|
1216
|
-
queue.push(value);
|
|
1217
|
-
}
|
|
1218
|
-
}
|
|
1219
|
-
return;
|
|
1220
|
-
}
|
|
1221
1214
|
function extractExplicitHttpStatus(error) {
|
|
1222
1215
|
if (!error || typeof error !== "object")
|
|
1223
1216
|
return;
|
|
@@ -1247,13 +1240,20 @@ function detectThinkingBindingMismatch(error) {
|
|
|
1247
1240
|
if (explicitStatus !== undefined && explicitStatus !== 400 || !THINKING_BINDING_MISMATCH_PATTERN.test(message)) {
|
|
1248
1241
|
return { isBindingMismatch: false };
|
|
1249
1242
|
}
|
|
1250
|
-
const
|
|
1243
|
+
const failingBlockPath = THINKING_BINDING_FAILING_PATH_PATTERN.exec(message)?.[1];
|
|
1244
|
+
const firstChangedPath = THINKING_BINDING_FIRST_CHANGED_PATTERN.exec(message)?.[1];
|
|
1251
1245
|
return {
|
|
1252
1246
|
isBindingMismatch: true,
|
|
1253
1247
|
matchedPattern: "bound to a different conversation",
|
|
1254
|
-
...
|
|
1248
|
+
...failingBlockPath ? { failingBlockPath } : {},
|
|
1249
|
+
...firstChangedPath ? { firstChangedPath } : {}
|
|
1255
1250
|
};
|
|
1256
1251
|
}
|
|
1252
|
+
function isPrefixBoundThinkingModel(providerID, modelID) {
|
|
1253
|
+
if (providerID?.toLowerCase() !== "anthropic" || !modelID)
|
|
1254
|
+
return false;
|
|
1255
|
+
return isFable51ThinkingBindingModel(providerID, modelID) || /(?:^|[-_.])opus[-_.]?5[-_.]5(?:$|[-_.])/i.test(modelID);
|
|
1256
|
+
}
|
|
1257
1257
|
function isFable51ThinkingBindingModel(providerID, modelID) {
|
|
1258
1258
|
if (providerID?.toLowerCase() !== "anthropic" || !modelID)
|
|
1259
1259
|
return false;
|
|
@@ -1325,6 +1325,67 @@ function parseReportedLimit(message) {
|
|
|
1325
1325
|
return;
|
|
1326
1326
|
}
|
|
1327
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
|
+
|
|
1328
1389
|
// ../plugin/src/features/magic-context/session-project-backfill.ts
|
|
1329
1390
|
import { randomUUID } from "node:crypto";
|
|
1330
1391
|
import { existsSync } from "node:fs";
|
|
@@ -1586,6 +1647,31 @@ async function runSessionProjectBackfill(db, source, options = {}) {
|
|
|
1586
1647
|
return result;
|
|
1587
1648
|
}
|
|
1588
1649
|
|
|
1650
|
+
// ../plugin/src/features/magic-context/storage-unavailable-reason.ts
|
|
1651
|
+
function describeStorageUnavailability(fallbackCause) {
|
|
1652
|
+
const migration = getMigrationOnOpenRefusal();
|
|
1653
|
+
const blockingProcesses = migration?.blockingProcesses ?? migration?.serverPids.map((pid) => ({ kind: "process", pid })) ?? [];
|
|
1654
|
+
if (migration && (blockingProcesses.length > 0 || migration.unreadableFile)) {
|
|
1655
|
+
return {
|
|
1656
|
+
kind: "migration_guard",
|
|
1657
|
+
persistedVersion: migration.persistedVersion,
|
|
1658
|
+
supportedVersion: migration.supportedVersion,
|
|
1659
|
+
blockingProcesses,
|
|
1660
|
+
...migration.unreadableFile ? { unreadableFile: migration.unreadableFile } : {},
|
|
1661
|
+
...migration.unreadableArm ? { unreadableArm: migration.unreadableArm } : {}
|
|
1662
|
+
};
|
|
1663
|
+
}
|
|
1664
|
+
const fence = getSchemaFenceRejection();
|
|
1665
|
+
if (fence) {
|
|
1666
|
+
return {
|
|
1667
|
+
kind: "schema_fence",
|
|
1668
|
+
persistedVersion: fence.persistedVersion,
|
|
1669
|
+
supportedVersion: fence.supportedVersion
|
|
1670
|
+
};
|
|
1671
|
+
}
|
|
1672
|
+
return { kind: "storage_failure", cause: fallbackCause };
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1589
1675
|
// ../plugin/src/features/magic-context/v22-deferred-backfill.ts
|
|
1590
1676
|
import { createHash as createHash2 } from "node:crypto";
|
|
1591
1677
|
import { realpathSync } from "node:fs";
|
|
@@ -1877,141 +1963,6 @@ function producerSourceLocalBudget(providerTokens, modelKey) {
|
|
|
1877
1963
|
return ratio === 1 ? providerTokens : localBudget(providerTokens, ratio);
|
|
1878
1964
|
}
|
|
1879
1965
|
|
|
1880
|
-
// ../plugin/src/hooks/magic-context/event-resolvers.ts
|
|
1881
|
-
var DEFAULT_CONTEXT_LIMIT = 200000;
|
|
1882
|
-
function resolveCacheTtl(cacheTtl, modelKey) {
|
|
1883
|
-
if (typeof cacheTtl === "string") {
|
|
1884
|
-
return cacheTtl;
|
|
1885
|
-
}
|
|
1886
|
-
return resolveModelConfigOrDefault(cacheTtl, modelKey, cacheTtl.default ?? "5m");
|
|
1887
|
-
}
|
|
1888
|
-
var clampWarnSeen = new Set;
|
|
1889
|
-
function isFinitePositive(v) {
|
|
1890
|
-
return typeof v === "number" && Number.isFinite(v) && v > 0;
|
|
1891
|
-
}
|
|
1892
|
-
function* modelKeyLookupOrder(modelKey) {
|
|
1893
|
-
const slash = modelKey.indexOf("/");
|
|
1894
|
-
const providerRefs = slash >= 0 ? modelRefLookupOrder(modelKey) : [];
|
|
1895
|
-
let modelId = slash >= 0 ? modelKey.slice(slash + 1) : modelKey;
|
|
1896
|
-
while (modelId.length > 0) {
|
|
1897
|
-
for (const providerRef of providerRefs) {
|
|
1898
|
-
const providerSlash = providerRef.indexOf("/");
|
|
1899
|
-
yield `${providerRef.slice(0, providerSlash)}/${modelId}`;
|
|
1900
|
-
}
|
|
1901
|
-
yield modelId;
|
|
1902
|
-
const lastDash = modelId.lastIndexOf("-");
|
|
1903
|
-
if (lastDash <= 0)
|
|
1904
|
-
break;
|
|
1905
|
-
modelId = modelId.slice(0, lastDash);
|
|
1906
|
-
}
|
|
1907
|
-
}
|
|
1908
|
-
function resolveExecuteThresholdDetail(config, modelKey, fallback, options) {
|
|
1909
|
-
if (options?.tokensConfig && isFinitePositive(options.contextLimit)) {
|
|
1910
|
-
const contextLimit = options.contextLimit;
|
|
1911
|
-
const tokenMatch = resolveTokensMatchWithKey(options.tokensConfig, modelKey);
|
|
1912
|
-
if (tokenMatch && isFinitePositive(tokenMatch.value)) {
|
|
1913
|
-
const cap = contextLimit * (MAX_EXECUTE_THRESHOLD / 100);
|
|
1914
|
-
const effectiveTokens = Math.min(tokenMatch.value, cap);
|
|
1915
|
-
if (effectiveTokens < tokenMatch.value) {
|
|
1916
|
-
const dedupeKey = `${options.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${tokenMatch.value}|${cap}`;
|
|
1917
|
-
if (!clampWarnSeen.has(dedupeKey)) {
|
|
1918
|
-
clampWarnSeen.add(dedupeKey);
|
|
1919
|
-
const msg = `execute_threshold_tokens clamped: ${tokenMatch.value} → ${effectiveTokens} (${MAX_EXECUTE_THRESHOLD}% of ${contextLimit}) for ${modelKey ?? "default"}`;
|
|
1920
|
-
if (options.sessionId) {
|
|
1921
|
-
sessionLog(options.sessionId, `WARN: ${msg}`);
|
|
1922
|
-
} else {
|
|
1923
|
-
log(`[magic-context] WARN: ${msg}`);
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1927
|
-
const percentage = effectiveTokens / contextLimit * 100;
|
|
1928
|
-
const detail = {
|
|
1929
|
-
percentage: Math.min(percentage, MAX_EXECUTE_THRESHOLD),
|
|
1930
|
-
mode: "tokens",
|
|
1931
|
-
absoluteTokens: Math.floor(effectiveTokens),
|
|
1932
|
-
matchedKey: tokenMatch.matchedKey
|
|
1933
|
-
};
|
|
1934
|
-
if (effectiveTokens < tokenMatch.value) {
|
|
1935
|
-
detail.clamped = true;
|
|
1936
|
-
detail.configuredValue = tokenMatch.value;
|
|
1937
|
-
}
|
|
1938
|
-
return detail;
|
|
1939
|
-
}
|
|
1940
|
-
}
|
|
1941
|
-
let resolved;
|
|
1942
|
-
let matchedKey;
|
|
1943
|
-
if (typeof config === "number") {
|
|
1944
|
-
resolved = config;
|
|
1945
|
-
} else if (modelKey) {
|
|
1946
|
-
let matched;
|
|
1947
|
-
for (const candidate of modelKeyLookupOrder(modelKey)) {
|
|
1948
|
-
if (typeof config[candidate] === "number") {
|
|
1949
|
-
matched = config[candidate];
|
|
1950
|
-
matchedKey = candidate;
|
|
1951
|
-
break;
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
if (matched === undefined && typeof config.default === "number") {
|
|
1955
|
-
resolved = config.default;
|
|
1956
|
-
matchedKey = "default";
|
|
1957
|
-
} else {
|
|
1958
|
-
resolved = matched ?? fallback;
|
|
1959
|
-
}
|
|
1960
|
-
} else if (typeof config.default === "number") {
|
|
1961
|
-
resolved = config.default;
|
|
1962
|
-
matchedKey = "default";
|
|
1963
|
-
} else {
|
|
1964
|
-
resolved = fallback;
|
|
1965
|
-
}
|
|
1966
|
-
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
1967
|
-
resolved = fallback;
|
|
1968
|
-
}
|
|
1969
|
-
const cappedPercentage = Math.min(resolved, MAX_EXECUTE_THRESHOLD);
|
|
1970
|
-
const percentageClamped = cappedPercentage < resolved;
|
|
1971
|
-
if (percentageClamped) {
|
|
1972
|
-
const dedupeKey = `pct|${options?.sessionId ?? "__global__"}|${modelKey ?? "__default__"}|${resolved}`;
|
|
1973
|
-
if (!clampWarnSeen.has(dedupeKey)) {
|
|
1974
|
-
clampWarnSeen.add(dedupeKey);
|
|
1975
|
-
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)`;
|
|
1976
|
-
if (options?.sessionId) {
|
|
1977
|
-
sessionLog(options.sessionId, `WARN: ${msg}`);
|
|
1978
|
-
} else {
|
|
1979
|
-
log(`[magic-context] WARN: ${msg}`);
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
}
|
|
1983
|
-
const detail = {
|
|
1984
|
-
percentage: cappedPercentage,
|
|
1985
|
-
mode: "percentage",
|
|
1986
|
-
matchedKey
|
|
1987
|
-
};
|
|
1988
|
-
if (percentageClamped) {
|
|
1989
|
-
detail.clamped = true;
|
|
1990
|
-
detail.configuredValue = resolved;
|
|
1991
|
-
}
|
|
1992
|
-
return detail;
|
|
1993
|
-
}
|
|
1994
|
-
function resolveExecuteThreshold(config, modelKey, fallback, options) {
|
|
1995
|
-
return resolveExecuteThresholdDetail(config, modelKey, fallback, options).percentage;
|
|
1996
|
-
}
|
|
1997
|
-
function resolveTokensMatchWithKey(tokensConfig, modelKey) {
|
|
1998
|
-
if (!tokensConfig) {
|
|
1999
|
-
return;
|
|
2000
|
-
}
|
|
2001
|
-
if (modelKey) {
|
|
2002
|
-
for (const candidate of modelKeyLookupOrder(modelKey)) {
|
|
2003
|
-
const value = tokensConfig[candidate];
|
|
2004
|
-
if (typeof value === "number") {
|
|
2005
|
-
return { value, matchedKey: candidate };
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
}
|
|
2009
|
-
if (typeof tokensConfig.default === "number") {
|
|
2010
|
-
return { value: tokensConfig.default, matchedKey: "default" };
|
|
2011
|
-
}
|
|
2012
|
-
return;
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
1966
|
// ../plugin/src/hooks/magic-context/note-nudger.ts
|
|
2016
1967
|
var NOTE_NUDGE_COOLDOWN_MS = 15 * 60 * 1000;
|
|
2017
1968
|
var lastDeliveredAt = new Map;
|
|
@@ -2802,6 +2753,11 @@ var USER_FACING_FAILURES = {
|
|
|
2802
2753
|
sentence: "Memory maintenance could not reach its model.",
|
|
2803
2754
|
action: "Check the model connection, then run /ctx-dream again."
|
|
2804
2755
|
},
|
|
2756
|
+
dream_step_limit: {
|
|
2757
|
+
code: "MC-D10",
|
|
2758
|
+
sentence: "Memory maintenance stopped at its hidden agent step limit.",
|
|
2759
|
+
action: "This task needs less work per run; changing the model connection will not help."
|
|
2760
|
+
},
|
|
2805
2761
|
dream_empty_completion: {
|
|
2806
2762
|
code: "MC-D03",
|
|
2807
2763
|
sentence: "Memory maintenance received no usable response.",
|
|
@@ -2967,6 +2923,11 @@ var USER_FACING_FAILURES = {
|
|
|
2967
2923
|
sentence: "Magic Context is temporarily unavailable.",
|
|
2968
2924
|
action: "Retry in a moment."
|
|
2969
2925
|
},
|
|
2926
|
+
store_ahead_of_binary: {
|
|
2927
|
+
code: "MC-C13",
|
|
2928
|
+
sentence: "Magic Context refused to start: its store (store.db) was migrated by a newer ck-mc build than the one running.",
|
|
2929
|
+
action: "Update ck-mc, or roll back by restoring ck-mc together with context.db and store.db from the same backup."
|
|
2930
|
+
},
|
|
2970
2931
|
compaction_marker_missing: {
|
|
2971
2932
|
code: "MC-C11",
|
|
2972
2933
|
sentence: "The history boundary marker is missing from the OpenCode store, so requests carry the full session.",
|
|
@@ -2982,11 +2943,6 @@ var USER_FACING_FAILURES = {
|
|
|
2982
2943
|
sentence: "Memory authority is inconsistent between the host and module.",
|
|
2983
2944
|
action: "Run `ck doctor drain-authority` before changing Rust mode."
|
|
2984
2945
|
},
|
|
2985
|
-
rust_mode_unsupported: {
|
|
2986
|
-
code: "MC-S06",
|
|
2987
|
-
sentence: "Experimental Rust transform mode is not available on this OpenCode host.",
|
|
2988
|
-
action: 'Magic Context is running its TypeScript mode instead; set `transform_mode` to "ts" to stop requesting Rust.'
|
|
2989
|
-
},
|
|
2990
2946
|
dreamer_task_failing: {
|
|
2991
2947
|
code: "MC-S05",
|
|
2992
2948
|
sentence: "A background maintenance task keeps failing on its schedule.",
|
|
@@ -3018,6 +2974,7 @@ function renderCapabilityRefusal(capability) {
|
|
|
3018
2974
|
var DREAM_FAILURE_KEYS = {
|
|
3019
2975
|
provider_timeout: "dream_provider_timeout",
|
|
3020
2976
|
provider_error: "dream_provider_error",
|
|
2977
|
+
step_limit: "dream_step_limit",
|
|
3021
2978
|
empty_completion: "dream_empty_completion",
|
|
3022
2979
|
no_models: "dream_no_models",
|
|
3023
2980
|
child_aborted: "dream_child_aborted",
|
|
@@ -3047,8 +3004,14 @@ function renderEmbeddingFailure(failureClass, style = "markdown") {
|
|
|
3047
3004
|
return renderUserFacingFailure(EMBEDDING_FAILURE_KEYS[failureClass], style);
|
|
3048
3005
|
}
|
|
3049
3006
|
|
|
3007
|
+
// src/dreamer/index.ts
|
|
3008
|
+
import { homedir as homedir2 } from "node:os";
|
|
3009
|
+
import { parse, resolve as resolve3 } from "node:path";
|
|
3010
|
+
|
|
3050
3011
|
// ../plugin/src/features/magic-context/dreamer/open-opencode-db.ts
|
|
3051
3012
|
function openOpenCodeDb() {
|
|
3013
|
+
if (!harnessOwnsOpenCodeStore())
|
|
3014
|
+
return null;
|
|
3052
3015
|
const resolution = resolveOpenCodeDbPath();
|
|
3053
3016
|
const dbPath = resolution.path;
|
|
3054
3017
|
if (!openCodeDbPathExists(resolution)) {
|
|
@@ -3204,6 +3167,37 @@ class HiddenCompletionRefusal extends Error {
|
|
|
3204
3167
|
this.name = "HiddenCompletionRefusal";
|
|
3205
3168
|
}
|
|
3206
3169
|
}
|
|
3170
|
+
// ../plugin/src/v2/hooks/hidden-child.ts
|
|
3171
|
+
var HIDDEN_HISTORIAN_AGENT = "historian";
|
|
3172
|
+
var HIDDEN_DREAMER_AGENT = "dreamer-classifier";
|
|
3173
|
+
var HIDDEN_CURATE_AGENT = DREAMER_AGENT;
|
|
3174
|
+
var READ_TOOLS = ["read", "grep", "glob"];
|
|
3175
|
+
var AGENT_TOOLS = {
|
|
3176
|
+
[HIDDEN_HISTORIAN_AGENT]: [],
|
|
3177
|
+
[HIDDEN_DREAMER_AGENT]: [],
|
|
3178
|
+
[HIDDEN_CURATE_AGENT]: ["ctx_memory", "ctx_memory_list"],
|
|
3179
|
+
[DREAMER_MEMORY_MAPPER_AGENT]: READ_TOOLS,
|
|
3180
|
+
[DREAMER_PRIMER_INVESTIGATOR_AGENT]: [...READ_TOOLS, "ctx_search"],
|
|
3181
|
+
[DREAMER_RETROSPECTIVE_AGENT]: ["ctx_search"]
|
|
3182
|
+
};
|
|
3183
|
+
var AGENT_STEPS = {
|
|
3184
|
+
[HIDDEN_CURATE_AGENT]: 150,
|
|
3185
|
+
[DREAMER_MEMORY_MAPPER_AGENT]: 60,
|
|
3186
|
+
[DREAMER_DOCS_AGENT]: 60,
|
|
3187
|
+
[DREAMER_PRIMER_INVESTIGATOR_AGENT]: 40,
|
|
3188
|
+
[DREAMER_RETROSPECTIVE_AGENT]: 40
|
|
3189
|
+
};
|
|
3190
|
+
class HiddenAgentStepLimit extends Error {
|
|
3191
|
+
agent;
|
|
3192
|
+
cap;
|
|
3193
|
+
constructor(agent, cap) {
|
|
3194
|
+
super(`Hidden agent ${agent} exceeded its ${cap}-step limit`);
|
|
3195
|
+
this.name = "HiddenAgentStepLimit";
|
|
3196
|
+
this.agent = agent;
|
|
3197
|
+
this.cap = cap;
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
3200
|
+
|
|
3207
3201
|
// ../plugin/src/shared/assistant-message-extractor.ts
|
|
3208
3202
|
function asSessionMessage(value) {
|
|
3209
3203
|
if (!isRecord(value))
|
|
@@ -3302,6 +3296,14 @@ function copyPromptArgs(args, body) {
|
|
|
3302
3296
|
return { ...args, body: { ...body } };
|
|
3303
3297
|
}
|
|
3304
3298
|
var promptFailureDetails = new WeakMap;
|
|
3299
|
+
function isHostTimeoutError(error) {
|
|
3300
|
+
return error !== null && typeof error === "object" && error.name === "TimeoutError";
|
|
3301
|
+
}
|
|
3302
|
+
function isPromptTimeoutError(error) {
|
|
3303
|
+
if (isHostTimeoutError(error))
|
|
3304
|
+
return true;
|
|
3305
|
+
return error instanceof Error && /^prompt timed out after \d+ms$/.test(error.message);
|
|
3306
|
+
}
|
|
3305
3307
|
function getPromptFailureDetail(error) {
|
|
3306
3308
|
return error !== null && typeof error === "object" ? promptFailureDetails.get(error) ?? null : null;
|
|
3307
3309
|
}
|
|
@@ -3358,9 +3360,13 @@ function parseModelSuggestion(error) {
|
|
|
3358
3360
|
suggestion: suggestionMatch[1].trim()
|
|
3359
3361
|
};
|
|
3360
3362
|
}
|
|
3363
|
+
function externalAbortMessage(signal) {
|
|
3364
|
+
const reason = signal.reason;
|
|
3365
|
+
return `prompt aborted by external signal${reason instanceof Error && /^lease_(?:lost|expired):/.test(reason.message) ? `: ${reason.message}` : ""}`;
|
|
3366
|
+
}
|
|
3361
3367
|
async function promptWithTimeout(client, args, timeoutMs, signal, transport) {
|
|
3362
3368
|
if (signal?.aborted) {
|
|
3363
|
-
throw new Error(
|
|
3369
|
+
throw new Error(externalAbortMessage(signal));
|
|
3364
3370
|
}
|
|
3365
3371
|
const controller = new AbortController;
|
|
3366
3372
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -3380,7 +3386,7 @@ async function promptWithTimeout(client, args, timeoutMs, signal, transport) {
|
|
|
3380
3386
|
if (!transport || transport.childSessionId) {
|
|
3381
3387
|
await abortChildRun(client, transport?.childSessionId ?? args.path.id);
|
|
3382
3388
|
}
|
|
3383
|
-
throw new Error(
|
|
3389
|
+
throw new Error(externalAbortMessage(signal));
|
|
3384
3390
|
}
|
|
3385
3391
|
if (controller.signal.aborted) {
|
|
3386
3392
|
if (!transport || transport.childSessionId) {
|
|
@@ -3388,6 +3394,11 @@ async function promptWithTimeout(client, args, timeoutMs, signal, transport) {
|
|
|
3388
3394
|
}
|
|
3389
3395
|
throw new Error(`prompt timed out after ${timeoutMs}ms`);
|
|
3390
3396
|
}
|
|
3397
|
+
if (isHostTimeoutError(error)) {
|
|
3398
|
+
if (!transport || transport.childSessionId) {
|
|
3399
|
+
await abortChildRun(client, transport?.childSessionId ?? args.path.id);
|
|
3400
|
+
}
|
|
3401
|
+
}
|
|
3391
3402
|
throw error;
|
|
3392
3403
|
} finally {
|
|
3393
3404
|
clearTimeout(timeout);
|
|
@@ -3397,7 +3408,7 @@ async function promptWithTimeout(client, args, timeoutMs, signal, transport) {
|
|
|
3397
3408
|
if (!transport || transport.childSessionId) {
|
|
3398
3409
|
await abortChildRun(client, transport?.childSessionId ?? args.path.id);
|
|
3399
3410
|
}
|
|
3400
|
-
throw new Error(signal?.aborted ?
|
|
3411
|
+
throw new Error(signal?.aborted ? externalAbortMessage(signal) : `prompt timed out after ${timeoutMs}ms`);
|
|
3401
3412
|
}
|
|
3402
3413
|
}
|
|
3403
3414
|
async function abortChildRun(client, sessionId) {
|
|
@@ -3413,7 +3424,7 @@ async function abortChildRun(client, sessionId) {
|
|
|
3413
3424
|
}
|
|
3414
3425
|
}
|
|
3415
3426
|
function isNonRetryable(error, externalSignal) {
|
|
3416
|
-
if (externalSignal?.aborted)
|
|
3427
|
+
if (externalSignal?.aborted || error instanceof HiddenAgentStepLimit)
|
|
3417
3428
|
return true;
|
|
3418
3429
|
if (error instanceof Error) {
|
|
3419
3430
|
if (error.name === "AbortError")
|
|
@@ -3423,6 +3434,8 @@ function isNonRetryable(error, externalSignal) {
|
|
|
3423
3434
|
if (/^prompt timed out after \d+ms$/.test(error.message))
|
|
3424
3435
|
return true;
|
|
3425
3436
|
}
|
|
3437
|
+
if (isHostTimeoutError(error))
|
|
3438
|
+
return true;
|
|
3426
3439
|
if (detectOverflow(error).isOverflow)
|
|
3427
3440
|
return true;
|
|
3428
3441
|
return false;
|
|
@@ -3435,11 +3448,14 @@ function shortErr(error) {
|
|
|
3435
3448
|
}
|
|
3436
3449
|
function classifyPromptFailure(error, phase, externalSignal) {
|
|
3437
3450
|
const message = extractMessage(error);
|
|
3451
|
+
if (error instanceof HiddenAgentStepLimit)
|
|
3452
|
+
return "step_limit";
|
|
3438
3453
|
if (externalSignal?.aborted || message === "prompt aborted by external signal") {
|
|
3439
3454
|
return "child_aborted";
|
|
3440
3455
|
}
|
|
3441
|
-
if (/^prompt timed out after \d+ms$/.test(message))
|
|
3456
|
+
if (/^prompt timed out after \d+ms$/.test(message) || isHostTimeoutError(error)) {
|
|
3442
3457
|
return "provider_timeout";
|
|
3458
|
+
}
|
|
3443
3459
|
if (phase === "validation") {
|
|
3444
3460
|
if (/returned no (?:assistant )?output|no assistant output/i.test(message)) {
|
|
3445
3461
|
return "empty_completion";
|
|
@@ -3656,7 +3672,10 @@ async function promptSyncWithValidatedOutputRetry(client, args, options) {
|
|
|
3656
3672
|
}
|
|
3657
3673
|
}
|
|
3658
3674
|
log(`[${callContext}] all models exhausted; tried: ${failedAttempts.map((failure) => failure.attempt.label).join(", ")}; original error: ${shortErr(firstError)}; last error: ${shortErr(lastError)}`);
|
|
3659
|
-
|
|
3675
|
+
const cause = lastError ?? firstError;
|
|
3676
|
+
const exhausted = cause instanceof Error ? cause : new Error(String(cause ?? "All fallback models failed validation"));
|
|
3677
|
+
exhausted.message = `All models exhausted (${failedAttempts.map((failure) => failure.attempt.label).join(", ")}): ${exhausted.message}`;
|
|
3678
|
+
throwWithPromptFailure(exhausted, failedAttempts, args, timeoutMs, options.transport);
|
|
3660
3679
|
}
|
|
3661
3680
|
// ../plugin/src/shared/normalize-sdk-response.ts
|
|
3662
3681
|
function normalizeSDKResponse(response, fallback, options) {
|
|
@@ -3681,6 +3700,149 @@ function normalizeSDKResponse(response, fallback, options) {
|
|
|
3681
3700
|
}
|
|
3682
3701
|
return fallback;
|
|
3683
3702
|
}
|
|
3703
|
+
// ../plugin/src/shared/prompt-async-transport.ts
|
|
3704
|
+
var DEFAULT_POLL_INTERVAL_MS = 1000;
|
|
3705
|
+
var DEFAULT_START_GRACE_MS = 30000;
|
|
3706
|
+
var MESSAGE_WINDOW = 20;
|
|
3707
|
+
function sessionApi(client) {
|
|
3708
|
+
return client?.session;
|
|
3709
|
+
}
|
|
3710
|
+
function supportsPromptAsync(client) {
|
|
3711
|
+
const session = sessionApi(client);
|
|
3712
|
+
return typeof session?.promptAsync === "function" && typeof session?.status === "function" && typeof session?.messages === "function";
|
|
3713
|
+
}
|
|
3714
|
+
function createPromptAsyncTransport(client, childSessionId, options = {}) {
|
|
3715
|
+
if (!supportsPromptAsync(client))
|
|
3716
|
+
return;
|
|
3717
|
+
return Object.assign((request) => promptAsyncAndWaitForIdle(client, request, options), { childSessionId });
|
|
3718
|
+
}
|
|
3719
|
+
function infoOf(message) {
|
|
3720
|
+
const info = message?.info;
|
|
3721
|
+
return info && typeof info === "object" ? info : {};
|
|
3722
|
+
}
|
|
3723
|
+
function messageId(message) {
|
|
3724
|
+
const id = infoOf(message).id;
|
|
3725
|
+
return typeof id === "string" ? id : null;
|
|
3726
|
+
}
|
|
3727
|
+
function isSettledAssistant(message) {
|
|
3728
|
+
const info = infoOf(message);
|
|
3729
|
+
if (info.role !== "assistant")
|
|
3730
|
+
return false;
|
|
3731
|
+
return info.time?.completed != null || info.error != null || info.finish != null;
|
|
3732
|
+
}
|
|
3733
|
+
function unwrapData(response) {
|
|
3734
|
+
if (response && typeof response === "object" && "data" in response) {
|
|
3735
|
+
return response.data;
|
|
3736
|
+
}
|
|
3737
|
+
return response;
|
|
3738
|
+
}
|
|
3739
|
+
function describeRejection(error) {
|
|
3740
|
+
if (error instanceof Error)
|
|
3741
|
+
return error.message;
|
|
3742
|
+
try {
|
|
3743
|
+
return JSON.stringify(error);
|
|
3744
|
+
} catch {
|
|
3745
|
+
return String(error);
|
|
3746
|
+
}
|
|
3747
|
+
}
|
|
3748
|
+
function abortError(signal) {
|
|
3749
|
+
return signal.reason ?? new Error("prompt_async wait aborted");
|
|
3750
|
+
}
|
|
3751
|
+
function sleep(ms, signal) {
|
|
3752
|
+
return new Promise((resolve, reject) => {
|
|
3753
|
+
if (signal?.aborted) {
|
|
3754
|
+
reject(abortError(signal));
|
|
3755
|
+
return;
|
|
3756
|
+
}
|
|
3757
|
+
const onAbort = () => {
|
|
3758
|
+
clearTimeout(timer);
|
|
3759
|
+
reject(abortError(signal));
|
|
3760
|
+
};
|
|
3761
|
+
const timer = setTimeout(() => {
|
|
3762
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3763
|
+
resolve();
|
|
3764
|
+
}, ms);
|
|
3765
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
3766
|
+
});
|
|
3767
|
+
}
|
|
3768
|
+
async function readMessages(session, sessionId, directory, signal) {
|
|
3769
|
+
const response = await session.messages?.({
|
|
3770
|
+
path: { id: sessionId },
|
|
3771
|
+
query: { ...directory ? { directory } : {}, limit: MESSAGE_WINDOW },
|
|
3772
|
+
...signal ? { signal } : {}
|
|
3773
|
+
});
|
|
3774
|
+
const data = unwrapData(response);
|
|
3775
|
+
return Array.isArray(data) ? data : [];
|
|
3776
|
+
}
|
|
3777
|
+
async function readStatus(session, sessionId, directory, signal) {
|
|
3778
|
+
try {
|
|
3779
|
+
const response = await session.status?.({
|
|
3780
|
+
...directory ? { query: { directory } } : {},
|
|
3781
|
+
...signal ? { signal } : {}
|
|
3782
|
+
});
|
|
3783
|
+
if (response && typeof response === "object" && "error" in response) {
|
|
3784
|
+
if (response.error)
|
|
3785
|
+
return null;
|
|
3786
|
+
}
|
|
3787
|
+
const data = unwrapData(response);
|
|
3788
|
+
if (!data || typeof data !== "object")
|
|
3789
|
+
return null;
|
|
3790
|
+
const entry = data[sessionId];
|
|
3791
|
+
const type = entry?.type;
|
|
3792
|
+
return typeof type === "string" ? type : "idle";
|
|
3793
|
+
} catch (error) {
|
|
3794
|
+
if (signal?.aborted)
|
|
3795
|
+
throw error;
|
|
3796
|
+
return null;
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
async function promptAsyncAndWaitForIdle(client, request, options = {}) {
|
|
3800
|
+
const session = sessionApi(client);
|
|
3801
|
+
if (!session || !supportsPromptAsync(client)) {
|
|
3802
|
+
throw new Error("prompt_async transport is unavailable on this client");
|
|
3803
|
+
}
|
|
3804
|
+
const sessionId = request.path.id;
|
|
3805
|
+
const directory = request.query?.directory;
|
|
3806
|
+
const dir = typeof directory === "string" ? directory : undefined;
|
|
3807
|
+
const signal = request.signal;
|
|
3808
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
3809
|
+
const startGraceMs = options.startGraceMs ?? DEFAULT_START_GRACE_MS;
|
|
3810
|
+
const baseline = new Set((await readMessages(session, sessionId, dir, signal)).map(messageId).filter((id) => id !== null));
|
|
3811
|
+
const sent = await session.promptAsync?.(request);
|
|
3812
|
+
if (sent && typeof sent === "object" && "error" in sent) {
|
|
3813
|
+
const rejection = sent.error;
|
|
3814
|
+
if (rejection)
|
|
3815
|
+
throw new Error(`prompt_async was rejected: ${describeRejection(rejection)}`);
|
|
3816
|
+
}
|
|
3817
|
+
const sentAt = Date.now();
|
|
3818
|
+
let sawBusy = false;
|
|
3819
|
+
for (;; ) {
|
|
3820
|
+
await sleep(pollIntervalMs, signal);
|
|
3821
|
+
const status = await readStatus(session, sessionId, dir, signal);
|
|
3822
|
+
if (status === "busy" || status === "retry") {
|
|
3823
|
+
sawBusy = true;
|
|
3824
|
+
continue;
|
|
3825
|
+
}
|
|
3826
|
+
if (status === null)
|
|
3827
|
+
continue;
|
|
3828
|
+
const messages = await readMessages(session, sessionId, dir, signal);
|
|
3829
|
+
const last = messages.at(-1);
|
|
3830
|
+
const lastId = messageId(last);
|
|
3831
|
+
if (last && lastId !== null && !baseline.has(lastId) && isSettledAssistant(last))
|
|
3832
|
+
return;
|
|
3833
|
+
const fresh = messages.some((message) => {
|
|
3834
|
+
const id = messageId(message);
|
|
3835
|
+
return id !== null && !baseline.has(id);
|
|
3836
|
+
});
|
|
3837
|
+
if (sawBusy && fresh)
|
|
3838
|
+
return;
|
|
3839
|
+
if (Date.now() - sentAt >= startGraceMs) {
|
|
3840
|
+
if (fresh)
|
|
3841
|
+
return;
|
|
3842
|
+
throw new Error(`prompt_async did not start a run in child session ${sessionId} within ${startGraceMs}ms`);
|
|
3843
|
+
}
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3684
3846
|
// ../plugin/src/shared/summarize-child-stderr.ts
|
|
3685
3847
|
var MAX_CHILD_STDERR_SUMMARY_LENGTH = 500;
|
|
3686
3848
|
var CHILD_ERROR_LINE_PATTERN = /^(?:[A-Za-z]*Error|SqliteError|Error)\b[^\n]*/;
|
|
@@ -3779,6 +3941,15 @@ var HISTORIAN_AGENT = "historian";
|
|
|
3779
3941
|
var HISTORIAN_RECOMP_AGENT = "historian-recomp";
|
|
3780
3942
|
var HISTORIAN_EDITOR_AGENT = "historian-editor";
|
|
3781
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
|
+
|
|
3782
3953
|
// ../plugin/src/features/magic-context/subagent-token-capture.ts
|
|
3783
3954
|
function asNumber(value) {
|
|
3784
3955
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
@@ -3820,6 +3991,9 @@ function failedInvocationStatus(error) {
|
|
|
3820
3991
|
const message = describeError(error).brief;
|
|
3821
3992
|
if (/timed out after \d+ms|prompt timed out/i.test(message))
|
|
3822
3993
|
return "timed_out";
|
|
3994
|
+
if (error !== null && typeof error === "object" && error.name === "TimeoutError") {
|
|
3995
|
+
return "timed_out";
|
|
3996
|
+
}
|
|
3823
3997
|
if (/length-capped|no (?:assistant )?output|empty (?:assistant )?(?:output|text)/i.test(message)) {
|
|
3824
3998
|
return "empty";
|
|
3825
3999
|
}
|
|
@@ -4881,7 +5055,7 @@ function shouldDiscardLastHistorianCompartment(compartments, chunk) {
|
|
|
4881
5055
|
function validateHistorianOutput(text, sessionId, chunk, _priorCompartments, sequenceOffset) {
|
|
4882
5056
|
const parseStarted = startHistorianPublishStage(sessionId, "parse", `response_chars=${text.length}`);
|
|
4883
5057
|
const parsed = parseCompartmentOutput(text);
|
|
4884
|
-
finishHistorianPublishStage(sessionId, "parse", parseStarted, "completed", `compartments=${parsed.compartments.length}`);
|
|
5058
|
+
finishHistorianPublishStage(sessionId, "parse", parseStarted, "completed", `compartments=${parsed.compartments.length} dropped_fact_blocks=${parsed.droppedFactBlocks} dropped_facts=${parsed.droppedFacts}`);
|
|
4885
5059
|
const validationStarted = startHistorianPublishStage(sessionId, "validate");
|
|
4886
5060
|
const finish = (result) => {
|
|
4887
5061
|
finishHistorianPublishStage(sessionId, "validate", validationStarted, result.ok ? "completed" : "failed", result.ok ? `compartments=${result.compartments.length}` : `reason=${JSON.stringify(result.error)}`);
|
|
@@ -4920,6 +5094,7 @@ function validateHistorianOutput(text, sessionId, chunk, _priorCompartments, seq
|
|
|
4920
5094
|
ok: true,
|
|
4921
5095
|
compartments: mapped.compartments,
|
|
4922
5096
|
facts: parsed.facts,
|
|
5097
|
+
...parsed.droppedFactBlocks > 0 ? { droppedFactBlocks: parsed.droppedFactBlocks, droppedFacts: parsed.droppedFacts } : {},
|
|
4923
5098
|
userObservations: parsed.userObservations.length > 0 ? parsed.userObservations : undefined,
|
|
4924
5099
|
primerCandidates: parsed.primerCandidates.length > 0 ? parsed.primerCandidates.slice(0, 1) : undefined,
|
|
4925
5100
|
events: parsed.events.length > 0 ? parsed.events : undefined
|
|
@@ -5172,6 +5347,7 @@ function resolveHiddenCompletionExecutor(executor, client, db, directory, entryP
|
|
|
5172
5347
|
return createV1HiddenCompletionExecutor(client, db, directory);
|
|
5173
5348
|
}
|
|
5174
5349
|
function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
5350
|
+
const asyncChildren = new Set;
|
|
5175
5351
|
return {
|
|
5176
5352
|
capabilities: { tools: true, harness: "opencode" },
|
|
5177
5353
|
async open(run) {
|
|
@@ -5188,11 +5364,19 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
|
5188
5364
|
preferResponseOnMissingData: true
|
|
5189
5365
|
});
|
|
5190
5366
|
const id = typeof created?.id === "string" ? created.id : "";
|
|
5367
|
+
if (id && run.kind === "dreamer-task")
|
|
5368
|
+
asyncChildren.add(id);
|
|
5369
|
+
if (id && run.kind !== "dreamer-task")
|
|
5370
|
+
rememberHistorianOutputCap(id, run.maxOutputTokens);
|
|
5191
5371
|
return { id, childSessionId: id || undefined };
|
|
5192
5372
|
},
|
|
5193
|
-
async attempt(
|
|
5373
|
+
async attempt(handle, request) {
|
|
5194
5374
|
if (!client)
|
|
5195
5375
|
throw new Error("Hidden completion client is unavailable");
|
|
5376
|
+
if (asyncChildren.has(handle.id) && supportsPromptAsync(client)) {
|
|
5377
|
+
await promptAsyncAndWaitForIdle(client, request);
|
|
5378
|
+
return;
|
|
5379
|
+
}
|
|
5196
5380
|
await client.session.prompt(request);
|
|
5197
5381
|
},
|
|
5198
5382
|
async collect(handle, limit) {
|
|
@@ -5220,6 +5404,10 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
|
5220
5404
|
};
|
|
5221
5405
|
},
|
|
5222
5406
|
async close(handle, settlement) {
|
|
5407
|
+
if (handle?.id) {
|
|
5408
|
+
asyncChildren.delete(handle.id);
|
|
5409
|
+
forgetHistorianOutputCap(handle.id);
|
|
5410
|
+
}
|
|
5223
5411
|
if (!client)
|
|
5224
5412
|
return;
|
|
5225
5413
|
await teardownChildSession({
|
|
@@ -5231,6 +5419,9 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
|
5231
5419
|
}
|
|
5232
5420
|
};
|
|
5233
5421
|
}
|
|
5422
|
+
function historianReasoningBudgetDiagnostic(outputTokens) {
|
|
5423
|
+
return `historian ran out of output budget while reasoning (length-capped at ${outputTokens} tokens, no text) — set historian.maxTokens or route historian.model to a low-reasoning lane/variant`;
|
|
5424
|
+
}
|
|
5234
5425
|
async function runValidatedHistorianPass(args) {
|
|
5235
5426
|
const firstRun = await runHistorianPrompt({
|
|
5236
5427
|
...args,
|
|
@@ -5457,14 +5648,14 @@ async function runHistorianPrompt(args) {
|
|
|
5457
5648
|
}
|
|
5458
5649
|
const backoffMs = getHistorianRetryBackoffMs(retryIndex);
|
|
5459
5650
|
sessionLog(parentSessionId, `historian retry ${retryIndex + 1}/${MAX_HISTORIAN_RETRIES} after ${backoffMs}ms: ${errorMsg}`);
|
|
5460
|
-
await
|
|
5651
|
+
await sleep2(backoffMs);
|
|
5461
5652
|
}
|
|
5462
5653
|
}
|
|
5463
5654
|
completion = await executor.collect(handle, 50);
|
|
5464
5655
|
const lengthCapped = completion.lengthCapped;
|
|
5465
5656
|
const textResult = completion.text;
|
|
5466
5657
|
const reasoningResult = textResult ? null : completion.reasoning;
|
|
5467
|
-
const emptyError = !textResult && reasoningResult && lengthCapped ?
|
|
5658
|
+
const emptyError = !textResult && reasoningResult && lengthCapped ? historianReasoningBudgetDiagnostic(completion.usage.output) : !textResult && !reasoningResult ? "Historian returned no assistant output." : !textResult ? "Historian returned reasoning but no assistant text." : lengthCapped ? "Historian returned length-capped output." : null;
|
|
5468
5659
|
const invocationId = recordInvocation({
|
|
5469
5660
|
status: emptyError ? "empty" : "completed",
|
|
5470
5661
|
messages: completion.messages,
|
|
@@ -5594,7 +5785,7 @@ function isTransientHistorianPromptError(message) {
|
|
|
5594
5785
|
"overloaded"
|
|
5595
5786
|
].some((token) => normalized.includes(token));
|
|
5596
5787
|
}
|
|
5597
|
-
function
|
|
5788
|
+
function sleep2(ms) {
|
|
5598
5789
|
return new Promise((resolve) => {
|
|
5599
5790
|
setTimeout(resolve, ms);
|
|
5600
5791
|
});
|
|
@@ -5791,13 +5982,25 @@ function runLeaseGuardedWrite(db, holderId, leaseKey, fn, slowWriteThresholdMs)
|
|
|
5791
5982
|
return fn();
|
|
5792
5983
|
}, `lease-guarded-write:${leaseKey}`, slowWriteThresholdMs);
|
|
5793
5984
|
}
|
|
5794
|
-
var LEASE_HEARTBEAT_INTERVAL_MS =
|
|
5985
|
+
var LEASE_HEARTBEAT_INTERVAL_MS = 40 * 1000;
|
|
5986
|
+
function reacquireOwnedLease(db, holderId, leaseKey, generation) {
|
|
5987
|
+
const keys = rowKeys(leaseKey);
|
|
5988
|
+
return runImmediate(db, () => {
|
|
5989
|
+
if (getLeaseHolder(db, leaseKey) !== holderId || getLeaseGeneration(db, leaseKey) !== generation) {
|
|
5990
|
+
return false;
|
|
5991
|
+
}
|
|
5992
|
+
const now = Date.now();
|
|
5993
|
+
setDreamState(db, keys.heartbeat, String(now));
|
|
5994
|
+
setDreamState(db, keys.expiry, String(now + LEASE_DURATION_MS));
|
|
5995
|
+
return true;
|
|
5996
|
+
});
|
|
5997
|
+
}
|
|
5795
5998
|
function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisition = LEASE_HEARTBEAT_INTERVAL_MS) {
|
|
5796
5999
|
const intervalMs = typeof intervalOrAcquisition === "number" ? intervalOrAcquisition : LEASE_HEARTBEAT_INTERVAL_MS;
|
|
5797
6000
|
const acquisition = typeof intervalOrAcquisition === "number" ? undefined : intervalOrAcquisition;
|
|
5798
6001
|
let lost = false;
|
|
5799
|
-
|
|
5800
|
-
let
|
|
6002
|
+
const expectedGeneration = acquisition?.generation ?? getLeaseGeneration(db, leaseKey);
|
|
6003
|
+
let renewalFailures = 0;
|
|
5801
6004
|
const declareLost = (reason) => {
|
|
5802
6005
|
if (lost)
|
|
5803
6006
|
return;
|
|
@@ -5809,32 +6012,20 @@ function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisiti
|
|
|
5809
6012
|
return;
|
|
5810
6013
|
try {
|
|
5811
6014
|
if (renewLease(db, holderId, leaseKey, expectedGeneration === null ? undefined : expectedGeneration)) {
|
|
5812
|
-
lastConfirmedAt = Date.now();
|
|
5813
|
-
return;
|
|
5814
|
-
}
|
|
5815
|
-
if (expectedGeneration !== null && getLeaseGeneration(db, leaseKey) !== expectedGeneration) {
|
|
5816
|
-
declareLost("lease generation changed — another holder acquired it");
|
|
5817
|
-
return;
|
|
5818
|
-
}
|
|
5819
|
-
if (Date.now() - lastConfirmedAt > LEASE_DURATION_MS) {
|
|
5820
|
-
declareLost("lease lapsed past TTL — another holder may have run");
|
|
5821
6015
|
return;
|
|
5822
6016
|
}
|
|
5823
|
-
|
|
5824
|
-
if (reacquired) {
|
|
5825
|
-
if (expectedGeneration !== null && reacquired.generation !== expectedGeneration) {
|
|
5826
|
-
declareLost("lease generation changed during reacquisition");
|
|
5827
|
-
return;
|
|
5828
|
-
}
|
|
5829
|
-
expectedGeneration = reacquired.generation;
|
|
5830
|
-
lastConfirmedAt = Date.now();
|
|
6017
|
+
if (expectedGeneration !== null && reacquireOwnedLease(db, holderId, leaseKey, expectedGeneration))
|
|
5831
6018
|
return;
|
|
6019
|
+
const holder = getLeaseHolder(db, leaseKey);
|
|
6020
|
+
if (holder !== null && holder !== holderId) {
|
|
6021
|
+
declareLost(`lease_lost: taken by ${holder}`);
|
|
6022
|
+
} else if (getLeaseGeneration(db, leaseKey) !== expectedGeneration) {
|
|
6023
|
+
declareLost("lease_lost: generation changed");
|
|
6024
|
+
} else {
|
|
6025
|
+
declareLost("lease_expired: reacquire failed (holder missing)");
|
|
5832
6026
|
}
|
|
5833
|
-
declareLost("lease acquired by another holder");
|
|
5834
6027
|
} catch {
|
|
5835
|
-
|
|
5836
|
-
declareLost("lease renewal unconfirmed past TTL");
|
|
5837
|
-
}
|
|
6028
|
+
renewalFailures += 1;
|
|
5838
6029
|
}
|
|
5839
6030
|
};
|
|
5840
6031
|
beat();
|
|
@@ -5846,6 +6037,9 @@ function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisiti
|
|
|
5846
6037
|
},
|
|
5847
6038
|
get lost() {
|
|
5848
6039
|
return lost;
|
|
6040
|
+
},
|
|
6041
|
+
get renewalFailures() {
|
|
6042
|
+
return renewalFailures;
|
|
5849
6043
|
}
|
|
5850
6044
|
};
|
|
5851
6045
|
}
|
|
@@ -5923,6 +6117,14 @@ function assertParsedManifestNonEmpty(parsedCount, expectedCount, text, expected
|
|
|
5923
6117
|
}
|
|
5924
6118
|
|
|
5925
6119
|
// ../plugin/src/features/magic-context/dreamer/module-apply.ts
|
|
6120
|
+
var loggedNotOwnerProjects = new Set;
|
|
6121
|
+
function logDreamerNotOwnerOnce(projectIdentity) {
|
|
6122
|
+
if (loggedNotOwnerProjects.has(projectIdentity))
|
|
6123
|
+
return;
|
|
6124
|
+
loggedNotOwnerProjects.add(projectIdentity);
|
|
6125
|
+
log(`[dreamer] ${projectIdentity}: module-managed project; skipping TS writes without an owner route`);
|
|
6126
|
+
}
|
|
6127
|
+
|
|
5926
6128
|
class DreamerModuleBusyError extends Error {
|
|
5927
6129
|
state;
|
|
5928
6130
|
transient = true;
|
|
@@ -6547,7 +6749,7 @@ async function runHiddenSingleShotPrompt(args) {
|
|
|
6547
6749
|
fetchOutput: () => args.executor.collect(handle, 50),
|
|
6548
6750
|
validateOutput: (completion) => {
|
|
6549
6751
|
if (completion.lengthCapped) {
|
|
6550
|
-
throw new Error(`${args.callContext} returned length-capped output`);
|
|
6752
|
+
throw new Error(completion.reasoning && !completion.text ? `${args.callContext} ran out of output budget while reasoning (length-capped at ${completion.usage.output} tokens, no text) — set dreamer.maxTokens or use a low-reasoning model` : `${args.callContext} returned length-capped output`);
|
|
6551
6753
|
}
|
|
6552
6754
|
const text = completion.text;
|
|
6553
6755
|
if (!text && !args.allowEmpty)
|
|
@@ -7120,12 +7322,45 @@ function validateClassifyManifest(text, expectedIds) {
|
|
|
7120
7322
|
return parsed;
|
|
7121
7323
|
}
|
|
7122
7324
|
|
|
7325
|
+
// ../plugin/src/features/magic-context/dreamer/failed-invocation-evidence.ts
|
|
7326
|
+
var FAILED_CHILD_READ_TIMEOUT_MS = 5000;
|
|
7327
|
+
var FAILED_CHILD_MESSAGE_LIMIT = 200;
|
|
7328
|
+
async function readFailedChildMessages(client, sessionId, directory) {
|
|
7329
|
+
if (!client || !sessionId)
|
|
7330
|
+
return;
|
|
7331
|
+
let timer;
|
|
7332
|
+
try {
|
|
7333
|
+
const response = await Promise.race([
|
|
7334
|
+
client.session.messages({
|
|
7335
|
+
path: { id: sessionId },
|
|
7336
|
+
query: { directory, limit: FAILED_CHILD_MESSAGE_LIMIT }
|
|
7337
|
+
}),
|
|
7338
|
+
new Promise((resolve) => {
|
|
7339
|
+
timer = setTimeout(() => resolve(null), FAILED_CHILD_READ_TIMEOUT_MS);
|
|
7340
|
+
})
|
|
7341
|
+
]);
|
|
7342
|
+
if (response === null)
|
|
7343
|
+
return;
|
|
7344
|
+
const messages = normalizeSDKResponse(response, [], {
|
|
7345
|
+
preferResponseOnMissingData: true
|
|
7346
|
+
});
|
|
7347
|
+
return Array.isArray(messages) ? messages : undefined;
|
|
7348
|
+
} catch (error) {
|
|
7349
|
+
log(`[dreamer] failed-child evidence read failed for ${sessionId}: ${String(error)}`);
|
|
7350
|
+
return;
|
|
7351
|
+
} finally {
|
|
7352
|
+
if (timer)
|
|
7353
|
+
clearTimeout(timer);
|
|
7354
|
+
}
|
|
7355
|
+
}
|
|
7356
|
+
|
|
7123
7357
|
// ../plugin/src/features/magic-context/dreamer/classify.ts
|
|
7124
7358
|
var MIN_POOL_TO_CLASSIFY = 10;
|
|
7125
7359
|
var FULL_POOL_CEILING = 100;
|
|
7126
7360
|
var STAGE3_ANCHOR_COUNT = 30;
|
|
7127
7361
|
var CLASSIFY_CHUNK_SIZE = 100;
|
|
7128
7362
|
var CLASSIFY_MODULE_RUN_TIMEOUT_MS = 660000;
|
|
7363
|
+
var HOST_COMPLETION_REQUIRED = "host_completion_required";
|
|
7129
7364
|
|
|
7130
7365
|
class ClassifyModuleFailureError extends Error {
|
|
7131
7366
|
transient = true;
|
|
@@ -7209,13 +7444,12 @@ async function runClassify(args) {
|
|
|
7209
7444
|
let stage;
|
|
7210
7445
|
let toClassify;
|
|
7211
7446
|
let anchors = [];
|
|
7447
|
+
const unclassifiedIds = new Set(getUnclassifiedMemoryIds(args.db, active.map((candidate) => candidate.contextMemory.id)));
|
|
7448
|
+
toClassify = active.filter((candidate) => unclassifiedIds.has(candidate.contextMemory.id));
|
|
7212
7449
|
if (active.length <= FULL_POOL_CEILING) {
|
|
7213
7450
|
stage = 2;
|
|
7214
|
-
toClassify = active;
|
|
7215
7451
|
} else {
|
|
7216
7452
|
stage = 3;
|
|
7217
|
-
const unclassifiedIds = new Set(getUnclassifiedMemoryIds(args.db, active.map((candidate) => candidate.contextMemory.id)));
|
|
7218
|
-
toClassify = active.filter((candidate) => unclassifiedIds.has(candidate.contextMemory.id));
|
|
7219
7453
|
const classified = active.filter((candidate) => !unclassifiedIds.has(candidate.contextMemory.id));
|
|
7220
7454
|
anchors = stratifiedAnchors(classified, STAGE3_ANCHOR_COUNT);
|
|
7221
7455
|
}
|
|
@@ -7236,7 +7470,7 @@ async function runClassify(args) {
|
|
|
7236
7470
|
chunks.push(toClassify.slice(i, i + CLASSIFY_CHUNK_SIZE));
|
|
7237
7471
|
}
|
|
7238
7472
|
const abortController = new AbortController;
|
|
7239
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
7473
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, (reason) => abortController.abort(new Error(reason)), args.leaseAcquisition);
|
|
7240
7474
|
try {
|
|
7241
7475
|
for (let i = 0;i < chunks.length; i += 1) {
|
|
7242
7476
|
const remainingMs = Math.max(0, args.deadline - Date.now());
|
|
@@ -7271,68 +7505,89 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
7271
7505
|
memories: chunk.map(toPromptMemory2),
|
|
7272
7506
|
anchors
|
|
7273
7507
|
});
|
|
7508
|
+
const runOnHostCarrier = async (system) => {
|
|
7509
|
+
const executor = resolveHiddenCompletionExecutor(args.hiddenCompletionExecutor, args.client, args.db, args.sessionDirectory, "classify-memories");
|
|
7510
|
+
closeExecutor = executor;
|
|
7511
|
+
handle = await executor.open({
|
|
7512
|
+
parentSessionId: args.parentSessionId,
|
|
7513
|
+
agent: DREAMER_CLASSIFIER_AGENT,
|
|
7514
|
+
kind: "dreamer-task",
|
|
7515
|
+
system,
|
|
7516
|
+
model: args.model,
|
|
7517
|
+
configuredModels: [
|
|
7518
|
+
...args.model ? [args.model] : [],
|
|
7519
|
+
...args.fallbackModels ?? []
|
|
7520
|
+
],
|
|
7521
|
+
timeoutMs: sliceMs,
|
|
7522
|
+
title: "magic-context-dream-classify",
|
|
7523
|
+
directory: args.sessionDirectory,
|
|
7524
|
+
metadata: { task: "classify-memories" }
|
|
7525
|
+
});
|
|
7526
|
+
agentSessionId = handle.id || null;
|
|
7527
|
+
if (!agentSessionId)
|
|
7528
|
+
throw new Error("Could not create classify session.");
|
|
7529
|
+
const opened = handle;
|
|
7530
|
+
const run = await promptSyncWithValidatedOutputRetry(args.client, {
|
|
7531
|
+
path: { id: agentSessionId },
|
|
7532
|
+
query: { directory: args.sessionDirectory },
|
|
7533
|
+
body: {
|
|
7534
|
+
agent: DREAMER_CLASSIFIER_AGENT,
|
|
7535
|
+
system,
|
|
7536
|
+
...modelBodyField(args.model),
|
|
7537
|
+
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
7538
|
+
}
|
|
7539
|
+
}, {
|
|
7540
|
+
transport: Object.assign((request) => executor.attempt(opened, request), { childSessionId: opened.childSessionId }),
|
|
7541
|
+
timeoutMs: sliceMs,
|
|
7542
|
+
signal,
|
|
7543
|
+
fallbackModels: args.fallbackModels,
|
|
7544
|
+
callContext: "dreamer:classify-memories",
|
|
7545
|
+
fetchOutput: () => executor.collect(opened, 50),
|
|
7546
|
+
validateOutput: (completion) => {
|
|
7547
|
+
const messages = completion.messages ?? [];
|
|
7548
|
+
if (completion.lengthCapped) {
|
|
7549
|
+
throw new Error(completion.reasoning && !completion.text ? `classify ran out of output budget while reasoning (length-capped at ${completion.usage.output} tokens, no text) — set dreamer.maxTokens or use a low-reasoning model` : "classify returned length-capped output");
|
|
7550
|
+
}
|
|
7551
|
+
const text = completion.text;
|
|
7552
|
+
if (!text)
|
|
7553
|
+
throw new Error("classify returned no output");
|
|
7554
|
+
try {
|
|
7555
|
+
validateClassifyManifest(text, new Set(chunk.map((candidate) => candidate.id)));
|
|
7556
|
+
} catch (error) {
|
|
7557
|
+
const providerFailure = providerOutputFailureFromInvalidManifest(messages, text);
|
|
7558
|
+
if (providerFailure)
|
|
7559
|
+
throw providerFailure;
|
|
7560
|
+
throw error;
|
|
7561
|
+
}
|
|
7562
|
+
return text;
|
|
7563
|
+
}
|
|
7564
|
+
});
|
|
7565
|
+
promptSettled = true;
|
|
7566
|
+
return run;
|
|
7567
|
+
};
|
|
7274
7568
|
if (moduleRoute) {
|
|
7275
|
-
const { accounting, ...run } = await runClassifyThroughModule(args, chunk, anchors, signal)
|
|
7569
|
+
const { accounting, ...run } = await runClassifyThroughModule(args, chunk, anchors, signal, async (system) => {
|
|
7570
|
+
const run = await runOnHostCarrier(system);
|
|
7571
|
+
const output = run.output;
|
|
7572
|
+
return {
|
|
7573
|
+
text: run.validated,
|
|
7574
|
+
model: output.providerId && output.modelId ? `${output.providerId}/${output.modelId}` : run.attempt.label,
|
|
7575
|
+
length_capped: output.lengthCapped === true,
|
|
7576
|
+
usage: {
|
|
7577
|
+
input: output.usage?.input ?? 0,
|
|
7578
|
+
output: output.usage?.output ?? 0,
|
|
7579
|
+
cache_read: output.usage?.cacheRead ?? 0,
|
|
7580
|
+
cache_write: output.usage?.cacheWrite ?? 0
|
|
7581
|
+
}
|
|
7582
|
+
};
|
|
7583
|
+
});
|
|
7276
7584
|
recordInvocation(args, startedAt, {
|
|
7277
7585
|
status: "completed",
|
|
7278
7586
|
moduleAccounting: accounting
|
|
7279
7587
|
});
|
|
7280
7588
|
return run;
|
|
7281
7589
|
}
|
|
7282
|
-
const
|
|
7283
|
-
closeExecutor = executor;
|
|
7284
|
-
handle = await executor.open({
|
|
7285
|
-
parentSessionId: args.parentSessionId,
|
|
7286
|
-
agent: DREAMER_CLASSIFIER_AGENT,
|
|
7287
|
-
kind: "dreamer-task",
|
|
7288
|
-
system: withContentLanguageDirective(CLASSIFY_SYSTEM_PROMPT, args.language),
|
|
7289
|
-
model: args.model,
|
|
7290
|
-
configuredModels: [...args.model ? [args.model] : [], ...args.fallbackModels ?? []],
|
|
7291
|
-
timeoutMs: sliceMs,
|
|
7292
|
-
title: "magic-context-dream-classify",
|
|
7293
|
-
directory: args.sessionDirectory,
|
|
7294
|
-
metadata: { task: "classify-memories" }
|
|
7295
|
-
});
|
|
7296
|
-
agentSessionId = handle.id || null;
|
|
7297
|
-
if (!agentSessionId)
|
|
7298
|
-
throw new Error("Could not create classify session.");
|
|
7299
|
-
const opened = handle;
|
|
7300
|
-
const run = await promptSyncWithValidatedOutputRetry(args.client, {
|
|
7301
|
-
path: { id: agentSessionId },
|
|
7302
|
-
query: { directory: args.sessionDirectory },
|
|
7303
|
-
body: {
|
|
7304
|
-
agent: DREAMER_CLASSIFIER_AGENT,
|
|
7305
|
-
system: withContentLanguageDirective(CLASSIFY_SYSTEM_PROMPT, args.language),
|
|
7306
|
-
...modelBodyField(args.model),
|
|
7307
|
-
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
7308
|
-
}
|
|
7309
|
-
}, {
|
|
7310
|
-
transport: Object.assign((request) => executor.attempt(opened, request), { childSessionId: opened.childSessionId }),
|
|
7311
|
-
timeoutMs: sliceMs,
|
|
7312
|
-
signal,
|
|
7313
|
-
fallbackModels: args.fallbackModels,
|
|
7314
|
-
callContext: "dreamer:classify-memories",
|
|
7315
|
-
fetchOutput: () => executor.collect(opened, 50),
|
|
7316
|
-
validateOutput: (completion) => {
|
|
7317
|
-
const messages = completion.messages ?? [];
|
|
7318
|
-
if (completion.lengthCapped) {
|
|
7319
|
-
throw new Error("classify returned length-capped output");
|
|
7320
|
-
}
|
|
7321
|
-
const text = completion.text;
|
|
7322
|
-
if (!text)
|
|
7323
|
-
throw new Error("classify returned no output");
|
|
7324
|
-
try {
|
|
7325
|
-
validateClassifyManifest(text, new Set(chunk.map((candidate) => candidate.id)));
|
|
7326
|
-
} catch (error) {
|
|
7327
|
-
const providerFailure = providerOutputFailureFromInvalidManifest(messages, text);
|
|
7328
|
-
if (providerFailure)
|
|
7329
|
-
throw providerFailure;
|
|
7330
|
-
throw error;
|
|
7331
|
-
}
|
|
7332
|
-
return text;
|
|
7333
|
-
}
|
|
7334
|
-
});
|
|
7335
|
-
promptSettled = true;
|
|
7590
|
+
const run = await runOnHostCarrier(withContentLanguageDirective(CLASSIFY_SYSTEM_PROMPT, args.language));
|
|
7336
7591
|
recordInvocation(args, startedAt, {
|
|
7337
7592
|
status: "completed",
|
|
7338
7593
|
messages: run.output.messages,
|
|
@@ -7345,7 +7600,8 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
7345
7600
|
log(`[dreamer] classify chunk failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
|
|
7346
7601
|
recordInvocation(args, startedAt, {
|
|
7347
7602
|
status: failedInvocationStatus(failure),
|
|
7348
|
-
error: failure
|
|
7603
|
+
error: failure,
|
|
7604
|
+
messages: args.hiddenCompletionExecutor ? undefined : await readFailedChildMessages(args.client, agentSessionId, args.sessionDirectory)
|
|
7349
7605
|
});
|
|
7350
7606
|
if (moduleRoute || failure instanceof HiddenCompletionRefusal || signal.aborted || failure instanceof DreamerProviderOutputFailureError || getPromptFailureDetail(failure)?.failureClass !== "parse_failed" && getPromptFailureDetail(failure) !== null)
|
|
7351
7607
|
throw failure;
|
|
@@ -7359,7 +7615,7 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
7359
7615
|
});
|
|
7360
7616
|
}
|
|
7361
7617
|
}
|
|
7362
|
-
async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
7618
|
+
async function runClassifyThroughModule(args, chunk, anchors, signal, runOnHost) {
|
|
7363
7619
|
const prompt = buildClassifyPrompt({
|
|
7364
7620
|
projectPath: args.projectIdentity,
|
|
7365
7621
|
memories: chunk.map(toPromptMemory2),
|
|
@@ -7367,7 +7623,8 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
7367
7623
|
});
|
|
7368
7624
|
const modelChain = [args.model, ...args.fallbackModels ?? []].map(toModelEntry).filter((entry) => entry !== undefined).map((entry) => entry.model);
|
|
7369
7625
|
const resolvedModelChain = [...new Set(modelChain)];
|
|
7370
|
-
const
|
|
7626
|
+
const commandId = `classify:${args.moduleCommandId ?? Date.now()}:${createHash5("sha256").update(chunk.map((candidate) => candidate.id).join(",")).digest("hex").slice(0, 24)}`;
|
|
7627
|
+
const runTask = (hostCompletion) => args.moduleClient?.call({
|
|
7371
7628
|
sessionId: args.moduleSessionId,
|
|
7372
7629
|
projectRoot: args.moduleProjectRoot,
|
|
7373
7630
|
method: "dreamer.run_task",
|
|
@@ -7376,7 +7633,7 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
7376
7633
|
v: 1,
|
|
7377
7634
|
session_id: args.moduleSessionId,
|
|
7378
7635
|
task: "classify",
|
|
7379
|
-
command_id:
|
|
7636
|
+
command_id: commandId,
|
|
7380
7637
|
authority_generation: args.moduleAuthorityGeneration,
|
|
7381
7638
|
model_chain: resolvedModelChain,
|
|
7382
7639
|
payload: {
|
|
@@ -7385,12 +7642,20 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
7385
7642
|
memory_id: candidate.id,
|
|
7386
7643
|
content_hash: candidate.normalizedHash
|
|
7387
7644
|
}))
|
|
7388
|
-
}
|
|
7645
|
+
},
|
|
7646
|
+
...hostCompletion ? { host_completion: hostCompletion } : {}
|
|
7389
7647
|
},
|
|
7390
7648
|
signal,
|
|
7391
|
-
timeoutMs: CLASSIFY_MODULE_RUN_TIMEOUT_MS
|
|
7649
|
+
timeoutMs: Math.max(1, resolvedModelChain.length) * CLASSIFY_MODULE_RUN_TIMEOUT_MS + 30000
|
|
7392
7650
|
});
|
|
7393
|
-
const
|
|
7651
|
+
const unwrap = (response) => response?.result ?? response;
|
|
7652
|
+
let result = unwrap(await runTask());
|
|
7653
|
+
const asked = result;
|
|
7654
|
+
if (asked?.code === HOST_COMPLETION_REQUIRED) {
|
|
7655
|
+
if (typeof asked.system_prompt !== "string")
|
|
7656
|
+
throw new Error("module asked for a host classify completion without a system prompt");
|
|
7657
|
+
result = unwrap(await runTask(await runOnHost(asked.system_prompt)));
|
|
7658
|
+
}
|
|
7394
7659
|
if (!result || typeof result !== "object")
|
|
7395
7660
|
throw new Error("module returned invalid classify result");
|
|
7396
7661
|
const manifestText = result.manifest_text;
|
|
@@ -8152,7 +8417,7 @@ async function guardedReadFile(projectRoot, repoRelativePath, signal, fileLimitB
|
|
|
8152
8417
|
const body = guardedReadFileBody(projectRoot, repoRelativePath, signal, fileLimitBytes);
|
|
8153
8418
|
let onAbort;
|
|
8154
8419
|
const abort = new Promise((_, reject) => {
|
|
8155
|
-
onAbort = () => reject(
|
|
8420
|
+
onAbort = () => reject(abortError2(signal));
|
|
8156
8421
|
if (signal.aborted)
|
|
8157
8422
|
onAbort();
|
|
8158
8423
|
else
|
|
@@ -8222,9 +8487,9 @@ async function closeLateOpenOnAbort(openPromise, signal) {
|
|
|
8222
8487
|
return handle;
|
|
8223
8488
|
if (handle)
|
|
8224
8489
|
handle.close().catch(() => {});
|
|
8225
|
-
throw
|
|
8490
|
+
throw abortError2(signal);
|
|
8226
8491
|
}
|
|
8227
|
-
function
|
|
8492
|
+
function abortError2(signal) {
|
|
8228
8493
|
return signal.reason instanceof SmartNoteNetworkError ? signal.reason : new SmartNoteNetworkError("SMART_NOTE_NETWORK: aborted");
|
|
8229
8494
|
}
|
|
8230
8495
|
function isPathInside(root, target) {
|
|
@@ -9043,9 +9308,9 @@ async function evaluateSmartNotes(args) {
|
|
|
9043
9308
|
throw new Error(`Dream lease lost during smart-notes ${phase}`);
|
|
9044
9309
|
}
|
|
9045
9310
|
};
|
|
9046
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => {
|
|
9311
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, (reason) => {
|
|
9047
9312
|
leaseLost = true;
|
|
9048
|
-
leaseAbortController.abort(new Error(
|
|
9313
|
+
leaseAbortController.abort(new Error(reason));
|
|
9049
9314
|
log("[dreamer] smart notes: lease lost — aborting");
|
|
9050
9315
|
args.onLeaseLost?.("smart notes");
|
|
9051
9316
|
}, args.leaseAcquisition);
|
|
@@ -9360,6 +9625,7 @@ async function confirmReadOnly(args, noteId, content, surfaceCondition, leaseSig
|
|
|
9360
9625
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
9361
9626
|
}
|
|
9362
9627
|
}, {
|
|
9628
|
+
transport: createPromptAsyncTransport(client, childSessionId),
|
|
9363
9629
|
timeoutMs: Math.max(1000, args.deadline - Date.now()),
|
|
9364
9630
|
signal: promptSignal.signal,
|
|
9365
9631
|
fallbackModels: args.fallbackModels,
|
|
@@ -9667,7 +9933,7 @@ function computeMapBatchSliceMs(remainingMs, batchesRemaining) {
|
|
|
9667
9933
|
return Math.min(remainingMs, Math.max(MAP_BATCH_FLOOR_MS, Math.floor(remainingMs / batchesRemaining)));
|
|
9668
9934
|
}
|
|
9669
9935
|
function isTimeoutClassError2(error) {
|
|
9670
|
-
return
|
|
9936
|
+
return isPromptTimeoutError(error);
|
|
9671
9937
|
}
|
|
9672
9938
|
function shouldRequeueIndependentMapping(state, content, repoDir) {
|
|
9673
9939
|
if (!state.hasSentinel || state.files.length > 0)
|
|
@@ -9722,7 +9988,7 @@ async function mapMemories(args) {
|
|
|
9722
9988
|
}
|
|
9723
9989
|
result.remaining = inputs.length;
|
|
9724
9990
|
const abortController = new AbortController;
|
|
9725
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
9991
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, (reason) => abortController.abort(new Error(reason)), args.leaseAcquisition);
|
|
9726
9992
|
try {
|
|
9727
9993
|
let consecutiveTimeouts = 0;
|
|
9728
9994
|
let timeoutStreakElapsedMs = [];
|
|
@@ -9837,6 +10103,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
|
|
|
9837
10103
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
9838
10104
|
}
|
|
9839
10105
|
}, {
|
|
10106
|
+
transport: createPromptAsyncTransport(client, agentSessionId),
|
|
9840
10107
|
timeoutMs: sliceMs,
|
|
9841
10108
|
signal,
|
|
9842
10109
|
fallbackModels: args.fallbackModels,
|
|
@@ -9871,7 +10138,11 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
|
|
|
9871
10138
|
} catch (error) {
|
|
9872
10139
|
const desc = describeError(error);
|
|
9873
10140
|
log(`[dreamer] map-memories batch failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
|
|
9874
|
-
recordInvocation2(args, startedAt, {
|
|
10141
|
+
recordInvocation2(args, startedAt, {
|
|
10142
|
+
status: failedInvocationStatus(error),
|
|
10143
|
+
error,
|
|
10144
|
+
messages: await readFailedChildMessages(args.client, agentSessionId, args.sessionDirectory)
|
|
10145
|
+
});
|
|
9875
10146
|
if (error instanceof DreamerModuleFailureError)
|
|
9876
10147
|
throw error;
|
|
9877
10148
|
if (signal.aborted)
|
|
@@ -10196,7 +10467,7 @@ function pruneExpiredPrimerCandidatesForProject(db, projectIdentity, now = Date.
|
|
|
10196
10467
|
db.transaction(() => {
|
|
10197
10468
|
for (const id of toDelete)
|
|
10198
10469
|
stmt.run(id, projectIdentity);
|
|
10199
|
-
})();
|
|
10470
|
+
}).immediate();
|
|
10200
10471
|
return toDelete.length;
|
|
10201
10472
|
}
|
|
10202
10473
|
async function promotePrimers(args) {
|
|
@@ -10279,12 +10550,12 @@ async function promotePrimers(args) {
|
|
|
10279
10550
|
|
|
10280
10551
|
// ../plugin/src/features/magic-context/dreamer/primer-seed.ts
|
|
10281
10552
|
var PRIMER_SEED_CAP_TOKENS = 4000;
|
|
10282
|
-
function renderUserAndToolOrientation(
|
|
10553
|
+
function renderUserAndToolOrientation(sessionId, startOrdinal, endOrdinal, capTokens) {
|
|
10283
10554
|
const lines = [];
|
|
10284
10555
|
let tokens = 0;
|
|
10285
|
-
|
|
10286
|
-
|
|
10287
|
-
|
|
10556
|
+
let sawMessage = false;
|
|
10557
|
+
visitRawSessionMessages2(sessionId, startOrdinal, endOrdinal, (msg) => {
|
|
10558
|
+
sawMessage = true;
|
|
10288
10559
|
const out = [];
|
|
10289
10560
|
if (msg.role === "user" && hasMeaningfulUserText2(msg.parts)) {
|
|
10290
10561
|
const text = extractTexts2(msg.parts).map((t) => cleanUserText2(t)).map(normalizeText).filter((t) => t.length > 0).join(" / ");
|
|
@@ -10297,22 +10568,27 @@ function renderUserAndToolOrientation(messages, startOrdinal, endOrdinal, capTok
|
|
|
10297
10568
|
const lineTokens = estimateTokens(line);
|
|
10298
10569
|
if (tokens + lineTokens > capTokens && lines.length > 0) {
|
|
10299
10570
|
lines.push("… (orientation truncated; investigate the current source directly)");
|
|
10300
|
-
return
|
|
10301
|
-
`);
|
|
10571
|
+
return false;
|
|
10302
10572
|
}
|
|
10303
10573
|
lines.push(line);
|
|
10304
10574
|
tokens += lineTokens;
|
|
10305
10575
|
}
|
|
10306
|
-
|
|
10307
|
-
|
|
10308
|
-
`
|
|
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];
|
|
10309
10583
|
}
|
|
10310
10584
|
function loadPrePostP1(db, sessionId, originStartMessage) {
|
|
10311
10585
|
const origin = db.prepare("SELECT sequence FROM compartments WHERE session_id = ? AND start_message = ? ORDER BY sequence ASC LIMIT 1").get(sessionId, originStartMessage);
|
|
10312
10586
|
if (typeof origin?.sequence !== "number")
|
|
10313
10587
|
return "";
|
|
10314
10588
|
const originSeq = origin.sequence;
|
|
10315
|
-
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
|
|
10316
10592
|
FROM compartments
|
|
10317
10593
|
WHERE session_id = ? AND sequence IN (?, ?)
|
|
10318
10594
|
ORDER BY sequence ASC`).all(sessionId, originSeq - 1, originSeq + 1);
|
|
@@ -10326,28 +10602,28 @@ function loadPrePostP1(db, sessionId, originStartMessage) {
|
|
|
10326
10602
|
`);
|
|
10327
10603
|
}
|
|
10328
10604
|
function closedBookOriginP1(db, sessionId, originStartMessage) {
|
|
10329
|
-
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);
|
|
10330
10608
|
const body = (row?.p1 ?? row?.content ?? "").slice(0, 2000);
|
|
10331
10609
|
const orientation = row?.title ? `${row.title}: ${body}` : body;
|
|
10332
10610
|
return { orientation, sessionId };
|
|
10333
10611
|
}
|
|
10334
10612
|
function buildPrimerSeed(db, primer) {
|
|
10335
|
-
const
|
|
10336
|
-
const mostRecent = candidates.slice().sort((a, b) => b.sourceMessageTime - a.sourceMessageTime || b.id - a.id)[0];
|
|
10613
|
+
const mostRecent = selectPrimerOriginCandidate(db, primer);
|
|
10337
10614
|
if (!mostRecent || typeof mostRecent.sourceCompartmentStart !== "number" || typeof mostRecent.sourceCompartmentEnd !== "number") {
|
|
10338
10615
|
return { kind: "closed-book", orientation: "", prePost: "", sessionId: null };
|
|
10339
10616
|
}
|
|
10340
10617
|
const sessionId = mostRecent.sessionId;
|
|
10341
10618
|
const start = mostRecent.sourceCompartmentStart;
|
|
10342
10619
|
const end = mostRecent.sourceCompartmentEnd;
|
|
10343
|
-
let
|
|
10620
|
+
let orientation = null;
|
|
10344
10621
|
try {
|
|
10345
|
-
|
|
10622
|
+
orientation = renderUserAndToolOrientation(sessionId, start, end, PRIMER_SEED_CAP_TOKENS);
|
|
10346
10623
|
} catch {
|
|
10347
|
-
|
|
10624
|
+
orientation = null;
|
|
10348
10625
|
}
|
|
10349
|
-
|
|
10350
|
-
if (!inRange) {
|
|
10626
|
+
if (orientation === null) {
|
|
10351
10627
|
const closed = closedBookOriginP1(db, sessionId, start);
|
|
10352
10628
|
return {
|
|
10353
10629
|
kind: "closed-book",
|
|
@@ -10356,7 +10632,6 @@ function buildPrimerSeed(db, primer) {
|
|
|
10356
10632
|
sessionId
|
|
10357
10633
|
};
|
|
10358
10634
|
}
|
|
10359
|
-
const orientation = renderUserAndToolOrientation(raw, start, end, PRIMER_SEED_CAP_TOKENS);
|
|
10360
10635
|
return {
|
|
10361
10636
|
kind: "raw",
|
|
10362
10637
|
orientation,
|
|
@@ -10590,9 +10865,7 @@ async function refreshOnePrimer(args, primer, sliceMs, signal) {
|
|
|
10590
10865
|
}
|
|
10591
10866
|
}
|
|
10592
10867
|
function originSessionIdForPrimer(args, primer) {
|
|
10593
|
-
|
|
10594
|
-
const mostRecent = candidates.slice().sort((a, b) => b.sourceMessageTime - a.sourceMessageTime || b.id - a.id)[0];
|
|
10595
|
-
return mostRecent?.sessionId ?? null;
|
|
10868
|
+
return selectPrimerOriginCandidate(args.db, primer)?.sessionId ?? null;
|
|
10596
10869
|
}
|
|
10597
10870
|
function recordInvocation3(args, startedAt, params) {
|
|
10598
10871
|
if (!args.parentSessionId)
|
|
@@ -10615,13 +10888,7 @@ var FRUSTRATION_MARKER_REGEX = /\b(?:not what i asked|i already (?:said|told you
|
|
|
10615
10888
|
var LEARNINGS_BLOCK_REGEX = /<learnings\b[^>]*>(.*?)<\/learnings>/is;
|
|
10616
10889
|
var LEARNING_REGEX = /<learning\b([^>]*)>(.*?)<\/learning>/gis;
|
|
10617
10890
|
var ATTR_REGEX = /([a-zA-Z_:-]+)\s*=\s*"([^"]*)"/g;
|
|
10618
|
-
var VALID_MEMORY_CATEGORIES = new Set(
|
|
10619
|
-
"PROJECT_RULES",
|
|
10620
|
-
"ARCHITECTURE",
|
|
10621
|
-
"CONSTRAINTS",
|
|
10622
|
-
"CONFIG_VALUES",
|
|
10623
|
-
"NAMING"
|
|
10624
|
-
]);
|
|
10891
|
+
var VALID_MEMORY_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
10625
10892
|
var RAW_QUOTE_REGEX = /["“”][^"“”]{4,}["“”]|'[^']{4,}'/;
|
|
10626
10893
|
var DATE_REGEX = /\b(?:20\d{2}[-/]\d{1,2}[-/]\d{1,2}|\d{1,2}\/\d{1,2}\/20\d{2}|(?:jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)[a-z]*\s+\d{1,2},?\s+20\d{2})\b/i;
|
|
10627
10894
|
function parseRetrospectiveLearnings(text) {
|
|
@@ -10996,11 +11263,48 @@ function normalizeOpenCodeRows(db, sessionId, rows) {
|
|
|
10996
11263
|
return [];
|
|
10997
11264
|
const messageIds = rows.map((row) => row.id);
|
|
10998
11265
|
const placeholders = messageIds.map(() => "?").join(", ");
|
|
10999
|
-
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
|
|
11000
11304
|
FROM part
|
|
11001
|
-
WHERE +session_id = ?
|
|
11305
|
+
WHERE +session_id = ? AND json_valid(data)
|
|
11002
11306
|
AND likelihood(message_id IN (${placeholders}), 0.000001)
|
|
11003
|
-
ORDER BY time_created ASC, id ASC`).all(sessionId, ...messageIds);
|
|
11307
|
+
ORDER BY time_created ASC, id ASC`).all(...userIds, whitespace, sessionId, ...messageIds);
|
|
11004
11308
|
const partsByMessageId = new Map;
|
|
11005
11309
|
for (const row of partRows) {
|
|
11006
11310
|
const parts = partsByMessageId.get(row.message_id) ?? [];
|
|
@@ -11380,6 +11684,10 @@ function validateVerifyManifest(text, expectedIds) {
|
|
|
11380
11684
|
// ../plugin/src/features/magic-context/dreamer/verify.ts
|
|
11381
11685
|
var VERIFY_BATCH_SIZE = 50;
|
|
11382
11686
|
var IDENTICAL_PROVIDER_FAILURE_BATCH_LIMIT = 2;
|
|
11687
|
+
var VERIFY_BATCH_FLOOR_MS = 240000;
|
|
11688
|
+
function computeVerifyBatchSliceMs(remainingMs, batchesRemaining) {
|
|
11689
|
+
return Math.min(remainingMs, Math.max(VERIFY_BATCH_FLOOR_MS, Math.floor(remainingMs / batchesRemaining)));
|
|
11690
|
+
}
|
|
11383
11691
|
function closeBroadCycle(args, cycleStartAt) {
|
|
11384
11692
|
if (!args.forceBroad || cycleStartAt === undefined)
|
|
11385
11693
|
return;
|
|
@@ -11434,17 +11742,19 @@ async function runVerify(args) {
|
|
|
11434
11742
|
batches.push(gate.inScope.slice(i, i + VERIFY_BATCH_SIZE));
|
|
11435
11743
|
}
|
|
11436
11744
|
const abortController = new AbortController;
|
|
11437
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
11745
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, (reason) => abortController.abort(new Error(reason)), args.leaseAcquisition);
|
|
11438
11746
|
let consecutiveProviderFailures = 0;
|
|
11439
11747
|
let priorProviderFailureFingerprint = null;
|
|
11440
11748
|
let lastProviderFailure = null;
|
|
11441
11749
|
try {
|
|
11442
11750
|
for (let i = 0;i < batches.length; i += 1) {
|
|
11443
11751
|
const remainingMs = Math.max(0, args.deadline - Date.now());
|
|
11444
|
-
if (remainingMs
|
|
11752
|
+
if (remainingMs < VERIFY_BATCH_FLOOR_MS) {
|
|
11753
|
+
result.stopReason = "deadline";
|
|
11754
|
+
log(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: stopping before batch ${i + 1}/${batches.length} — remaining budget ${remainingMs}ms is below the ${VERIFY_BATCH_FLOOR_MS}ms batch floor`);
|
|
11445
11755
|
break;
|
|
11446
|
-
|
|
11447
|
-
const sliceMs =
|
|
11756
|
+
}
|
|
11757
|
+
const sliceMs = computeVerifyBatchSliceMs(remainingMs, batches.length - i);
|
|
11448
11758
|
const counts = await verifyOneBatch(args, batches[i], sliceMs, abortController.signal);
|
|
11449
11759
|
result.verified += counts.verified;
|
|
11450
11760
|
result.updated += counts.updated;
|
|
@@ -11455,6 +11765,11 @@ async function runVerify(args) {
|
|
|
11455
11765
|
result.remaining -= batchProcessed;
|
|
11456
11766
|
result.batches += 1;
|
|
11457
11767
|
args.onProgress?.(result.verified + result.updated + result.archived + result.skipped + result.refused, result.refused);
|
|
11768
|
+
if (counts.timedOut) {
|
|
11769
|
+
result.stopReason = "batch-timeout";
|
|
11770
|
+
log(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: batch ${i + 1}/${batches.length} timed out after its ${sliceMs}ms slice; stopping with ${result.remaining} remaining`);
|
|
11771
|
+
break;
|
|
11772
|
+
}
|
|
11458
11773
|
if (counts.providerFailure) {
|
|
11459
11774
|
lastProviderFailure = counts.providerFailure;
|
|
11460
11775
|
if (counts.providerFailure.fingerprint === priorProviderFailureFingerprint) {
|
|
@@ -11543,6 +11858,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
11543
11858
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
11544
11859
|
}
|
|
11545
11860
|
}, {
|
|
11861
|
+
transport: createPromptAsyncTransport(client, agentSessionId),
|
|
11546
11862
|
timeoutMs: sliceMs,
|
|
11547
11863
|
signal,
|
|
11548
11864
|
fallbackModels: args.fallbackModels,
|
|
@@ -11577,8 +11893,24 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
11577
11893
|
const providerFailure = error instanceof DreamerProviderOutputFailureError ? error : undefined;
|
|
11578
11894
|
const promptFailure = getPromptFailureDetail(error);
|
|
11579
11895
|
log(`[dreamer] verify batch ${providerFailure ? "provider failure" : "failed"}: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
|
|
11580
|
-
recordInvocation4(args, startedAt, {
|
|
11581
|
-
|
|
11896
|
+
recordInvocation4(args, startedAt, {
|
|
11897
|
+
status: failedInvocationStatus(error),
|
|
11898
|
+
error,
|
|
11899
|
+
messages: await readFailedChildMessages(args.client, agentSessionId, args.sessionDirectory)
|
|
11900
|
+
});
|
|
11901
|
+
if (error instanceof DreamerModuleFailureError || signal.aborted)
|
|
11902
|
+
throw error;
|
|
11903
|
+
if (promptFailure?.failureClass === "provider_timeout" || isPromptTimeoutError(error)) {
|
|
11904
|
+
return {
|
|
11905
|
+
verified: 0,
|
|
11906
|
+
updated: 0,
|
|
11907
|
+
archived: 0,
|
|
11908
|
+
skipped: 0,
|
|
11909
|
+
refused: 0,
|
|
11910
|
+
timedOut: true
|
|
11911
|
+
};
|
|
11912
|
+
}
|
|
11913
|
+
if (promptFailure !== null && promptFailure.failureClass !== "parse_failed" && !providerFailure)
|
|
11582
11914
|
throw error;
|
|
11583
11915
|
return {
|
|
11584
11916
|
verified: 0,
|
|
@@ -11820,6 +12152,16 @@ function dreamRunFailureDetail(error) {
|
|
|
11820
12152
|
}
|
|
11821
12153
|
const described = describeError(error);
|
|
11822
12154
|
const message = described.brief;
|
|
12155
|
+
if (error instanceof Error && error.name === "HiddenAgentStepLimit") {
|
|
12156
|
+
return {
|
|
12157
|
+
failure_class: "step_limit",
|
|
12158
|
+
model_attempted: null,
|
|
12159
|
+
models_tried: [],
|
|
12160
|
+
provider_error: null,
|
|
12161
|
+
timeout_ms: null,
|
|
12162
|
+
child_session_id: null
|
|
12163
|
+
};
|
|
12164
|
+
}
|
|
11823
12165
|
const providerFailure = error instanceof HiddenCompletionRefusal || error instanceof Error && error.name === "DreamerProviderOutputFailureError";
|
|
11824
12166
|
return {
|
|
11825
12167
|
failure_class: providerFailure ? "provider_error" : /no models?|model chain is empty/i.test(message) ? "no_models" : "unknown",
|
|
@@ -11959,11 +12301,16 @@ function createDreamTaskExecutor(deps) {
|
|
|
11959
12301
|
});
|
|
11960
12302
|
};
|
|
11961
12303
|
reportProgress(0);
|
|
12304
|
+
if (config.modelChainUnavailable) {
|
|
12305
|
+
return {
|
|
12306
|
+
status: "completed",
|
|
12307
|
+
detail: "skipped: Pi model chain is empty (no configured model resolves in Pi)"
|
|
12308
|
+
};
|
|
12309
|
+
}
|
|
11962
12310
|
const incompleteMessage = (remaining) => {
|
|
11963
12311
|
const processed = processedDreamTaskItems(backlogAtStart.pending, remaining);
|
|
11964
12312
|
return `${config.task} incomplete: ${remaining} remain (was ${backlogAtStart.pending} at run start; processed ${processed} this run)`;
|
|
11965
12313
|
};
|
|
11966
|
-
const parent = await resolveParentSessionId();
|
|
11967
12314
|
let moduleRoute;
|
|
11968
12315
|
if (config.task === "curate" || config.task === "map-memories" || config.task === "compress-cues" || config.task === "classify-memories" || config.task === "verify" || config.task === "verify-broad" || config.task === "retrospective") {
|
|
11969
12316
|
try {
|
|
@@ -11979,6 +12326,19 @@ function createDreamTaskExecutor(deps) {
|
|
|
11979
12326
|
throw new DreamerModuleFailureError("authority.status", error);
|
|
11980
12327
|
}
|
|
11981
12328
|
}
|
|
12329
|
+
if (!moduleRoute && getAuthorityManagedMarker(db, projectIdentity) && [
|
|
12330
|
+
"curate",
|
|
12331
|
+
"map-memories",
|
|
12332
|
+
"compress-cues",
|
|
12333
|
+
"classify-memories",
|
|
12334
|
+
"verify",
|
|
12335
|
+
"verify-broad",
|
|
12336
|
+
"retrospective"
|
|
12337
|
+
].includes(config.task)) {
|
|
12338
|
+
logDreamerNotOwnerOnce(projectIdentity);
|
|
12339
|
+
return { status: "completed", detail: "skipped: module-managed memory; not owner" };
|
|
12340
|
+
}
|
|
12341
|
+
const parent = await resolveParentSessionId();
|
|
11982
12342
|
if (!leaseOwnershipMatches(db, holderId, leaseAcquisition.generation, leaseKey)) {
|
|
11983
12343
|
throw new Error("Dream lease lost during executor setup");
|
|
11984
12344
|
}
|
|
@@ -12168,13 +12528,14 @@ function createDreamTaskExecutor(deps) {
|
|
|
12168
12528
|
});
|
|
12169
12529
|
return { status: "completed" };
|
|
12170
12530
|
}
|
|
12171
|
-
const
|
|
12531
|
+
const batchTimedOut = result.stopReason === "batch-timeout";
|
|
12532
|
+
const error = batchTimedOut ? `${config.task}: a batch timed out within its time slice; ${result.remaining} remain` : incompleteMessage(result.remaining);
|
|
12172
12533
|
recordRun("failed", error, {
|
|
12173
12534
|
progress: verificationProgress,
|
|
12174
12535
|
memoryChanges: computeMemoryDelta(memoryBefore),
|
|
12175
12536
|
backlogAfter
|
|
12176
12537
|
});
|
|
12177
|
-
return { status: "failed", transient:
|
|
12538
|
+
return { status: "failed", transient: !batchTimedOut, error };
|
|
12178
12539
|
}
|
|
12179
12540
|
recordRun("completed", null, {
|
|
12180
12541
|
progress: verificationProgress,
|
|
@@ -13000,25 +13361,45 @@ function ensureSeeded(db, projectIdentity, config, now) {
|
|
|
13000
13361
|
const nextDueAt = nextDueAtMs(config.schedule, now);
|
|
13001
13362
|
seedTaskScheduleState(db, projectIdentity, config.task, nextDueAt, lastRunAt, config.schedule);
|
|
13002
13363
|
}
|
|
13364
|
+
function firstRepeatedCivilMinute(candidateMs) {
|
|
13365
|
+
const date = new Date(candidateMs);
|
|
13366
|
+
const first = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes()).getTime();
|
|
13367
|
+
return first < candidateMs ? first : null;
|
|
13368
|
+
}
|
|
13003
13369
|
function reconcileSchedule(db, projectIdentity, config, now) {
|
|
13004
13370
|
ensureSeeded(db, projectIdentity, config, now);
|
|
13005
|
-
|
|
13006
|
-
if (!stored || stored.schedule === config.schedule)
|
|
13007
|
-
return;
|
|
13008
|
-
if (config.schedule.trim() === "") {
|
|
13009
|
-
writeTaskScheduleState(db, { ...stored, schedule: config.schedule, nextDueAt: null });
|
|
13010
|
-
return;
|
|
13011
|
-
}
|
|
13012
|
-
if (stored.schedule === null && stored.nextDueAt !== null) {
|
|
13013
|
-
writeTaskScheduleState(db, { ...stored, schedule: config.schedule });
|
|
13371
|
+
if (getTaskScheduleState(db, projectIdentity, config.task)?.schedule === config.schedule)
|
|
13014
13372
|
return;
|
|
13373
|
+
const candidate = nextDueAtMs(config.schedule, now);
|
|
13374
|
+
const repeatedFirst = candidate === null ? null : firstRepeatedCivilMinute(candidate);
|
|
13375
|
+
const afterRepeatedFirst = repeatedFirst === null ? candidate : nextDueAtMs(config.schedule, now, repeatedFirst);
|
|
13376
|
+
db.exec("BEGIN IMMEDIATE");
|
|
13377
|
+
let committed = false;
|
|
13378
|
+
try {
|
|
13379
|
+
const stored = getTaskScheduleState(db, projectIdentity, config.task);
|
|
13380
|
+
if (stored && stored.schedule !== config.schedule) {
|
|
13381
|
+
if (stored.schedule === null && stored.nextDueAt !== null) {
|
|
13382
|
+
writeTaskScheduleState(db, { ...stored, schedule: config.schedule });
|
|
13383
|
+
} else {
|
|
13384
|
+
const nextDueAt = repeatedFirst !== null && candidate !== null && stored.nextDueAt !== null && stored.nextDueAt > candidate && stored.lastStatus !== null ? afterRepeatedFirst : candidate;
|
|
13385
|
+
const reconciledNextDueAt = stored.nextDueAt === null ? nextDueAt : nextDueAt === null ? stored.nextDueAt : Math.min(stored.nextDueAt, nextDueAt);
|
|
13386
|
+
writeTaskScheduleState(db, {
|
|
13387
|
+
...stored,
|
|
13388
|
+
schedule: config.schedule,
|
|
13389
|
+
nextDueAt: reconciledNextDueAt,
|
|
13390
|
+
retryCount: reconciledNextDueAt === stored.nextDueAt ? stored.retryCount : 0
|
|
13391
|
+
});
|
|
13392
|
+
}
|
|
13393
|
+
}
|
|
13394
|
+
db.exec("COMMIT");
|
|
13395
|
+
committed = true;
|
|
13396
|
+
} finally {
|
|
13397
|
+
if (!committed) {
|
|
13398
|
+
try {
|
|
13399
|
+
db.exec("ROLLBACK");
|
|
13400
|
+
} catch {}
|
|
13401
|
+
}
|
|
13015
13402
|
}
|
|
13016
|
-
writeTaskScheduleState(db, {
|
|
13017
|
-
...stored,
|
|
13018
|
-
schedule: config.schedule,
|
|
13019
|
-
nextDueAt: nextDueAtMs(config.schedule, now),
|
|
13020
|
-
retryCount: 0
|
|
13021
|
-
});
|
|
13022
13403
|
}
|
|
13023
13404
|
function planDueTasks(db, projectIdentity, tasks, now) {
|
|
13024
13405
|
const pruned = pruneNonCanonicalTaskRows(db, projectIdentity, CANONICAL_DREAM_TASKS);
|
|
@@ -13027,6 +13408,8 @@ function planDueTasks(db, projectIdentity, tasks, now) {
|
|
|
13027
13408
|
}
|
|
13028
13409
|
const due = [];
|
|
13029
13410
|
for (const config of tasks) {
|
|
13411
|
+
if (config.schedule.trim() === "")
|
|
13412
|
+
continue;
|
|
13030
13413
|
reconcileSchedule(db, projectIdentity, config, now);
|
|
13031
13414
|
const state = getTaskScheduleState(db, projectIdentity, config.task);
|
|
13032
13415
|
if (!state || state.nextDueAt === null)
|
|
@@ -13112,10 +13495,11 @@ async function runDomainGroup(deps, group, cb) {
|
|
|
13112
13495
|
}
|
|
13113
13496
|
try {
|
|
13114
13497
|
for (const due of [...group].sort((a, b) => compareTaskOrder(a.config.task, b.config.task))) {
|
|
13115
|
-
if (!
|
|
13498
|
+
if (!reacquireOwnedLease(db, holderId, leaseKey, acquisition.generation)) {
|
|
13116
13499
|
log(`[dreamer] domain lease lost (${leaseKey}) — stopping remaining task(s)`);
|
|
13117
13500
|
break;
|
|
13118
13501
|
}
|
|
13502
|
+
acquisition = { acquiredAt: Date.now(), generation: acquisition.generation };
|
|
13119
13503
|
if (!cb?.forceGate) {
|
|
13120
13504
|
const gatePass = evaluateTaskGate(due.config.task, {
|
|
13121
13505
|
db,
|
|
@@ -13170,6 +13554,8 @@ async function runManualDream(deps) {
|
|
|
13170
13554
|
backlogBefore: {},
|
|
13171
13555
|
backlogAfter: {}
|
|
13172
13556
|
};
|
|
13557
|
+
if (!isUsableProjectIdentity(deps.projectIdentity))
|
|
13558
|
+
return result;
|
|
13173
13559
|
let selected;
|
|
13174
13560
|
let forceGate = false;
|
|
13175
13561
|
if (deps.task) {
|
|
@@ -13243,6 +13629,8 @@ async function runManualDream(deps) {
|
|
|
13243
13629
|
return result;
|
|
13244
13630
|
}
|
|
13245
13631
|
async function runDueTasksForProject(deps) {
|
|
13632
|
+
if (!isUsableProjectIdentity(deps.projectIdentity))
|
|
13633
|
+
return 0;
|
|
13246
13634
|
const now = deps.now ?? Date.now();
|
|
13247
13635
|
const due = planDueTasks(deps.db, deps.projectIdentity, deps.tasks, now);
|
|
13248
13636
|
if (due.length === 0)
|
|
@@ -13488,6 +13876,13 @@ function openTimerDatabaseOrNull(context) {
|
|
|
13488
13876
|
}
|
|
13489
13877
|
return db;
|
|
13490
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
|
+
}
|
|
13491
13886
|
var registeredProjects = new Map;
|
|
13492
13887
|
function stopDreamScheduleTimerIfIdle() {
|
|
13493
13888
|
if (registeredProjects.size !== 0)
|
|
@@ -13507,6 +13902,10 @@ function stopDreamScheduleTimerIfIdle() {
|
|
|
13507
13902
|
log("[dreamer] stopped dream schedule timer (no projects left)");
|
|
13508
13903
|
}
|
|
13509
13904
|
async function startDreamScheduleTimer(args) {
|
|
13905
|
+
if (!isUsableProjectIdentity(args.projectIdentity)) {
|
|
13906
|
+
logEmptyIdentityRefusalOnce(args.directory);
|
|
13907
|
+
return;
|
|
13908
|
+
}
|
|
13510
13909
|
beginBootQuietPeriod();
|
|
13511
13910
|
const db = openTimerDatabaseOrNull("schedule timer registration");
|
|
13512
13911
|
if (!db)
|
|
@@ -13704,7 +14103,8 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
13704
14103
|
}
|
|
13705
14104
|
const dreamerConfig = reg.dreamerConfig;
|
|
13706
14105
|
const dreamingEnabled = Boolean(dreamerConfig && dreamerConfig.disable !== true);
|
|
13707
|
-
const
|
|
14106
|
+
const configuredTasks = dreamingEnabled && dreamerConfig ? buildDreamTaskRuntimeConfigs(dreamerConfig, reg.harness, reg.language, reg.mural?.model) : [];
|
|
14107
|
+
const runtimeConfigs = reg.validateTaskModels?.(configuredTasks) ?? configuredTasks;
|
|
13708
14108
|
await sweepOrphanedInternalChildren(reg, runtimeConfigs.filter((config) => PRIVACY_SENSITIVE_CHILD_TASKS.includes(config.task)).map((config) => config.timeoutMinutes));
|
|
13709
14109
|
if (commitIndexingEnabled && reg.gitCommitIndexing) {
|
|
13710
14110
|
await sweepGitCommits({
|
|
@@ -13719,6 +14119,10 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
13719
14119
|
}
|
|
13720
14120
|
try {
|
|
13721
14121
|
await runCompiledSmartNoteSweep(reg, db);
|
|
14122
|
+
} catch (error) {
|
|
14123
|
+
log(`[dreamer] compiled smart-note sweep failed for ${reg.projectIdentity}:`, error);
|
|
14124
|
+
}
|
|
14125
|
+
try {
|
|
13722
14126
|
const executor = createDreamTaskExecutor({
|
|
13723
14127
|
client: reg.client,
|
|
13724
14128
|
sessionDirectory: reg.directory,
|
|
@@ -13773,6 +14177,10 @@ async function sweepOrphanedInternalChildren(reg, privacyTimeoutMinutes) {
|
|
|
13773
14177
|
}
|
|
13774
14178
|
}
|
|
13775
14179
|
async function runCompiledSmartNoteSweep(reg, db) {
|
|
14180
|
+
if (getAuthorityManagedMarker(db, reg.projectIdentity)) {
|
|
14181
|
+
logDreamerNotOwnerOnce(reg.projectIdentity);
|
|
14182
|
+
return;
|
|
14183
|
+
}
|
|
13776
14184
|
const leaseKey = leaseKeyFor("evaluate-smart-notes", reg.projectIdentity);
|
|
13777
14185
|
const holderId = crypto.randomUUID();
|
|
13778
14186
|
if (!acquireLease(db, holderId, leaseKey))
|
|
@@ -15062,13 +15470,101 @@ function terminateChild(child) {
|
|
|
15062
15470
|
}
|
|
15063
15471
|
}
|
|
15064
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
|
+
|
|
15065
15561
|
// src/dreamer/pi-session-api.ts
|
|
15066
15562
|
import { existsSync as existsSync8, readFileSync as readFileSync6, realpathSync as realpathSync4, statSync as statSync5 } from "node:fs";
|
|
15067
15563
|
import {
|
|
15068
15564
|
basename as basename2,
|
|
15069
15565
|
dirname as dirname2,
|
|
15070
15566
|
extname,
|
|
15071
|
-
join as
|
|
15567
|
+
join as join7,
|
|
15072
15568
|
relative,
|
|
15073
15569
|
resolve,
|
|
15074
15570
|
sep as sep2
|
|
@@ -15118,11 +15614,11 @@ function resolveRunningEntry() {
|
|
|
15118
15614
|
function findPackageRoot(startDir) {
|
|
15119
15615
|
let dir = startDir;
|
|
15120
15616
|
while (dir !== dirname2(dir)) {
|
|
15121
|
-
const pkg = readManifest(
|
|
15617
|
+
const pkg = readManifest(join7(dir, "package.json"));
|
|
15122
15618
|
if (isCodingAgentPackageName(pkg?.name)) {
|
|
15123
15619
|
if (basename2(dir) === "dist") {
|
|
15124
15620
|
const parentDir = dirname2(dir);
|
|
15125
|
-
const parentPkg = readManifest(
|
|
15621
|
+
const parentPkg = readManifest(join7(parentDir, "package.json"));
|
|
15126
15622
|
if (parentPkg?.name === pkg.name) {
|
|
15127
15623
|
return { dir: parentDir, pkg: parentPkg };
|
|
15128
15624
|
}
|
|
@@ -15181,7 +15677,7 @@ function toSourceEntry(entryPath, pkgDir) {
|
|
|
15181
15677
|
if (srcRel === rel) {
|
|
15182
15678
|
return null;
|
|
15183
15679
|
}
|
|
15184
|
-
return
|
|
15680
|
+
return join7(pkgDir, srcRel);
|
|
15185
15681
|
}
|
|
15186
15682
|
var defaultLoaders = [
|
|
15187
15683
|
{
|
|
@@ -15266,35 +15762,108 @@ async function loadDefaultPiSessionApi(loaders) {
|
|
|
15266
15762
|
}
|
|
15267
15763
|
|
|
15268
15764
|
// src/dreamer/primer-raw-provider-pi.ts
|
|
15269
|
-
|
|
15270
|
-
|
|
15271
|
-
|
|
15272
|
-
|
|
15273
|
-
|
|
15274
|
-
|
|
15275
|
-
|
|
15276
|
-
|
|
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)
|
|
15277
15823
|
}
|
|
15278
|
-
resolved ??= loadDefaultPiSessionApi();
|
|
15279
|
-
return resolved;
|
|
15280
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 = {}) {
|
|
15281
15849
|
return async (sessionId) => {
|
|
15282
15850
|
try {
|
|
15283
|
-
|
|
15284
|
-
|
|
15285
|
-
|
|
15286
|
-
|
|
15287
|
-
|
|
15288
|
-
|
|
15289
|
-
|
|
15290
|
-
|
|
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)
|
|
15291
15860
|
return null;
|
|
15292
15861
|
return {
|
|
15293
15862
|
readMessages() {
|
|
15294
|
-
|
|
15863
|
+
throw new Error("Pi primer history requires bounded pages");
|
|
15295
15864
|
},
|
|
15296
|
-
|
|
15297
|
-
return
|
|
15865
|
+
readMessagePage(after, limit, watermark) {
|
|
15866
|
+
return convertEntriesToRawMessagePage(summaryEntries(path), after, Math.min(50, limit), watermark);
|
|
15298
15867
|
}
|
|
15299
15868
|
};
|
|
15300
15869
|
} catch {
|
|
@@ -15304,17 +15873,22 @@ function createPiPrimerRawProviderFactory(deps = {}) {
|
|
|
15304
15873
|
}
|
|
15305
15874
|
|
|
15306
15875
|
// src/dreamer/retrospective-raw-provider-pi.ts
|
|
15307
|
-
import { resolve as resolve2 } from "node:path";
|
|
15876
|
+
import { join as join9, resolve as resolve2 } from "node:path";
|
|
15308
15877
|
class PiRetrospectiveRawProvider {
|
|
15309
15878
|
deps;
|
|
15310
15879
|
sessionPathById = new Map;
|
|
15311
|
-
resolvedDefaultDeps = null;
|
|
15312
15880
|
constructor(deps) {
|
|
15313
15881
|
this.deps = deps;
|
|
15314
15882
|
}
|
|
15315
15883
|
async listProjectSessions(_projectIdentity) {
|
|
15316
|
-
|
|
15317
|
-
|
|
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) : [];
|
|
15318
15892
|
const projectCwd = resolve2(this.deps.projectCwd);
|
|
15319
15893
|
const result = [];
|
|
15320
15894
|
this.sessionPathById.clear();
|
|
@@ -15336,51 +15910,50 @@ class PiRetrospectiveRawProvider {
|
|
|
15336
15910
|
return result.sort((a, b) => (a.updatedAt ?? 0) - (b.updatedAt ?? 0));
|
|
15337
15911
|
}
|
|
15338
15912
|
async readUserMessagesSince(sessionId, sinceMs, capPerSession) {
|
|
15339
|
-
const all = await this.loadUserEntries(sessionId);
|
|
15340
15913
|
const limit = Math.max(1, Math.floor(capPerSession));
|
|
15341
|
-
const
|
|
15914
|
+
const messages = await this.selectUserEntries(sessionId, (ts) => ts > sinceMs, limit + 1, false);
|
|
15342
15915
|
return {
|
|
15343
|
-
messages:
|
|
15344
|
-
truncated:
|
|
15916
|
+
messages: messages.slice(0, limit),
|
|
15917
|
+
truncated: messages.length > limit
|
|
15345
15918
|
};
|
|
15346
15919
|
}
|
|
15347
15920
|
async readOldestMessageTimesSince(sessionIds, sinceMs) {
|
|
15348
15921
|
const out = new Map;
|
|
15349
15922
|
for (const sessionId of sessionIds) {
|
|
15350
|
-
const oldest =
|
|
15923
|
+
const [oldest] = await this.selectUserEntries(sessionId, (ts) => ts > sinceMs, 1, false);
|
|
15351
15924
|
if (oldest)
|
|
15352
15925
|
out.set(sessionId, oldest.ts);
|
|
15353
15926
|
}
|
|
15354
15927
|
return out;
|
|
15355
15928
|
}
|
|
15356
15929
|
async readUserMessagesBefore(sessionId, beforeMs, count) {
|
|
15357
|
-
|
|
15358
|
-
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);
|
|
15359
15931
|
}
|
|
15360
|
-
async
|
|
15932
|
+
async selectUserEntries(sessionId, eligible, limit, newest) {
|
|
15361
15933
|
const filePath = this.sessionPathById.get(sessionId);
|
|
15362
15934
|
if (!filePath)
|
|
15363
15935
|
return [];
|
|
15364
|
-
const
|
|
15365
|
-
let entries;
|
|
15936
|
+
const kept = [];
|
|
15366
15937
|
try {
|
|
15367
|
-
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
|
+
}
|
|
15368
15953
|
} catch {
|
|
15369
15954
|
return [];
|
|
15370
15955
|
}
|
|
15371
|
-
|
|
15372
|
-
return [];
|
|
15373
|
-
return entries.map((entry, index) => normalizePiUserEntry(entry, sessionId, index + 1)).filter((entry) => entry !== null);
|
|
15374
|
-
}
|
|
15375
|
-
async resolveDeps() {
|
|
15376
|
-
if (this.deps.listSessions && this.deps.loadEntriesFromFile) {
|
|
15377
|
-
return {
|
|
15378
|
-
listSessions: this.deps.listSessions,
|
|
15379
|
-
loadEntriesFromFile: this.deps.loadEntriesFromFile
|
|
15380
|
-
};
|
|
15381
|
-
}
|
|
15382
|
-
this.resolvedDefaultDeps ??= loadDefaultPiSessionApi();
|
|
15383
|
-
return this.resolvedDefaultDeps;
|
|
15956
|
+
return kept;
|
|
15384
15957
|
}
|
|
15385
15958
|
}
|
|
15386
15959
|
function normalizePiUserEntry(entry, sessionId, ordinal) {
|
|
@@ -15418,6 +15991,42 @@ function extractPiTextContent(content) {
|
|
|
15418
15991
|
}
|
|
15419
15992
|
|
|
15420
15993
|
// src/dreamer/index.ts
|
|
15994
|
+
var warnedUnknownModels = new Set;
|
|
15995
|
+
var modelAvailability = new WeakMap;
|
|
15996
|
+
function validatePiDreamerModels(tasks, registry, harness = "pi") {
|
|
15997
|
+
let resolved = modelAvailability.get(registry);
|
|
15998
|
+
if (!resolved) {
|
|
15999
|
+
resolved = new Map;
|
|
16000
|
+
modelAvailability.set(registry, resolved);
|
|
16001
|
+
}
|
|
16002
|
+
return tasks.map((task) => {
|
|
16003
|
+
const entries = [task.model, ...task.fallbackModels ?? []].filter((entry) => entry !== undefined);
|
|
16004
|
+
const valid = entries.filter((entry) => {
|
|
16005
|
+
const model = typeof entry === "string" ? entry : entry.model;
|
|
16006
|
+
if (harness === "omp" && model.startsWith("@"))
|
|
16007
|
+
return true;
|
|
16008
|
+
let available = resolved.get(model);
|
|
16009
|
+
if (available === undefined) {
|
|
16010
|
+
const separator = model.indexOf("/");
|
|
16011
|
+
available = separator > 0 && Boolean(registry.find(model.slice(0, separator), model.slice(separator + 1)));
|
|
16012
|
+
resolved.set(model, available);
|
|
16013
|
+
}
|
|
16014
|
+
if (available)
|
|
16015
|
+
return true;
|
|
16016
|
+
if (!warnedUnknownModels.has(model)) {
|
|
16017
|
+
log(`[dreamer] WARNING: dropping Pi model not found: ${model}`);
|
|
16018
|
+
warnedUnknownModels.add(model);
|
|
16019
|
+
}
|
|
16020
|
+
return false;
|
|
16021
|
+
});
|
|
16022
|
+
return {
|
|
16023
|
+
...task,
|
|
16024
|
+
model: valid[0],
|
|
16025
|
+
fallbackModels: valid.slice(1),
|
|
16026
|
+
modelChainUnavailable: entries.length > 0 && valid.length === 0
|
|
16027
|
+
};
|
|
16028
|
+
});
|
|
16029
|
+
}
|
|
15421
16030
|
var PI_DREAMER_PROJECTS = Symbol.for("magic-context.pi.dreamer-registered-projects");
|
|
15422
16031
|
function getRegisteredProjects() {
|
|
15423
16032
|
const globals = globalThis;
|
|
@@ -15446,7 +16055,8 @@ var sessionCounter = 0;
|
|
|
15446
16055
|
var piSubagentRunnerFactory = () => new PiSubagentRunner;
|
|
15447
16056
|
var startDreamScheduleTimerFn = startDreamScheduleTimer;
|
|
15448
16057
|
function registerPiDreamerProject(opts) {
|
|
15449
|
-
|
|
16058
|
+
const directory = resolve3(opts.projectDir);
|
|
16059
|
+
if (opts.config.disable === true || !isUsableProjectIdentity(opts.projectIdentity) || directory === parse(directory).root || directory === homedir2()) {
|
|
15450
16060
|
return;
|
|
15451
16061
|
}
|
|
15452
16062
|
const existing = registeredProjects2.get(opts.projectIdentity);
|
|
@@ -15459,7 +16069,7 @@ function registerPiDreamerProject(opts) {
|
|
|
15459
16069
|
callback(projectIdentity);
|
|
15460
16070
|
};
|
|
15461
16071
|
if (existing) {
|
|
15462
|
-
if (existing.generation && existing.projectDir === opts.projectDir) {
|
|
16072
|
+
if (existing.generation && existing.projectDir === opts.projectDir && (!opts.modelRegistry || existing.modelRegistry)) {
|
|
15463
16073
|
return;
|
|
15464
16074
|
}
|
|
15465
16075
|
existing.cleanup();
|
|
@@ -15469,15 +16079,17 @@ function registerPiDreamerProject(opts) {
|
|
|
15469
16079
|
const client = createPiDreamerClient(opts, notifyOwnersOfAdjunctRefresh, () => {
|
|
15470
16080
|
const current = registeredProjects2.get(opts.projectIdentity);
|
|
15471
16081
|
return current?.generation === generation && current.owners.get(opts.registrationOwner)?.projectDir === opts.projectDir;
|
|
15472
|
-
});
|
|
16082
|
+
}, () => opts.sampleDreamRun ? opts.sampleDreamRun().dreamerConfig?.maxTokens : opts.config.maxTokens);
|
|
15473
16083
|
let cleanup;
|
|
15474
16084
|
let cancelled = false;
|
|
16085
|
+
const modelRegistry = opts.modelRegistry;
|
|
15475
16086
|
startDreamScheduleTimerFn({
|
|
15476
16087
|
directory: opts.projectDir,
|
|
15477
16088
|
projectIdentity: opts.projectIdentity,
|
|
15478
16089
|
harness: opts.harness,
|
|
15479
16090
|
client,
|
|
15480
16091
|
dreamerConfig: opts.config,
|
|
16092
|
+
validateTaskModels: modelRegistry ? (tasks) => validatePiDreamerModels(tasks, modelRegistry, opts.harness) : undefined,
|
|
15481
16093
|
sampleDreamRun: opts.sampleDreamRun,
|
|
15482
16094
|
language: opts.language,
|
|
15483
16095
|
gitCommitIndexing: opts.gitCommitIndexing,
|
|
@@ -15505,11 +16117,11 @@ function registerPiDreamerProject(opts) {
|
|
|
15505
16117
|
const sampled = manualOpts.sampleDreamRun?.();
|
|
15506
16118
|
const dreamerConfig = sampled?.dreamerConfig ?? manualOpts.config;
|
|
15507
16119
|
const mural = sampled?.mural ?? manualOpts.mural;
|
|
15508
|
-
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);
|
|
15509
16121
|
const manualRun = runManualDream({
|
|
15510
16122
|
db: manualOpts.db,
|
|
15511
16123
|
projectIdentity: manualOpts.projectIdentity,
|
|
15512
|
-
tasks: 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),
|
|
15513
16125
|
executor: createDreamTaskExecutor({
|
|
15514
16126
|
client: manualClient,
|
|
15515
16127
|
sessionDirectory: manualOpts.projectDir,
|
|
@@ -15542,7 +16154,8 @@ function registerPiDreamerProject(opts) {
|
|
|
15542
16154
|
cleanup?.();
|
|
15543
16155
|
},
|
|
15544
16156
|
runManual,
|
|
15545
|
-
projectDir: opts.projectDir
|
|
16157
|
+
projectDir: opts.projectDir,
|
|
16158
|
+
modelRegistry: opts.modelRegistry
|
|
15546
16159
|
});
|
|
15547
16160
|
}
|
|
15548
16161
|
async function runPiDreamForProject(projectIdentity, task, registrationOwner) {
|
|
@@ -15584,7 +16197,7 @@ async function awaitInFlightDreamers(registrationOwner) {
|
|
|
15584
16197
|
return;
|
|
15585
16198
|
await Promise.allSettled(runs);
|
|
15586
16199
|
}
|
|
15587
|
-
function createPiDreamerClient(opts, onAdjunctsRefreshNeeded = opts.onAdjunctsRefreshNeeded, isRegistrationOwnerActive = () => true) {
|
|
16200
|
+
function createPiDreamerClient(opts, onAdjunctsRefreshNeeded = opts.onAdjunctsRefreshNeeded, isRegistrationOwnerActive = () => true, getMaxOutputTokens = () => opts.config.maxTokens) {
|
|
15588
16201
|
const runner = piSubagentRunnerFactory();
|
|
15589
16202
|
const assertRegistrationOwnerActive = () => {
|
|
15590
16203
|
if (!isRegistrationOwnerActive()) {
|
|
@@ -15625,6 +16238,7 @@ function createPiDreamerClient(opts, onAdjunctsRefreshNeeded = opts.onAdjunctsRe
|
|
|
15625
16238
|
cwd: dreamSession.directory,
|
|
15626
16239
|
signal: args.signal ?? undefined,
|
|
15627
16240
|
thinkingLevel: extractBodyVariant(args),
|
|
16241
|
+
maxOutputTokens: getMaxOutputTokens(),
|
|
15628
16242
|
accountingSessionId: opts.projectIdentity,
|
|
15629
16243
|
accountingSubagent: "dreamer",
|
|
15630
16244
|
accountingTask: accountingTaskFromTitle(dreamSession.title)
|
|
@@ -16054,7 +16668,7 @@ function formatEmbedStatusText(coverage, drain) {
|
|
|
16054
16668
|
lines.push(`Synapse — ${formatSynapseLaneDescriptor(coverage.synapseDescriptor)}`);
|
|
16055
16669
|
}
|
|
16056
16670
|
lines.push(`This session: ${coverage.session.embedded} / ${coverage.session.total} compartments embedded`);
|
|
16057
|
-
lines.push(`Project memories: ${coverage.memories.embedded} / ${coverage.memories.total} embedded`);
|
|
16671
|
+
lines.push(coverage.memories.memoryEnabled === false ? "Project memories: off (memory disabled)" : `Project memories: ${coverage.memories.embedded} / ${coverage.memories.total} embedded`);
|
|
16058
16672
|
if (coverage.commits.gitEnabled) {
|
|
16059
16673
|
lines.push(`Git commits: ${coverage.commits.embedded} / ${coverage.commits.total}`);
|
|
16060
16674
|
} else {
|
|
@@ -16230,7 +16844,6 @@ No active Pi session is available.`,
|
|
|
16230
16844
|
projectDir: deps.projectDir,
|
|
16231
16845
|
projectIdentity: deps.projectIdentity
|
|
16232
16846
|
};
|
|
16233
|
-
const memoryEnabled = deps.resolveMemoryEnabled?.(ctx) ?? deps.memoryEnabled;
|
|
16234
16847
|
const sub = args.trim().toLowerCase();
|
|
16235
16848
|
if (sub === "pause") {
|
|
16236
16849
|
embedPauseBySession.add(sessionId);
|
|
@@ -16247,16 +16860,6 @@ Paused at ${cov.session.embedded}/${cov.session.total} compartments embedded.`,
|
|
|
16247
16860
|
});
|
|
16248
16861
|
return;
|
|
16249
16862
|
}
|
|
16250
|
-
if (memoryEnabled === false) {
|
|
16251
|
-
sendStatus({
|
|
16252
|
-
title: "/ctx-embed",
|
|
16253
|
-
text: `## /ctx-embed
|
|
16254
|
-
|
|
16255
|
-
Memory is disabled for this project, so there is no semantic embedding to backfill.`,
|
|
16256
|
-
level: "info"
|
|
16257
|
-
});
|
|
16258
|
-
return;
|
|
16259
|
-
}
|
|
16260
16863
|
await ensureProjectRegisteredFromPiDirectory(project.projectDir, deps.db);
|
|
16261
16864
|
if (sub === "start") {
|
|
16262
16865
|
const { text, level } = await runEmbedDrain(deps.db, project.projectIdentity, sessionId, {
|
|
@@ -16289,13 +16892,13 @@ ${statusText}`,
|
|
|
16289
16892
|
}
|
|
16290
16893
|
});
|
|
16291
16894
|
}
|
|
16292
|
-
function maybeAutoEmbedPiSession(deps, sessionId, projectDir, projectIdentity
|
|
16895
|
+
function maybeAutoEmbedPiSession(deps, sessionId, projectDir, projectIdentity) {
|
|
16896
|
+
if (!isUsableProjectIdentity(projectIdentity))
|
|
16897
|
+
return;
|
|
16293
16898
|
if (autoEmbedAttemptedBySession.has(sessionId))
|
|
16294
16899
|
return;
|
|
16295
16900
|
if (embedPauseBySession.has(sessionId))
|
|
16296
16901
|
return;
|
|
16297
|
-
if (deps.memoryEnabled === false)
|
|
16298
|
-
return;
|
|
16299
16902
|
autoEmbedAttemptedBySession.add(sessionId);
|
|
16300
16903
|
(async () => {
|
|
16301
16904
|
let drainReachedTerminal = false;
|
|
@@ -16331,7 +16934,7 @@ function executeFlush(db, sessionId) {
|
|
|
16331
16934
|
removePendingOp(db, sessionId, op.tagId);
|
|
16332
16935
|
dropped++;
|
|
16333
16936
|
}
|
|
16334
|
-
})();
|
|
16937
|
+
}).immediate();
|
|
16335
16938
|
const parts = [];
|
|
16336
16939
|
if (dropped > 0)
|
|
16337
16940
|
parts.push(`${dropped} dropped`);
|
|
@@ -16440,6 +17043,135 @@ function commitPiCompactionModeRecord(db, sessionId, record) {
|
|
|
16440
17043
|
// src/context-handler.ts
|
|
16441
17044
|
import * as crypto3 from "node:crypto";
|
|
16442
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
|
+
|
|
16443
17175
|
// ../plugin/src/features/magic-context/scheduler.ts
|
|
16444
17176
|
var TTL_PATTERN = /^(\d+)([smh])$/;
|
|
16445
17177
|
var NUMERIC_PATTERN = /^\d+$/;
|
|
@@ -16630,7 +17362,7 @@ function createTagger() {
|
|
|
16630
17362
|
db.transaction(() => {
|
|
16631
17363
|
getUpsertCounterStatement(db).run(sessionId, next, getHarness());
|
|
16632
17364
|
insertTag(db, sessionId, messageId, type, byteSize, next, reasoningByteSize, toolName, inputByteSize, toolOwnerMessageId, entryFingerprint, tokenCounts);
|
|
16633
|
-
})();
|
|
17365
|
+
}).immediate();
|
|
16634
17366
|
} catch (error) {
|
|
16635
17367
|
if (!isUniqueConstraintError(error)) {
|
|
16636
17368
|
throw error;
|
|
@@ -16866,7 +17598,8 @@ var canonicalReasons = new Set([
|
|
|
16866
17598
|
"ttl_expiry",
|
|
16867
17599
|
"epoch_change",
|
|
16868
17600
|
"coverage_fold",
|
|
16869
|
-
"profile_transition"
|
|
17601
|
+
"profile_transition",
|
|
17602
|
+
"host_compaction"
|
|
16870
17603
|
]);
|
|
16871
17604
|
var piReasonAliases = {
|
|
16872
17605
|
project_memory_change: "project_memory_epoch",
|
|
@@ -17100,6 +17833,72 @@ var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
|
17100
17833
|
function buildReplacementContent(tagId) {
|
|
17101
17834
|
return `[dropped §${tagId}§]`;
|
|
17102
17835
|
}
|
|
17836
|
+
function applyNewToolDrop(target, options) {
|
|
17837
|
+
if (!target)
|
|
17838
|
+
return { result: "absent", mode: "full" };
|
|
17839
|
+
if (options.inWindow && hasSmallToolInput(target) || options.keepSkeleton === true || target.cannotRemove?.() === true) {
|
|
17840
|
+
const strip = target.hasAttachments?.() === true;
|
|
17841
|
+
return {
|
|
17842
|
+
result: (strip ? target.skeletonStripped?.() : target.skeletonReal?.()) ?? "absent",
|
|
17843
|
+
mode: strip ? "skeleton_stripped" : "skeleton_real"
|
|
17844
|
+
};
|
|
17845
|
+
}
|
|
17846
|
+
const result = target.drop?.() ?? "absent";
|
|
17847
|
+
if (result === "truncated" && target.hasAttachments?.() === true) {
|
|
17848
|
+
return { result: target.skeletonStripped?.() ?? "absent", mode: "skeleton_stripped" };
|
|
17849
|
+
}
|
|
17850
|
+
return { result, mode: result === "truncated" ? "skeleton_real" : "full" };
|
|
17851
|
+
}
|
|
17852
|
+
function hasSmallToolInput(target) {
|
|
17853
|
+
const bytes = target?.inputStringBytes?.() ?? null;
|
|
17854
|
+
return bytes !== null && bytes <= SKELETON_REAL_INPUT_MAX_BYTES;
|
|
17855
|
+
}
|
|
17856
|
+
var CACHE_LOSING_FOLD_REASONS = new Set([
|
|
17857
|
+
"model_change",
|
|
17858
|
+
"system_hash",
|
|
17859
|
+
"ttl_idle",
|
|
17860
|
+
"host_compaction"
|
|
17861
|
+
]);
|
|
17862
|
+
function sameBytes(left, right) {
|
|
17863
|
+
if (left === null || right === null)
|
|
17864
|
+
return left === right;
|
|
17865
|
+
return Buffer.compare(Buffer.from(left), Buffer.from(right)) === 0;
|
|
17866
|
+
}
|
|
17867
|
+
function foldChangesServedPrefix(before, after) {
|
|
17868
|
+
if (!sameBytes(before.m0Bytes, after.m0Bytes))
|
|
17869
|
+
return true;
|
|
17870
|
+
if (!sameBytes(before.m1Bytes, after.m1Bytes))
|
|
17871
|
+
return true;
|
|
17872
|
+
return before.muralDataUrl !== after.muralDataUrl;
|
|
17873
|
+
}
|
|
17874
|
+
function foldBustsServedPrefix(reason, before, after) {
|
|
17875
|
+
return CACHE_LOSING_FOLD_REASONS.has(reason ?? "") || foldChangesServedPrefix(before, after);
|
|
17876
|
+
}
|
|
17877
|
+
function convertLegacyToolSkeletons(db, sessionId, targets) {
|
|
17878
|
+
const rows = db.prepare(`SELECT tag_number AS tagNumber, drop_mode AS dropMode
|
|
17879
|
+
FROM tags
|
|
17880
|
+
WHERE session_id = ? AND type = 'tool' AND status = 'dropped'
|
|
17881
|
+
AND drop_mode IN ('truncated', 'full')
|
|
17882
|
+
ORDER BY tag_number`).all(sessionId);
|
|
17883
|
+
const converted = new Map;
|
|
17884
|
+
for (const row of rows) {
|
|
17885
|
+
const target = targets.get(row.tagNumber);
|
|
17886
|
+
if (target?.canDrop?.() !== true)
|
|
17887
|
+
continue;
|
|
17888
|
+
const cannotRemove = target.cannotRemove?.() === true || target.requiresToolArcSkeleton === true || target.wouldStrandConversationEnd?.() === true;
|
|
17889
|
+
let mode;
|
|
17890
|
+
if (row.dropMode === "full") {
|
|
17891
|
+
if (target.cannotRemove?.() !== true)
|
|
17892
|
+
continue;
|
|
17893
|
+
mode = "skeleton_real";
|
|
17894
|
+
} else {
|
|
17895
|
+
mode = hasSmallToolInput(target) || cannotRemove ? "skeleton_real" : "full";
|
|
17896
|
+
}
|
|
17897
|
+
updateTagDropMode(db, sessionId, row.tagNumber, mode);
|
|
17898
|
+
converted.set(row.tagNumber, mode);
|
|
17899
|
+
}
|
|
17900
|
+
return converted;
|
|
17901
|
+
}
|
|
17103
17902
|
function applyPendingOperations(sessionId, db, targets, protectedTagIds, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set, onTagReduced, onBatchComplete) {
|
|
17104
17903
|
let didMutateMessage = false;
|
|
17105
17904
|
let diagnostics;
|
|
@@ -17159,7 +17958,8 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
|
|
|
17159
17958
|
let shouldPersistDrop = false;
|
|
17160
17959
|
if (isToolTag) {
|
|
17161
17960
|
if (editMarkerTagIds.has(pendingOp.tagId)) {
|
|
17162
|
-
const
|
|
17961
|
+
const strip = target?.hasAttachments?.() === true;
|
|
17962
|
+
const markResult = (strip ? target?.editMarkerStripped?.() : target?.editMarker?.()) ?? "absent";
|
|
17163
17963
|
if (markResult === "incomplete" || markResult === "absent") {
|
|
17164
17964
|
reject(`edit_marker_${markResult}`);
|
|
17165
17965
|
continue;
|
|
@@ -17167,34 +17967,23 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
|
|
|
17167
17967
|
didMutateMessage = true;
|
|
17168
17968
|
operationMutated = true;
|
|
17169
17969
|
onTagReduced?.({ tagNumber: pendingOp.tagId, mode: "edit_marker" });
|
|
17170
|
-
updateTagDropMode(db, sessionId, pendingOp.tagId, "edit_marker");
|
|
17171
|
-
shouldPersistDrop = true;
|
|
17172
|
-
} else if (skeletonWindow.has(pendingOp.tagId)) {
|
|
17173
|
-
const truncResult = target?.truncate?.() ?? "absent";
|
|
17174
|
-
if (truncResult === "incomplete" || synthetic && truncResult !== "truncated") {
|
|
17175
|
-
reject(`truncate_${truncResult}`);
|
|
17176
|
-
continue;
|
|
17177
|
-
}
|
|
17178
|
-
if (truncResult === "truncated") {
|
|
17179
|
-
didMutateMessage = true;
|
|
17180
|
-
operationMutated = true;
|
|
17181
|
-
onTagReduced?.({ tagNumber: pendingOp.tagId, mode: "truncated" });
|
|
17182
|
-
} else {
|
|
17183
|
-
reject(`truncate_${truncResult}`);
|
|
17184
|
-
}
|
|
17185
|
-
updateTagDropMode(db, sessionId, pendingOp.tagId, "truncated");
|
|
17970
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, strip ? "edit_marker_stripped" : "edit_marker");
|
|
17186
17971
|
shouldPersistDrop = true;
|
|
17187
17972
|
} else {
|
|
17188
|
-
const dropResult = target
|
|
17973
|
+
const { result: dropResult, mode: appliedMode } = applyNewToolDrop(target, {
|
|
17974
|
+
inWindow: skeletonWindow.has(pendingOp.tagId)
|
|
17975
|
+
});
|
|
17189
17976
|
if (dropResult === "incomplete" || synthetic && dropResult !== "removed" && dropResult !== "truncated") {
|
|
17190
17977
|
reject(`drop_${dropResult}`);
|
|
17191
17978
|
continue;
|
|
17192
17979
|
}
|
|
17193
|
-
const appliedMode = dropResult === "truncated" ? "truncated" : "full";
|
|
17194
17980
|
if (dropResult === "removed" || dropResult === "truncated") {
|
|
17195
17981
|
didMutateMessage = true;
|
|
17196
17982
|
operationMutated = true;
|
|
17197
|
-
onTagReduced?.({
|
|
17983
|
+
onTagReduced?.({
|
|
17984
|
+
tagNumber: pendingOp.tagId,
|
|
17985
|
+
mode: appliedMode === "full" ? "full" : "truncated"
|
|
17986
|
+
});
|
|
17198
17987
|
} else {
|
|
17199
17988
|
reject(`drop_${dropResult}`);
|
|
17200
17989
|
}
|
|
@@ -17261,11 +18050,24 @@ function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
|
|
|
17261
18050
|
if (tag.status === "dropped") {
|
|
17262
18051
|
const target = targets.get(tag.tagNumber);
|
|
17263
18052
|
if (tag.type === "tool") {
|
|
17264
|
-
if (tag.dropMode === "
|
|
18053
|
+
if (tag.dropMode === "edit_marker_stripped") {
|
|
18054
|
+
const result = target?.editMarkerStripped?.() ?? "absent";
|
|
18055
|
+
if (result === "truncated")
|
|
18056
|
+
didMutateMessage = true;
|
|
18057
|
+
} else if (tag.dropMode === "edit_marker") {
|
|
17265
18058
|
const markResult = target?.editMarker?.() ?? "absent";
|
|
17266
18059
|
if (markResult === "truncated") {
|
|
17267
18060
|
didMutateMessage = true;
|
|
17268
18061
|
}
|
|
18062
|
+
} else if (tag.dropMode === "skeleton_stripped") {
|
|
18063
|
+
const result = target?.skeletonStripped?.() ?? "absent";
|
|
18064
|
+
if (result === "truncated")
|
|
18065
|
+
didMutateMessage = true;
|
|
18066
|
+
} else if (tag.dropMode === "skeleton_real") {
|
|
18067
|
+
const result = target?.skeletonReal?.() ?? "absent";
|
|
18068
|
+
if (result === "truncated") {
|
|
18069
|
+
didMutateMessage = true;
|
|
18070
|
+
}
|
|
17269
18071
|
} else if (tag.dropMode === "truncated") {
|
|
17270
18072
|
const truncResult = target?.truncate?.() ?? "absent";
|
|
17271
18073
|
if (truncResult === "truncated") {
|
|
@@ -17611,7 +18413,7 @@ function applyCavemanCleanup(sessionId, db, targets, tags, config) {
|
|
|
17611
18413
|
else if (targetDepth === DEPTH_ULTRA)
|
|
17612
18414
|
result.compressedToUltra += 1;
|
|
17613
18415
|
}
|
|
17614
|
-
})();
|
|
18416
|
+
}).immediate();
|
|
17615
18417
|
const total = result.compressedToLite + result.compressedToFull + result.compressedToUltra;
|
|
17616
18418
|
if (total > 0) {
|
|
17617
18419
|
sessionLog(sessionId, `caveman cleanup: compressed ${total} text tags (lite=${result.compressedToLite}, full=${result.compressedToFull}, ultra=${result.compressedToUltra})`);
|
|
@@ -19533,6 +20335,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19533
20335
|
let any = false;
|
|
19534
20336
|
for (const occ of occurrences) {
|
|
19535
20337
|
if (occ.kind === "tool_use" && occ.part.setToolInput) {
|
|
20338
|
+
occ.originalInput ??= occ.part.getToolInput?.() ?? undefined;
|
|
19536
20339
|
if (occ.part.setToolInput(droppedInputMarker(tagId)))
|
|
19537
20340
|
any = true;
|
|
19538
20341
|
} else if (setToolContentOrText(occ.part, sentinel)) {
|
|
@@ -19541,6 +20344,28 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19541
20344
|
}
|
|
19542
20345
|
return any ? "truncated" : "absent";
|
|
19543
20346
|
};
|
|
20347
|
+
const complete = () => occurrences.some((occ) => occ.kind === "tool_use") && occurrences.some((occ) => occ.kind === "tool_result");
|
|
20348
|
+
const skeletonReal = () => {
|
|
20349
|
+
if (!complete())
|
|
20350
|
+
return "incomplete";
|
|
20351
|
+
const sentinel = `[dropped §${tagId}§]`;
|
|
20352
|
+
let any = false;
|
|
20353
|
+
for (const occ of occurrences) {
|
|
20354
|
+
if (occ.kind === "tool_use") {
|
|
20355
|
+
if (occ.originalInput && occ.part.setToolInput?.(occ.originalInput))
|
|
20356
|
+
any = true;
|
|
20357
|
+
} else if (setToolContentOrText(occ.part, sentinel)) {
|
|
20358
|
+
any = true;
|
|
20359
|
+
}
|
|
20360
|
+
}
|
|
20361
|
+
return any ? "truncated" : "absent";
|
|
20362
|
+
};
|
|
20363
|
+
const cannotRemove = () => {
|
|
20364
|
+
if (requiresToolArcSkeleton)
|
|
20365
|
+
return true;
|
|
20366
|
+
const authorization = occurrences.map((occ) => occ.part.canRemove?.());
|
|
20367
|
+
return !occurrences.every((occ, index) => occ.part.remove && authorization[index] !== false);
|
|
20368
|
+
};
|
|
19544
20369
|
return {
|
|
19545
20370
|
measureReclaim(skeleton) {
|
|
19546
20371
|
let beforeTools = 0;
|
|
@@ -19551,7 +20376,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19551
20376
|
const before = occ.kind === "tool_use" ? JSON.stringify(occ.part.getToolInput?.() ?? {}) : occ.part.getText() ?? "";
|
|
19552
20377
|
beforeTools += estimateTokens(before);
|
|
19553
20378
|
if (skeleton || !removable) {
|
|
19554
|
-
const after = occ.kind === "tool_use" ?
|
|
20379
|
+
const after = occ.kind === "tool_use" ? before : `[dropped §${tagId}§]`;
|
|
19555
20380
|
afterTools += estimateTokens(after);
|
|
19556
20381
|
}
|
|
19557
20382
|
}
|
|
@@ -19580,8 +20405,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19580
20405
|
return occurrences[0]?.part.getText() ?? null;
|
|
19581
20406
|
},
|
|
19582
20407
|
drop() {
|
|
19583
|
-
|
|
19584
|
-
if (!complete)
|
|
20408
|
+
if (!complete())
|
|
19585
20409
|
return "incomplete";
|
|
19586
20410
|
if (!requiresToolArcSkeleton) {
|
|
19587
20411
|
const authorization = occurrences.map((occ) => occ.part.canRemove?.());
|
|
@@ -19589,7 +20413,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19589
20413
|
return "incomplete";
|
|
19590
20414
|
if (occurrences.every((occ, index) => occ.part.remove && authorization[index] !== false)) {
|
|
19591
20415
|
if (conversationEnd?.wouldStrand(occurrences))
|
|
19592
|
-
return
|
|
20416
|
+
return skeletonReal();
|
|
19593
20417
|
let removed = false;
|
|
19594
20418
|
for (const occ of occurrences)
|
|
19595
20419
|
removed = occ.part.remove?.() || removed;
|
|
@@ -19607,6 +20431,19 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19607
20431
|
return any ? "removed" : "absent";
|
|
19608
20432
|
},
|
|
19609
20433
|
truncate,
|
|
20434
|
+
skeletonReal,
|
|
20435
|
+
cannotRemove,
|
|
20436
|
+
inputStringBytes() {
|
|
20437
|
+
for (const occ of occurrences) {
|
|
20438
|
+
if (occ.kind !== "tool_use")
|
|
20439
|
+
continue;
|
|
20440
|
+
return toolInputStringBytes(occ.originalInput ?? occ.part.getToolInput?.() ?? null);
|
|
20441
|
+
}
|
|
20442
|
+
return null;
|
|
20443
|
+
},
|
|
20444
|
+
wouldStrandConversationEnd() {
|
|
20445
|
+
return conversationEnd?.wouldStrand(occurrences) ?? false;
|
|
20446
|
+
},
|
|
19610
20447
|
editMarker() {
|
|
19611
20448
|
const sentinel = `[dropped §${tagId}§]`;
|
|
19612
20449
|
let any = false;
|
|
@@ -19625,9 +20462,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19625
20462
|
}
|
|
19626
20463
|
return any ? "truncated" : "absent";
|
|
19627
20464
|
},
|
|
19628
|
-
canDrop
|
|
19629
|
-
return occurrences.some((occ) => occ.kind === "tool_use") && occurrences.some((occ) => occ.kind === "tool_result");
|
|
19630
|
-
},
|
|
20465
|
+
canDrop: complete,
|
|
19631
20466
|
requiresToolArcSkeleton,
|
|
19632
20467
|
readInput() {
|
|
19633
20468
|
for (const occ of occurrences) {
|
|
@@ -19673,6 +20508,15 @@ function buildToolTarget(part, message, tagId) {
|
|
|
19673
20508
|
const changed = part.setToolInput ? part.setToolInput(droppedInputMarker(tagId)) : setToolContentOrText(part, `[dropped §${tagId}§]`);
|
|
19674
20509
|
return changed ? "truncated" : "absent";
|
|
19675
20510
|
},
|
|
20511
|
+
skeletonReal() {
|
|
20512
|
+
if (part.setToolInput)
|
|
20513
|
+
return "truncated";
|
|
20514
|
+
return setToolContentOrText(part, `[dropped §${tagId}§]`) ? "truncated" : "absent";
|
|
20515
|
+
},
|
|
20516
|
+
cannotRemove: () => part.setToolInput !== undefined,
|
|
20517
|
+
inputStringBytes() {
|
|
20518
|
+
return part.setToolInput ? toolInputStringBytes(part.getToolInput?.() ?? null) : 0;
|
|
20519
|
+
},
|
|
19676
20520
|
message: {
|
|
19677
20521
|
info: { id: message.info.id, role: message.info.role },
|
|
19678
20522
|
parts: []
|
|
@@ -19917,6 +20761,8 @@ async function runAutoSearchHintForPi(args) {
|
|
|
19917
20761
|
}
|
|
19918
20762
|
if (found.index !== messages.length - 1)
|
|
19919
20763
|
return messages;
|
|
20764
|
+
if (!isUsableProjectIdentity(options.projectPath))
|
|
20765
|
+
return messages;
|
|
19920
20766
|
await args.ensureProjectRegistered?.();
|
|
19921
20767
|
const writeNoHintAndReconcile = (reason) => {
|
|
19922
20768
|
const outcome = appendAutoSearchHintDecision(db, sessionId, {
|
|
@@ -19946,7 +20792,7 @@ async function runAutoSearchHintForPi(args) {
|
|
|
19946
20792
|
try {
|
|
19947
20793
|
const snapshot = getProjectEmbeddingSnapshot(options.projectPath);
|
|
19948
20794
|
const memoryEnabled = snapshot?.features.memoryEnabled ?? true;
|
|
19949
|
-
const embeddingEnabled = snapshot ? snapshot.
|
|
20795
|
+
const embeddingEnabled = snapshot ? snapshot.historyEnabled : true;
|
|
19950
20796
|
const gitCommitsEnabled = snapshot?.gitCommitEnabled ?? false;
|
|
19951
20797
|
const searchOptions = {
|
|
19952
20798
|
limit: 10,
|
|
@@ -20010,6 +20856,8 @@ import * as crypto2 from "node:crypto";
|
|
|
20010
20856
|
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
20011
20857
|
if (compartments.length === 0)
|
|
20012
20858
|
return;
|
|
20859
|
+
if (getProjectChunkEmbeddingModelId(projectPath) === "off")
|
|
20860
|
+
return;
|
|
20013
20861
|
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
20014
20862
|
for (const compartment of compartments) {
|
|
20015
20863
|
try {
|
|
@@ -20166,7 +21014,7 @@ function persistFilteredNoise(db, sessionId, chunk, eligibleEnd) {
|
|
|
20166
21014
|
}
|
|
20167
21015
|
]);
|
|
20168
21016
|
return true;
|
|
20169
|
-
})();
|
|
21017
|
+
}).immediate();
|
|
20170
21018
|
if (saved)
|
|
20171
21019
|
sessionLog(sessionId, `historian skipped ordinals ${start}-${eligibleEnd - 1}: all ${rows.length} raw rows excluded by chunk filters (no-content boundary marker)`);
|
|
20172
21020
|
return saved;
|
|
@@ -22763,8 +23611,7 @@ ${chunkText}`,
|
|
|
22763
23611
|
const discardedLast = newCompartments.length < emittedCompartments.length;
|
|
22764
23612
|
const weakLookaheadFinalCompartment = forceKeepLastCompartmentForChunk;
|
|
22765
23613
|
const skipUnanchoredPromotion = discardedLast || weakLookaheadFinalCompartment;
|
|
22766
|
-
const
|
|
22767
|
-
const promotionActive = embeddingActive && autoPromote !== false;
|
|
23614
|
+
const promotionActive = memoryEnabled !== false && autoPromote !== false;
|
|
22768
23615
|
const publishableEvents = (validatedPass.events ?? []).filter((e) => {
|
|
22769
23616
|
if (typeof e.atCompartment !== "number")
|
|
22770
23617
|
return !weakLookaheadFinalCompartment;
|
|
@@ -22897,7 +23744,7 @@ ${chunkText}`,
|
|
|
22897
23744
|
sessionLog(sessionId, "failed to store primer candidates:", error);
|
|
22898
23745
|
}
|
|
22899
23746
|
}
|
|
22900
|
-
if (
|
|
23747
|
+
if (newCompartments.length > 0) {
|
|
22901
23748
|
const chunksToEmbed = newCompartments.map((c, i) => ({
|
|
22902
23749
|
id: persistedIds[i],
|
|
22903
23750
|
startMessage: c.startMessage,
|
|
@@ -23280,7 +24127,7 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
|
|
|
23280
24127
|
const candidateTags = tags.filter((t) => t.status === "active" && t.type === "tool" && targets.get(t.tagNumber)?.canDrop?.());
|
|
23281
24128
|
const recentTags = new Set(candidateTags.slice().sort((a, b) => b.tagNumber - a.tagNumber).slice(0, 20).map((tag) => tag.tagNumber));
|
|
23282
24129
|
const calibration = sessionDecisionCalibration(db, sessionId);
|
|
23283
|
-
const activeTags = tags.filter((t) => t.status === "active").map((tag) => measureEmergencyTag(tag, targets.get(tag.tagNumber), calibration, targets.get(tag.tagNumber)?.requiresToolArcSkeleton === true || (emergency.usagePercentage ?? 0) < 95 && recentTags.has(tag.tagNumber)));
|
|
24130
|
+
const activeTags = tags.filter((t) => t.status === "active").map((tag) => measureEmergencyTag(tag, targets.get(tag.tagNumber), calibration, targets.get(tag.tagNumber)?.requiresToolArcSkeleton === true || (emergency.usagePercentage ?? 0) < 95 && recentTags.has(tag.tagNumber) && hasSmallToolInput(targets.get(tag.tagNumber))));
|
|
23284
24131
|
const byTag = new Map(activeTags.map((tag) => [tag.tagNumber, tag]));
|
|
23285
24132
|
const droppableTags = candidateTags.flatMap((tag) => {
|
|
23286
24133
|
const measured = byTag.get(tag.tagNumber);
|
|
@@ -23309,18 +24156,18 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
|
|
|
23309
24156
|
continue;
|
|
23310
24157
|
const target = targets.get(tag.tagNumber);
|
|
23311
24158
|
const recent = (emergency.usagePercentage ?? 0) < 95 && newestEmergencyTags.has(tag.tagNumber);
|
|
23312
|
-
const
|
|
23313
|
-
|
|
23314
|
-
|
|
24159
|
+
const { result, mode } = applyNewToolDrop(target, {
|
|
24160
|
+
inWindow: recent,
|
|
24161
|
+
keepSkeleton: target?.requiresToolArcSkeleton === true
|
|
24162
|
+
});
|
|
23315
24163
|
if (result === "removed" || result === "truncated") {
|
|
23316
|
-
const appliedMode = skeleton || result === "truncated" ? "truncated" : "full";
|
|
23317
24164
|
updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
|
|
23318
|
-
updateTagDropMode(db, sessionId, tag.tagNumber,
|
|
24165
|
+
updateTagDropMode(db, sessionId, tag.tagNumber, mode);
|
|
23319
24166
|
droppedTools++;
|
|
23320
24167
|
emergencyDroppedTools++;
|
|
23321
24168
|
droppedTokenReductions.push({
|
|
23322
24169
|
tagNumber: tag.tagNumber,
|
|
23323
|
-
mode:
|
|
24170
|
+
mode: mode === "full" ? "full" : "truncated"
|
|
23324
24171
|
});
|
|
23325
24172
|
}
|
|
23326
24173
|
}
|
|
@@ -23344,10 +24191,10 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
|
|
|
23344
24191
|
if (!matched)
|
|
23345
24192
|
continue;
|
|
23346
24193
|
const target = targets.get(tag.tagNumber);
|
|
23347
|
-
const result = target
|
|
24194
|
+
const { result, mode } = applyNewToolDrop(target, { inWindow: false });
|
|
23348
24195
|
if (result === "incomplete")
|
|
23349
24196
|
continue;
|
|
23350
|
-
updateTagDropMode(db, sessionId, tag.tagNumber,
|
|
24197
|
+
updateTagDropMode(db, sessionId, tag.tagNumber, mode);
|
|
23351
24198
|
updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
|
|
23352
24199
|
if (result === "removed" || result === "truncated") {
|
|
23353
24200
|
droppedStaleReduceCalls++;
|
|
@@ -23428,17 +24275,18 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
|
|
|
23428
24275
|
for (let i = 0;i < group.length - 1; i++) {
|
|
23429
24276
|
const tag = group[i];
|
|
23430
24277
|
const target = targets.get(tag.tagNumber);
|
|
23431
|
-
const result = target
|
|
24278
|
+
const { result, mode } = applyNewToolDrop(target, {
|
|
24279
|
+
inWindow: false
|
|
24280
|
+
});
|
|
23432
24281
|
if (result === "incomplete")
|
|
23433
24282
|
continue;
|
|
23434
|
-
|
|
23435
|
-
updateTagDropMode(db, sessionId, tag.tagNumber, appliedMode);
|
|
24283
|
+
updateTagDropMode(db, sessionId, tag.tagNumber, mode);
|
|
23436
24284
|
updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
|
|
23437
24285
|
if (result === "removed" || result === "truncated") {
|
|
23438
24286
|
deduplicatedTools++;
|
|
23439
24287
|
droppedTokenReductions.push({
|
|
23440
24288
|
tagNumber: tag.tagNumber,
|
|
23441
|
-
mode:
|
|
24289
|
+
mode: mode === "full" ? "full" : "truncated"
|
|
23442
24290
|
});
|
|
23443
24291
|
}
|
|
23444
24292
|
}
|
|
@@ -24739,9 +25587,7 @@ ${decayed}
|
|
|
24739
25587
|
if (memoryBlock)
|
|
24740
25588
|
sections.push(memoryBlock);
|
|
24741
25589
|
if (mural?.enabled && mural.supportsVision && mural.dataUrl) {
|
|
24742
|
-
sections.push(
|
|
24743
|
-
The project memory mural image follows.
|
|
24744
|
-
</memory-mural>`);
|
|
25590
|
+
sections.push(MEMORY_MURAL_BLOCK);
|
|
24745
25591
|
}
|
|
24746
25592
|
return sections.join(`
|
|
24747
25593
|
|
|
@@ -26204,7 +27050,7 @@ function messageRole(message) {
|
|
|
26204
27050
|
const role = recordValue(message, "role");
|
|
26205
27051
|
return typeof role === "string" ? role : undefined;
|
|
26206
27052
|
}
|
|
26207
|
-
function
|
|
27053
|
+
function messageId2(message) {
|
|
26208
27054
|
const id = recordValue(messageInfo(message), "id") ?? recordValue(message, "id");
|
|
26209
27055
|
return typeof id === "string" && id.length > 0 ? id : null;
|
|
26210
27056
|
}
|
|
@@ -26337,7 +27183,7 @@ function validateLkgSeam(prefix, tail, providerKey) {
|
|
|
26337
27183
|
const calls = new Set;
|
|
26338
27184
|
const results = new Set;
|
|
26339
27185
|
for (const message of all) {
|
|
26340
|
-
const id =
|
|
27186
|
+
const id = messageId2(message);
|
|
26341
27187
|
if (id !== null) {
|
|
26342
27188
|
if (ids.has(id))
|
|
26343
27189
|
return false;
|
|
@@ -26880,6 +27726,56 @@ function resolvePiPressureSnapshot(args) {
|
|
|
26880
27726
|
...validInferredLimit ? { contextLimit: inferredLimit } : {}
|
|
26881
27727
|
};
|
|
26882
27728
|
}
|
|
27729
|
+
var estimateSetAsideLogged = new Set;
|
|
27730
|
+
function notePiUsageReadingUsed(sessionId) {
|
|
27731
|
+
estimateSetAsideLogged.delete(sessionId);
|
|
27732
|
+
}
|
|
27733
|
+
function entryUsageTokens(usage) {
|
|
27734
|
+
if (!usage || typeof usage !== "object")
|
|
27735
|
+
return 0;
|
|
27736
|
+
const u = usage;
|
|
27737
|
+
const n = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
27738
|
+
return n(u.totalTokens) || n(u.input) + n(u.output) + n(u.cacheRead) + n(u.cacheWrite);
|
|
27739
|
+
}
|
|
27740
|
+
function isPiLiveUsageRawBranchEstimate(branchEntries) {
|
|
27741
|
+
if (!branchEntries)
|
|
27742
|
+
return false;
|
|
27743
|
+
for (let index = branchEntries.length - 1;index >= 0; index -= 1) {
|
|
27744
|
+
const entry = branchEntries[index];
|
|
27745
|
+
if (!entry || typeof entry !== "object")
|
|
27746
|
+
continue;
|
|
27747
|
+
if (entry.type === "context_edit" || entry.type === "compaction")
|
|
27748
|
+
return true;
|
|
27749
|
+
if (entry.type !== "message")
|
|
27750
|
+
continue;
|
|
27751
|
+
const message = entry.message;
|
|
27752
|
+
if (message?.role === "assistant" && message.stopReason !== "aborted" && message.stopReason !== "error" && entryUsageTokens(message.usage) > 0) {
|
|
27753
|
+
return false;
|
|
27754
|
+
}
|
|
27755
|
+
}
|
|
27756
|
+
return false;
|
|
27757
|
+
}
|
|
27758
|
+
function noteRawBranchEstimateSetAside(sessionId, reading, source) {
|
|
27759
|
+
if (estimateSetAsideLogged.has(sessionId))
|
|
27760
|
+
return;
|
|
27761
|
+
estimateSetAsideLogged.add(sessionId);
|
|
27762
|
+
sessionLog(sessionId, `usage reading ${reading} set aside (${source}): Pi re-estimated its whole unreduced session branch because a context edit or compaction follows the last recorded usage (for example after a retried request); keeping the previous reading until provider usage arrives`);
|
|
27763
|
+
}
|
|
27764
|
+
function resolvePiPressureSnapshotWithEstimateGuard(args) {
|
|
27765
|
+
const live = typeof args.liveInputTokens === "number" && Number.isFinite(args.liveInputTokens) ? args.liveInputTokens : 0;
|
|
27766
|
+
const setAsideEstimate = args.liveIsRawBranchEstimate === true && live > 0;
|
|
27767
|
+
const snapshot = resolvePiPressureSnapshot(setAsideEstimate ? {
|
|
27768
|
+
...args,
|
|
27769
|
+
liveInputTokens: undefined,
|
|
27770
|
+
...args.persistedFromLive ? { persistedInputTokens: 0, persistedPercentage: 0 } : {}
|
|
27771
|
+
} : args);
|
|
27772
|
+
if (setAsideEstimate) {
|
|
27773
|
+
noteRawBranchEstimateSetAside(args.sessionId, live, args.source);
|
|
27774
|
+
} else if (snapshot.inputTokens > 0) {
|
|
27775
|
+
notePiUsageReadingUsed(args.sessionId);
|
|
27776
|
+
}
|
|
27777
|
+
return snapshot;
|
|
27778
|
+
}
|
|
26883
27779
|
function formatPiPressureForLog(snapshot) {
|
|
26884
27780
|
return `usage=${snapshot.percentage.toFixed(1)}% (${snapshot.inputTokens} tokens, limit=${snapshot.contextLimit ?? "?"})`;
|
|
26885
27781
|
}
|
|
@@ -27336,12 +28232,12 @@ function handlePiProviderFailure(args) {
|
|
|
27336
28232
|
const model = typeof message.model === "string" ? message.model : undefined;
|
|
27337
28233
|
const binding = detectThinkingBindingMismatch(message.errorMessage);
|
|
27338
28234
|
if (binding.isBindingMismatch) {
|
|
27339
|
-
const enabled = args.thinkingBindingRecoveryEnabled !== false && !args.compactionOff &&
|
|
28235
|
+
const enabled = args.thinkingBindingRecoveryEnabled !== false && !args.compactionOff && isPrefixBoundThinkingModel(provider, model);
|
|
27340
28236
|
if (enabled) {
|
|
27341
28237
|
armThinkingBindingRecovery(args.db, args.sessionId);
|
|
27342
28238
|
clearPiLkgSessionState(args.sessionId);
|
|
27343
28239
|
dropSlot(args.sessionId, "thinking-binding-recovery-arm");
|
|
27344
|
-
reportBindingRecovery(args.sessionId, args.report, `
|
|
28240
|
+
reportBindingRecovery(args.sessionId, args.report, `thinking-binding recovery armed from message_end (provider paths: failing=${binding.failingBlockPath ?? "?"} firstChanged=${binding.firstChangedPath ?? "?"})`);
|
|
27345
28241
|
}
|
|
27346
28242
|
return { kind: "thinking_binding", armed: enabled };
|
|
27347
28243
|
}
|
|
@@ -27390,36 +28286,25 @@ function stripThinkingParts(message) {
|
|
|
27390
28286
|
function applyPiThinkingBindingRecovery(args) {
|
|
27391
28287
|
if (args.provider?.toLowerCase() !== "anthropic")
|
|
27392
28288
|
return null;
|
|
27393
|
-
const frozenEntryIds =
|
|
27394
|
-
|
|
27395
|
-
if (!frozenId.startsWith(THINKING_BINDING_RECOVERY_FROZEN_PREFIX))
|
|
27396
|
-
continue;
|
|
27397
|
-
const entryId = frozenId.slice(THINKING_BINDING_RECOVERY_FROZEN_PREFIX.length);
|
|
27398
|
-
if (entryId.length > 0)
|
|
27399
|
-
frozenEntryIds.add(entryId);
|
|
27400
|
-
}
|
|
27401
|
-
const flagTarget = isFable51ThinkingBindingModel(args.provider, args.model) ? getThinkingBindingRecoveryTarget(args.db, args.sessionId) : null;
|
|
28289
|
+
const frozenEntryIds = frozenBindingEntryIds(args.db, args.sessionId);
|
|
28290
|
+
const flagTarget = isPrefixBoundThinkingModel(args.provider, args.model) ? getThinkingBindingRecoveryTarget(args.db, args.sessionId) : null;
|
|
27402
28291
|
let applied = null;
|
|
27403
28292
|
if (flagTarget) {
|
|
27404
|
-
|
|
27405
|
-
|
|
27406
|
-
|
|
27407
|
-
|
|
27408
|
-
|
|
27409
|
-
|
|
27410
|
-
|
|
27411
|
-
|
|
27412
|
-
|
|
27413
|
-
|
|
27414
|
-
|
|
27415
|
-
|
|
27416
|
-
|
|
27417
|
-
|
|
27418
|
-
|
|
27419
|
-
frozenEntryIds.add(entryId);
|
|
27420
|
-
applied = { flagTarget, entryId };
|
|
27421
|
-
reportBindingRecovery(args.sessionId, args.report, `Fable thinking-binding recovery consumed on context pass target=${flagTarget} entry=${entryId}`);
|
|
27422
|
-
}
|
|
28293
|
+
const entryIds = new Set;
|
|
28294
|
+
for (let index = 0;index < args.messages.length; index += 1) {
|
|
28295
|
+
const entryId = args.entryIds[index];
|
|
28296
|
+
if (entryId && hasThinkingPart(args.messages[index]))
|
|
28297
|
+
entryIds.add(entryId);
|
|
28298
|
+
}
|
|
28299
|
+
const newEntryIds = [...entryIds].filter((id) => !frozenEntryIds.has(id));
|
|
28300
|
+
if (newEntryIds.length === 0 || addMergedReasoningStrippedIds(args.db, args.sessionId, [
|
|
28301
|
+
...newEntryIds.map(thinkingBindingRecoveryFrozenId),
|
|
28302
|
+
...args.endOfPassOrder ? [THINKING_BINDING_STRIP_ORDER_END_MARKER] : []
|
|
28303
|
+
])) {
|
|
28304
|
+
for (const id of newEntryIds)
|
|
28305
|
+
frozenEntryIds.add(id);
|
|
28306
|
+
applied = { flagTarget, entryIds: [...entryIds] };
|
|
28307
|
+
reportBindingRecovery(args.sessionId, args.report, `thinking-binding recovery consumed on context pass target=${flagTarget} entries=${applied.entryIds.length} [${applied.entryIds.join(",")}]`);
|
|
27423
28308
|
}
|
|
27424
28309
|
}
|
|
27425
28310
|
for (let index = 0;index < args.messages.length; index += 1) {
|
|
@@ -27429,6 +28314,76 @@ function applyPiThinkingBindingRecovery(args) {
|
|
|
27429
28314
|
}
|
|
27430
28315
|
return applied;
|
|
27431
28316
|
}
|
|
28317
|
+
function applyPiProactiveThinkingStrip(args) {
|
|
28318
|
+
if (!args.cacheBustingPass)
|
|
28319
|
+
return null;
|
|
28320
|
+
if (!isPrefixBoundThinkingModel(args.provider, args.model))
|
|
28321
|
+
return null;
|
|
28322
|
+
const entryIds = [];
|
|
28323
|
+
const indices = [];
|
|
28324
|
+
for (let index = 0;index < args.messages.length; index += 1) {
|
|
28325
|
+
const entryId = args.entryIds[index];
|
|
28326
|
+
if (!entryId || !hasThinkingPart(args.messages[index]))
|
|
28327
|
+
continue;
|
|
28328
|
+
entryIds.push(entryId);
|
|
28329
|
+
indices.push(index);
|
|
28330
|
+
}
|
|
28331
|
+
if (entryIds.length === 0)
|
|
28332
|
+
return null;
|
|
28333
|
+
let persisted = false;
|
|
28334
|
+
try {
|
|
28335
|
+
persisted = addMergedReasoningStrippedIds(args.db, args.sessionId, [
|
|
28336
|
+
...entryIds.map(thinkingBindingRecoveryFrozenId),
|
|
28337
|
+
THINKING_BINDING_STRIP_ORDER_END_MARKER
|
|
28338
|
+
]);
|
|
28339
|
+
} catch {
|
|
28340
|
+
persisted = false;
|
|
28341
|
+
}
|
|
28342
|
+
if (!persisted) {
|
|
28343
|
+
reportBindingRecovery(args.sessionId, args.report, "proactive thinking strip: persistence failed; serving the thinking unchanged");
|
|
28344
|
+
return null;
|
|
28345
|
+
}
|
|
28346
|
+
for (const index of indices)
|
|
28347
|
+
stripThinkingParts(args.messages[index]);
|
|
28348
|
+
reportBindingRecovery(args.sessionId, args.report, `proactive thinking strip: busting pass froze thinking of ${entryIds.length} entr${entryIds.length === 1 ? "y" : "ies"} [${entryIds.join(",")}]`);
|
|
28349
|
+
return { entryIds };
|
|
28350
|
+
}
|
|
28351
|
+
function frozenBindingEntryIds(db, sessionId) {
|
|
28352
|
+
const ids = new Set;
|
|
28353
|
+
for (const entry of getMergedReasoningStrippedIds(db, sessionId)) {
|
|
28354
|
+
if (!entry.startsWith(THINKING_BINDING_RECOVERY_FROZEN_PREFIX))
|
|
28355
|
+
continue;
|
|
28356
|
+
const entryId = entry.slice(THINKING_BINDING_RECOVERY_FROZEN_PREFIX.length);
|
|
28357
|
+
if (entryId.length > 0)
|
|
28358
|
+
ids.add(entryId);
|
|
28359
|
+
}
|
|
28360
|
+
return ids;
|
|
28361
|
+
}
|
|
28362
|
+
function resolvePiBindingStripOrder(args) {
|
|
28363
|
+
const ledger = getMergedReasoningStrippedIds(args.db, args.sessionId);
|
|
28364
|
+
if (ledger.has(THINKING_BINDING_STRIP_ORDER_END_MARKER))
|
|
28365
|
+
return "end";
|
|
28366
|
+
const frozen = frozenBindingEntryIds(args.db, args.sessionId);
|
|
28367
|
+
if (frozen.size === 0)
|
|
28368
|
+
return "end";
|
|
28369
|
+
let onBranch = false;
|
|
28370
|
+
let carriesThinking = false;
|
|
28371
|
+
for (let index = 0;index < args.messages.length; index += 1) {
|
|
28372
|
+
const entryId = args.entryIds[index];
|
|
28373
|
+
if (!entryId || !frozen.has(entryId))
|
|
28374
|
+
continue;
|
|
28375
|
+
onBranch = true;
|
|
28376
|
+
if (hasThinkingPart(args.messages[index]))
|
|
28377
|
+
carriesThinking = true;
|
|
28378
|
+
}
|
|
28379
|
+
const mayChangeOrder = onBranch && carriesThinking && args.bustPermittedAtStart;
|
|
28380
|
+
if (mayChangeOrder && addMergedReasoningStrippedIds(args.db, args.sessionId, [
|
|
28381
|
+
THINKING_BINDING_STRIP_ORDER_END_MARKER
|
|
28382
|
+
])) {
|
|
28383
|
+
return "end";
|
|
28384
|
+
}
|
|
28385
|
+
return "start";
|
|
28386
|
+
}
|
|
27432
28387
|
|
|
27433
28388
|
// src/reasoning-replay-pi.ts
|
|
27434
28389
|
var INLINE_THINKING_PATTERNS = [
|
|
@@ -27946,144 +28901,6 @@ function stripPiProcessedImages(args) {
|
|
|
27946
28901
|
|
|
27947
28902
|
// src/system-prompt.ts
|
|
27948
28903
|
import { createHash as createHash13 } from "node:crypto";
|
|
27949
|
-
|
|
27950
|
-
// ../plugin/src/agents/magic-context-prompt.ts
|
|
27951
|
-
var LONG_TERM_PARTNER_FRAME = `### You are the user's long-term partner on this project — not a one-off hire
|
|
27952
|
-
|
|
27953
|
-
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.
|
|
27954
|
-
|
|
27955
|
-
Because of this:
|
|
27956
|
-
- **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.
|
|
27957
|
-
- **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.
|
|
27958
|
-
- **Finishing a task does not end the session.** Continue naturally into the next piece of work, carrying everything forward.
|
|
27959
|
-
- **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.`;
|
|
27960
|
-
var PARTNER_FRAME_CLOSER_REDUCE = `
|
|
27961
|
-
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.`;
|
|
27962
|
-
var PARTNER_FRAME_CLOSER_NO_REDUCE = `
|
|
27963
|
-
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.`;
|
|
27964
|
-
var PARTNER_FRAME_CLOSER_REDUCE_LIGHT = `
|
|
27965
|
-
When ctx_reduce is available, use it only as routine housekeeping; never cut task scope or depth because context is large.`;
|
|
27966
|
-
var PARTNER_FRAME_CLOSER_NO_REDUCE_LIGHT = `
|
|
27967
|
-
When ctx_reduce is unavailable, context is automatic; never prune, heed reduction warnings, or cut task scope or depth because context is large.`;
|
|
27968
|
-
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.`;
|
|
27969
|
-
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.`;
|
|
27970
|
-
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.`;
|
|
27971
|
-
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.`;
|
|
27972
|
-
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)`;
|
|
27973
|
-
var TEMPORAL_AWARENESS_OVERRIDE_GUIDANCE = `
|
|
27974
|
-
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.`;
|
|
27975
|
-
var BASE_INTRO = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `### Your desk
|
|
27976
|
-
|
|
27977
|
-
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.
|
|
27978
|
-
|
|
27979
|
-
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". Never stamp a user message for what it asks of you; a large paste inside one is fine once you have used it.
|
|
27980
|
-
|
|
27981
|
-
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; that is housekeeping, not a warning, and the desk never gets smaller for it.
|
|
27982
|
-
|
|
27983
|
-
${TOOL_HISTORY_GUIDANCE}
|
|
27984
|
-
|
|
27985
|
-
\`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.
|
|
27986
|
-
|
|
27987
|
-
${memoryEnabled ? `${MEMORY_GUIDANCE} ` : ""}${CTX_NOTE_GUIDANCE}${dreamerEnabled ? ` ${SMART_NOTE_GUIDANCE}` : ""}
|
|
27988
|
-
|
|
27989
|
-
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.`;
|
|
27990
|
-
var BASE_INTRO_NO_REDUCE = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `### Your desk
|
|
27991
|
-
|
|
27992
|
-
Think of your context as a desk. Every message and every tool output lands on it.
|
|
27993
|
-
|
|
27994
|
-
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.
|
|
27995
|
-
|
|
27996
|
-
${TOOL_HISTORY_GUIDANCE}
|
|
27997
|
-
|
|
27998
|
-
\`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.
|
|
27999
|
-
|
|
28000
|
-
${memoryEnabled ? `${MEMORY_GUIDANCE} ` : ""}${CTX_NOTE_GUIDANCE}${dreamerEnabled ? ` ${SMART_NOTE_GUIDANCE}` : ""}
|
|
28001
|
-
|
|
28002
|
-
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.`;
|
|
28003
|
-
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`;
|
|
28004
|
-
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.`;
|
|
28005
|
-
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.`;
|
|
28006
|
-
var SMART_NOTE_GUIDANCE_LIGHT = `; a \`surface_condition\` leaves the note with an outside checker that returns it when the condition holds`;
|
|
28007
|
-
var TEMPORAL_AWARENESS_GUIDANCE_LIGHT = `, \`<!-- +Xm -->\` (time since your last reply)`;
|
|
28008
|
-
var BASE_INTRO_LIGHT = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `### Your desk
|
|
28009
|
-
|
|
28010
|
-
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). 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 are housekeeping, not warnings; the desk never gets smaller.
|
|
28011
|
-
|
|
28012
|
-
${TOOL_HISTORY_GUIDANCE_LIGHT}
|
|
28013
|
-
|
|
28014
|
-
\`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 : ""}.
|
|
28015
|
-
|
|
28016
|
-
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.`;
|
|
28017
|
-
var BASE_INTRO_NO_REDUCE_LIGHT = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `### Your desk
|
|
28018
|
-
|
|
28019
|
-
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.
|
|
28020
|
-
|
|
28021
|
-
${TOOL_HISTORY_GUIDANCE_LIGHT}
|
|
28022
|
-
|
|
28023
|
-
\`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 : ""}.
|
|
28024
|
-
|
|
28025
|
-
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.`;
|
|
28026
|
-
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".
|
|
28027
|
-
|
|
28028
|
-
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.
|
|
28029
|
-
|
|
28030
|
-
\`<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.`;
|
|
28031
|
-
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".
|
|
28032
|
-
|
|
28033
|
-
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.
|
|
28034
|
-
|
|
28035
|
-
\`<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.`;
|
|
28036
|
-
var CAVEMAN_COMPRESSION_WARNING = `
|
|
28037
|
-
**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.`;
|
|
28038
|
-
function buildMagicContextSection(_agent, _legacyProtectionCount, ctxReduceCallable = true, dreamerEnabled = false, temporalAwarenessEnabled = false, cavemanTextCompressionEnabled = false, subagentMode = false, language, memoryEnabled = true, preset = "full", primaryOverride) {
|
|
28039
|
-
if (subagentMode) {
|
|
28040
|
-
const intro = preset === "light" ? SUBAGENT_REDUCE_INTRO_LIGHT() : SUBAGENT_REDUCE_INTRO();
|
|
28041
|
-
return `## Magic Context
|
|
28042
|
-
|
|
28043
|
-
${intro}`;
|
|
28044
|
-
}
|
|
28045
|
-
const temporalOverrideGuidance = temporalAwarenessEnabled ? TEMPORAL_AWARENESS_OVERRIDE_GUIDANCE : "";
|
|
28046
|
-
const cavemanWarning = cavemanTextCompressionEnabled ? CAVEMAN_COMPRESSION_WARNING : "";
|
|
28047
|
-
const languageDirective = buildPrimaryLanguageDirective(language);
|
|
28048
|
-
const languageGuidance = languageDirective ? `
|
|
28049
|
-
|
|
28050
|
-
${languageDirective}` : "";
|
|
28051
|
-
if (primaryOverride !== undefined) {
|
|
28052
|
-
return `${primaryOverride}${temporalOverrideGuidance}${cavemanWarning}${languageGuidance}`;
|
|
28053
|
-
}
|
|
28054
|
-
if (!ctxReduceCallable) {
|
|
28055
|
-
if (preset === "light") {
|
|
28056
|
-
return `## Magic Context
|
|
28057
|
-
|
|
28058
|
-
${LONG_TERM_PARTNER_FRAME}
|
|
28059
|
-
${PARTNER_FRAME_CLOSER_NO_REDUCE_LIGHT}
|
|
28060
|
-
|
|
28061
|
-
${BASE_INTRO_NO_REDUCE_LIGHT(memoryEnabled, dreamerEnabled, temporalAwarenessEnabled)}${cavemanWarning}${languageGuidance}`;
|
|
28062
|
-
}
|
|
28063
|
-
return `## Magic Context
|
|
28064
|
-
|
|
28065
|
-
${LONG_TERM_PARTNER_FRAME}
|
|
28066
|
-
${PARTNER_FRAME_CLOSER_NO_REDUCE}
|
|
28067
|
-
|
|
28068
|
-
${BASE_INTRO_NO_REDUCE(memoryEnabled, dreamerEnabled, temporalAwarenessEnabled)}${cavemanWarning}${languageGuidance}`;
|
|
28069
|
-
}
|
|
28070
|
-
if (preset === "light") {
|
|
28071
|
-
return `## Magic Context
|
|
28072
|
-
|
|
28073
|
-
${LONG_TERM_PARTNER_FRAME}
|
|
28074
|
-
${PARTNER_FRAME_CLOSER_REDUCE_LIGHT}
|
|
28075
|
-
|
|
28076
|
-
${BASE_INTRO_LIGHT(memoryEnabled, dreamerEnabled, temporalAwarenessEnabled)}${cavemanWarning}${languageGuidance}`;
|
|
28077
|
-
}
|
|
28078
|
-
return `## Magic Context
|
|
28079
|
-
|
|
28080
|
-
${LONG_TERM_PARTNER_FRAME}
|
|
28081
|
-
${PARTNER_FRAME_CLOSER_REDUCE}
|
|
28082
|
-
|
|
28083
|
-
${BASE_INTRO(memoryEnabled, dreamerEnabled, temporalAwarenessEnabled)}${cavemanWarning}${languageGuidance}`;
|
|
28084
|
-
}
|
|
28085
|
-
|
|
28086
|
-
// src/system-prompt.ts
|
|
28087
28904
|
var MAGIC_CONTEXT_MARKER = "## Magic Context";
|
|
28088
28905
|
var stickyDateBySession = new Map;
|
|
28089
28906
|
function buildMagicContextBlock(opts) {
|
|
@@ -29026,12 +29843,14 @@ var MAX_TRACKED_SESSIONS = 100;
|
|
|
29026
29843
|
function trackSessionForProject(projectIdentity, sessionId) {
|
|
29027
29844
|
activeContextHandlerSessions.delete(sessionId);
|
|
29028
29845
|
activeContextHandlerSessions.add(sessionId);
|
|
29029
|
-
|
|
29030
|
-
|
|
29031
|
-
sessions
|
|
29032
|
-
|
|
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);
|
|
29033
29853
|
}
|
|
29034
|
-
sessions.add(sessionId);
|
|
29035
29854
|
while (activeContextHandlerSessions.size > MAX_TRACKED_SESSIONS) {
|
|
29036
29855
|
const oldest = activeContextHandlerSessions.values().next().value;
|
|
29037
29856
|
if (oldest === undefined || oldest === sessionId)
|
|
@@ -29490,7 +30309,7 @@ function databaseIsInTransaction(db) {
|
|
|
29490
30309
|
}
|
|
29491
30310
|
function runImmediateTransaction(db, fn) {
|
|
29492
30311
|
if (databaseIsInTransaction(db)) {
|
|
29493
|
-
return db.transaction(fn)();
|
|
30312
|
+
return db.transaction(fn).immediate();
|
|
29494
30313
|
}
|
|
29495
30314
|
const transactionStartedAt = performance.now();
|
|
29496
30315
|
db.exec("BEGIN IMMEDIATE");
|
|
@@ -29672,6 +30491,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
29672
30491
|
logTransformTiming(sessionId, "findSessionId", tFindSession, `messages=${event.messages.length}`);
|
|
29673
30492
|
const tEntryBranch = performance.now();
|
|
29674
30493
|
const branchEntries = readPiBranchEntriesForContext(ctx, sessionId);
|
|
30494
|
+
const piLiveUsageIsRawBranchEstimate = isPiLiveUsageRawBranchEstimate(branchEntries);
|
|
29675
30495
|
schedulePiTransformDecisionResolve({
|
|
29676
30496
|
db: options.db,
|
|
29677
30497
|
sessionId,
|
|
@@ -29704,14 +30524,29 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
29704
30524
|
const lkgInputIdByRef = new Map;
|
|
29705
30525
|
for (const input of lkgPassSnapshot.inputs)
|
|
29706
30526
|
lkgInputIdByRef.set(event.messages[input.messageIndex], input.id);
|
|
29707
|
-
const
|
|
30527
|
+
const bindingStripOrder = resolvePiBindingStripOrder({
|
|
30528
|
+
db: options.db,
|
|
30529
|
+
sessionId,
|
|
30530
|
+
messages: event.messages,
|
|
30531
|
+
entryIds: lkgEntryIds ?? [],
|
|
30532
|
+
bustPermittedAtStart: hasPendingMaterialization(sessionId)
|
|
30533
|
+
});
|
|
30534
|
+
const startOfPassBindingRecovery = bindingStripOrder === "start" ? applyPiThinkingBindingRecovery({
|
|
29708
30535
|
db: options.db,
|
|
29709
30536
|
sessionId,
|
|
29710
30537
|
messages: event.messages,
|
|
29711
30538
|
entryIds: lkgEntryIds ?? [],
|
|
29712
30539
|
provider: lkgProviderKey ?? undefined,
|
|
29713
30540
|
model: ctx.model?.id
|
|
29714
|
-
});
|
|
30541
|
+
}) : null;
|
|
30542
|
+
const bindingEntryIdByRef = new Map;
|
|
30543
|
+
if (lkgEntryIds) {
|
|
30544
|
+
for (let index = 0;index < event.messages.length; index += 1) {
|
|
30545
|
+
const entryId = lkgEntryIds[index];
|
|
30546
|
+
if (entryId)
|
|
30547
|
+
bindingEntryIdByRef.set(event.messages[index], entryId);
|
|
30548
|
+
}
|
|
30549
|
+
}
|
|
29715
30550
|
const tMeta = performance.now();
|
|
29716
30551
|
const sessionMetaForUsage = getOrCreateSessionMeta(options.db, sessionId);
|
|
29717
30552
|
sessionMetaForPass = sessionMetaForUsage;
|
|
@@ -29773,6 +30608,8 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
29773
30608
|
}
|
|
29774
30609
|
const previousModelKey = liveModelBySession.get(sessionId);
|
|
29775
30610
|
const currentModelKey = resolvePiContextModelKey(ctx);
|
|
30611
|
+
if (options.cacheTtlConfig !== undefined)
|
|
30612
|
+
resolveSessionCacheTtl(options.db, sessionId, options.cacheTtlConfig, currentModelKey);
|
|
29776
30613
|
const modelChanged = previousModelKey !== undefined && currentModelKey !== undefined && piModelRefToCanonical(previousModelKey) !== piModelRefToCanonical(currentModelKey);
|
|
29777
30614
|
if (currentModelKey !== undefined) {
|
|
29778
30615
|
liveModelBySession.set(sessionId, currentModelKey);
|
|
@@ -29921,7 +30758,11 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
29921
30758
|
if (!usedPersistedUsage && isSaneLimit(usageContextLimit) && usageInputTokens > 0) {
|
|
29922
30759
|
usagePercentage = usageInputTokens / usageContextLimit * 100;
|
|
29923
30760
|
}
|
|
29924
|
-
({ percentage: usagePercentage, inputTokens: usageInputTokens } =
|
|
30761
|
+
({ percentage: usagePercentage, inputTokens: usageInputTokens } = resolvePiPressureSnapshotWithEstimateGuard({
|
|
30762
|
+
sessionId,
|
|
30763
|
+
source: "transform",
|
|
30764
|
+
liveIsRawBranchEstimate: piLiveUsageIsRawBranchEstimate,
|
|
30765
|
+
persistedFromLive: !usedPersistedUsage,
|
|
29925
30766
|
persistedPercentage: usagePercentage,
|
|
29926
30767
|
persistedInputTokens: usageInputTokens,
|
|
29927
30768
|
liveInputTokens: piUsage?.tokens,
|
|
@@ -30099,6 +30940,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
30099
30940
|
sessionMeta,
|
|
30100
30941
|
piUsage,
|
|
30101
30942
|
minimumPercentage: usagePercentage,
|
|
30943
|
+
liveIsRawBranchEstimate: piLiveUsageIsRawBranchEstimate,
|
|
30102
30944
|
historianStateSnapshot: historianStateForPass,
|
|
30103
30945
|
publishedHistoryRide: isCacheBusting
|
|
30104
30946
|
});
|
|
@@ -30161,7 +31003,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
30161
31003
|
const tTodoCapture = performance.now();
|
|
30162
31004
|
try {
|
|
30163
31005
|
const sessionMetaForTodo = sessionMeta;
|
|
30164
|
-
if (!options.compactionOff && !sessionMetaForTodo.isSubagent && sessionMetaForTodo.lastTodoState !== "") {
|
|
31006
|
+
if (options.todowriteEnabled === true && !options.compactionOff && !sessionMetaForTodo.isSubagent && sessionMetaForTodo.lastTodoState !== "") {
|
|
30165
31007
|
const isCacheBustingForTodo = isCacheBusting || result.executedWorkThisPass;
|
|
30166
31008
|
outputMessages = injectSyntheticTodowriteForPi({
|
|
30167
31009
|
db: options.db,
|
|
@@ -30176,6 +31018,34 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
30176
31018
|
sessionLog(sessionId, `synthetic todowrite injection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
30177
31019
|
}
|
|
30178
31020
|
logTransformTiming(sessionId, "todoCapture", tTodoCapture);
|
|
31021
|
+
const tThinkingBinding = performance.now();
|
|
31022
|
+
const outputEntryIds = resolvePiLkgOutputEntryIds(outputMessages, result.syntheticLeadingCount, (message) => result.lkgEntryIdByRef.get(message) ?? result.postCommitEntryIdByRef.get(message) ?? bindingEntryIdByRef.get(message)).map((entryId) => entryId ?? undefined);
|
|
31023
|
+
const thinkingBindingRecoveryApplied = bindingStripOrder === "end" ? applyPiThinkingBindingRecovery({
|
|
31024
|
+
db: options.db,
|
|
31025
|
+
sessionId,
|
|
31026
|
+
messages: outputMessages,
|
|
31027
|
+
entryIds: outputEntryIds,
|
|
31028
|
+
provider: lkgProviderKey ?? undefined,
|
|
31029
|
+
model: ctx.model?.id,
|
|
31030
|
+
endOfPassOrder: true
|
|
31031
|
+
}) : startOfPassBindingRecovery;
|
|
31032
|
+
if (!options.compactionOff && !sessionMeta.isSubagent && bindingStripOrder === "end") {
|
|
31033
|
+
try {
|
|
31034
|
+
applyPiProactiveThinkingStrip({
|
|
31035
|
+
db: options.db,
|
|
31036
|
+
sessionId,
|
|
31037
|
+
messages: outputMessages,
|
|
31038
|
+
entryIds: outputEntryIds,
|
|
31039
|
+
provider: lkgProviderKey ?? undefined,
|
|
31040
|
+
model: ctx.model?.id,
|
|
31041
|
+
cacheBustingPass: isCacheBusting || result.executedWorkThisPass,
|
|
31042
|
+
report: (line) => sessionLog(sessionId, line)
|
|
31043
|
+
});
|
|
31044
|
+
} catch (err) {
|
|
31045
|
+
sessionLog(sessionId, `proactive thinking strip failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
31046
|
+
}
|
|
31047
|
+
}
|
|
31048
|
+
logTransformTiming(sessionId, "thinkingBinding", tThinkingBinding);
|
|
30179
31049
|
const tChannelAccounting = performance.now();
|
|
30180
31050
|
try {
|
|
30181
31051
|
const sessionMetaForCh1 = sessionMeta;
|
|
@@ -30655,7 +31525,11 @@ function maybeFireHistorian(args) {
|
|
|
30655
31525
|
};
|
|
30656
31526
|
usageSource = "piUsage fallback";
|
|
30657
31527
|
}
|
|
30658
|
-
usage =
|
|
31528
|
+
usage = resolvePiPressureSnapshotWithEstimateGuard({
|
|
31529
|
+
sessionId,
|
|
31530
|
+
source: "historian trigger",
|
|
31531
|
+
liveIsRawBranchEstimate: args.liveIsRawBranchEstimate,
|
|
31532
|
+
persistedFromLive: usageSource === "piUsage fallback",
|
|
30659
31533
|
persistedPercentage: usage.percentage,
|
|
30660
31534
|
persistedInputTokens: usage.inputTokens,
|
|
30661
31535
|
liveInputTokens: piUsage?.tokens,
|
|
@@ -30978,6 +31852,7 @@ async function runPipeline(args) {
|
|
|
30978
31852
|
const foldDueDecision = piM0State ? mustMaterializePi(piM0State, args.db, injectionPassSnapshot?.compartments, injectionPassSnapshot) : { value: false, reason: null };
|
|
30979
31853
|
const firstRenderBust = piM0State !== undefined && !(injectionPassSnapshot?.cachedRow?.cached_m0_bytes && injectionPassSnapshot.cachedRow.cached_m1_bytes);
|
|
30980
31854
|
let foldExecutedThisPass = false;
|
|
31855
|
+
let foldBustsServedPrefixThisPass = false;
|
|
30981
31856
|
let publishedM1RefreshedThisPass = false;
|
|
30982
31857
|
let prefixPreflightContended = false;
|
|
30983
31858
|
const softRefreshOpportunity = args.schedulerDecision === "execute";
|
|
@@ -30991,6 +31866,18 @@ async function runPipeline(args) {
|
|
|
30991
31866
|
prefixPreflightContended = preFoldInjectionResult.contentionExhausted === true;
|
|
30992
31867
|
publishedM1RefreshedThisPass = !prefixPreflightContended && persistedM0BeforeFold.cachedM1Bytes?.toString("utf8") !== getOrCreateSessionMeta(args.db, args.sessionId).cachedM1Bytes?.toString("utf8");
|
|
30993
31868
|
foldExecutedThisPass = foldExecutesThisPass(foldDueDecision.value || softRefreshOpportunity, preFoldInjectionResult.m0Materialized === true);
|
|
31869
|
+
if (foldExecutedThisPass) {
|
|
31870
|
+
const afterFold = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
31871
|
+
foldBustsServedPrefixThisPass = foldBustsServedPrefix(foldDueDecision.reason, {
|
|
31872
|
+
m0Bytes: persistedM0BeforeFold.cachedM0Bytes ?? null,
|
|
31873
|
+
m1Bytes: persistedM0BeforeFold.cachedM1Bytes ?? null,
|
|
31874
|
+
muralDataUrl: persistedM0BeforeFold.cachedM0MuralDataUrl ?? null
|
|
31875
|
+
}, {
|
|
31876
|
+
m0Bytes: afterFold.cachedM0Bytes ?? null,
|
|
31877
|
+
m1Bytes: afterFold.cachedM1Bytes ?? null,
|
|
31878
|
+
muralDataUrl: afterFold.cachedM0MuralDataUrl ?? null
|
|
31879
|
+
});
|
|
31880
|
+
}
|
|
30994
31881
|
if (preFoldInjectionResult.m0Materialized) {
|
|
30995
31882
|
injectionPassSnapshot = createPiM0M1PassSnapshot({
|
|
30996
31883
|
db: args.db,
|
|
@@ -31018,7 +31905,7 @@ async function runPipeline(args) {
|
|
|
31018
31905
|
sessionLog(args.sessionId, `pi m[0] HARD fold pre-execution failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
31019
31906
|
}
|
|
31020
31907
|
const mismatch = foldDueDecision.mismatch ? ` mismatch=${JSON.stringify(foldDueDecision.mismatch)}` : "";
|
|
31021
|
-
sessionLog(args.sessionId, `pi m[0] HARD fold decision: reason=${foldDueDecision.reason ?? "unknown"}${mismatch} executed=${foldExecutedThisPass}`);
|
|
31908
|
+
sessionLog(args.sessionId, `pi m[0] HARD fold decision: reason=${foldDueDecision.reason ?? "unknown"}${mismatch} executed=${foldExecutedThisPass} bustsServedPrefix=${foldBustsServedPrefixThisPass}`);
|
|
31022
31909
|
}
|
|
31023
31910
|
const executePressureEligible = args.schedulerDecision === "execute" || emergencyDropEligible;
|
|
31024
31911
|
if (!executePressureEligible) {
|
|
@@ -31029,7 +31916,7 @@ async function runPipeline(args) {
|
|
|
31029
31916
|
const routinePressureAlreadyApplied = !args.sessionMeta.isSubagent && executePressureEligible && routinePressureAppliedBySession.get(args.sessionId) === true;
|
|
31030
31917
|
const hasPendingMaterializeSignal = hasPendingMaterialization(args.sessionId);
|
|
31031
31918
|
const rideSignals = {
|
|
31032
|
-
hardFold:
|
|
31919
|
+
hardFold: foldBustsServedPrefixThisPass || firstRenderBust,
|
|
31033
31920
|
force: (args.forceMaterialization === true || emergencyDropEligible) && (args.contextUsage.percentage >= 95 || getEmergencyInputSample(args.db, args.sessionId) === 0),
|
|
31034
31921
|
explicitFlush: hasPendingMaterializeSignal || deferredMaterializeEligible && !prefixPreflightContended,
|
|
31035
31922
|
publishedHistory: !prefixPreflightContended && (args.isCacheBusting || publishedM1RefreshedThisPass || canConsumeDeferredLate && deferredHistoryWasPendingAtPassStart)
|
|
@@ -31045,7 +31932,7 @@ async function runPipeline(args) {
|
|
|
31045
31932
|
onRejectedProjectOverride: (warning) => sessionLog(args.sessionId, warning)
|
|
31046
31933
|
});
|
|
31047
31934
|
let protectionFloorResolution = resolveProtectionFloor();
|
|
31048
|
-
const shouldRunHeuristics = args.heuristics !== undefined && isCacheBustingPass && (rideSignals.publishedHistory || args.forceMaterialization === true || hasPendingMaterializeSignal || deferredMaterializeEligible ||
|
|
31935
|
+
const shouldRunHeuristics = args.heuristics !== undefined && isCacheBustingPass && (rideSignals.publishedHistory || args.forceMaterialization === true || hasPendingMaterializeSignal || deferredMaterializeEligible || foldBustsServedPrefixThisPass || firstRenderBust || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
|
|
31049
31936
|
const tFallbackIdentity = performance.now();
|
|
31050
31937
|
const hasFallbackMessageTags = hasPiFallbackMessageTags(args.db, args.sessionId);
|
|
31051
31938
|
const entryFingerprintByMessageId = buildEntryFingerprintMap(args.messages, stableIdResolver, args.reusableMessageIds, hasFallbackMessageTags);
|
|
@@ -31085,6 +31972,19 @@ async function runPipeline(args) {
|
|
|
31085
31972
|
} : undefined
|
|
31086
31973
|
});
|
|
31087
31974
|
logTransformTiming(args.sessionId, "tagMessages", tTag);
|
|
31975
|
+
if (foldBustsServedPrefixThisPass) {
|
|
31976
|
+
try {
|
|
31977
|
+
let converted = 0;
|
|
31978
|
+
args.db.transaction(() => {
|
|
31979
|
+
converted = convertLegacyToolSkeletons(args.db, args.sessionId, targets).size;
|
|
31980
|
+
}).immediate();
|
|
31981
|
+
if (converted > 0) {
|
|
31982
|
+
sessionLog(args.sessionId, `pi HARD fold converted ${converted} legacy dropped-tool skeleton(s) to real-or-absent`);
|
|
31983
|
+
}
|
|
31984
|
+
} catch (error) {
|
|
31985
|
+
sessionLog(args.sessionId, `pi legacy dropped-tool skeleton conversion failed (kept legacy bytes): ${error instanceof Error ? error.message : String(error)}`);
|
|
31986
|
+
}
|
|
31987
|
+
}
|
|
31088
31988
|
try {
|
|
31089
31989
|
if (!args.sessionMeta.isSubagent) {
|
|
31090
31990
|
const hasRecentCommit = detectRecentCommit(args.messages);
|
|
@@ -31111,12 +32011,13 @@ async function runPipeline(args) {
|
|
|
31111
32011
|
mutationGateObserverForTests?.({
|
|
31112
32012
|
foldDue: foldDueDecision.value,
|
|
31113
32013
|
foldExecuted: foldExecutedThisPass,
|
|
32014
|
+
foldBustsServedPrefix: foldBustsServedPrefixThisPass,
|
|
31114
32015
|
shouldApplyPendingOps,
|
|
31115
32016
|
shouldRunHeuristics,
|
|
31116
32017
|
shouldRunReasoningCleanup: args.reasoningClearing !== undefined && shouldRunHeuristics
|
|
31117
32018
|
});
|
|
31118
32019
|
if (shouldApplyPendingOps) {
|
|
31119
|
-
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" :
|
|
32020
|
+
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" : foldBustsServedPrefixThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : `${reclaimRideLabel(rideSignals)} (scheduler=${args.schedulerDecision})`;
|
|
31120
32021
|
const pendingOpsDepth = getPendingOpsCount(args.db, args.sessionId);
|
|
31121
32022
|
const pendingDecisionLog = `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOpsDepth === null ? "not loaded (deferred pass)" : pendingOpsDepth} context=${args.contextUsage.percentage.toFixed(1)}%`;
|
|
31122
32023
|
sessionLog(args.sessionId, pendingDecisionLog);
|
|
@@ -31203,7 +32104,7 @@ async function runPipeline(args) {
|
|
|
31203
32104
|
const activeTags = allTagsForPass.filter((tag) => tag.status === "active");
|
|
31204
32105
|
logTransformTiming(args.sessionId, "getTagsBySessionSnapshot", tActiveTags, `all=${allTagsForPass.length} active=${activeTags.length}`);
|
|
31205
32106
|
if (shouldRunHeuristics) {
|
|
31206
|
-
const reason = args.forceMaterialization ? "force_materialization" :
|
|
32107
|
+
const reason = args.forceMaterialization ? "force_materialization" : foldBustsServedPrefixThisPass && args.schedulerDecision !== "execute" ? `m0_hard_fold (drain folded into executed m[0] bust, scheduler=${args.schedulerDecision})` : `${reclaimRideLabel(rideSignals)} (pendingOps=${pendingOps.length}, scheduler=${args.schedulerDecision})`;
|
|
31207
32108
|
const heuristicsDecisionLog = `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=n/a`;
|
|
31208
32109
|
sessionLog(args.sessionId, heuristicsDecisionLog);
|
|
31209
32110
|
pendingDecisionLogObserverForTests?.(heuristicsDecisionLog);
|
|
@@ -31216,7 +32117,7 @@ async function runPipeline(args) {
|
|
|
31216
32117
|
if (shouldRunHeuristics && args.heuristics) {
|
|
31217
32118
|
try {
|
|
31218
32119
|
const tHeuristic = performance.now();
|
|
31219
|
-
const independentMutationBeforeHeuristics = pendingOpsDidMutate ||
|
|
32120
|
+
const independentMutationBeforeHeuristics = pendingOpsDidMutate || foldBustsServedPrefixThisPass;
|
|
31220
32121
|
if (args.forceMaterialization === true && independentMutationBeforeHeuristics && getEmergencyInputSample(args.db, args.sessionId) > 0) {
|
|
31221
32122
|
clearEmergencyDropSample(args.db, args.sessionId);
|
|
31222
32123
|
}
|
|
@@ -31991,6 +32892,7 @@ ${result}`;
|
|
|
31991
32892
|
}
|
|
31992
32893
|
|
|
31993
32894
|
// ../plugin/src/features/magic-context/store-generation-rebase.ts
|
|
32895
|
+
var rebasesInFlight = new WeakMap;
|
|
31994
32896
|
var repairCheckedSessions = new WeakMap;
|
|
31995
32897
|
|
|
31996
32898
|
// ../plugin/src/hooks/magic-context/historian-state-file.ts
|
|
@@ -32195,7 +33097,7 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
32195
33097
|
clearInjectionCache(sessionId);
|
|
32196
33098
|
}
|
|
32197
33099
|
promoted.facts;
|
|
32198
|
-
|
|
33100
|
+
{
|
|
32199
33101
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
32200
33102
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
32201
33103
|
const liveCompartments = getCompartments(db, sessionId);
|
|
@@ -32412,7 +33314,7 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
32412
33314
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd, compartmentTagKeys);
|
|
32413
33315
|
}
|
|
32414
33316
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
32415
|
-
|
|
33317
|
+
{
|
|
32416
33318
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
32417
33319
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
32418
33320
|
const liveCompartments = getCompartments(db, sessionId);
|
|
@@ -32574,7 +33476,7 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
32574
33476
|
clearInjectionCache(sessionId);
|
|
32575
33477
|
}
|
|
32576
33478
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
32577
|
-
|
|
33479
|
+
{
|
|
32578
33480
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
32579
33481
|
const liveCompartments = getCompartments(db, sessionId);
|
|
32580
33482
|
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
@@ -33551,6 +34453,8 @@ ${c.content}
|
|
|
33551
34453
|
|
|
33552
34454
|
// ../plugin/src/shared/cache-ttl-display.ts
|
|
33553
34455
|
function resolveCacheTtlDisplay(args) {
|
|
34456
|
+
if (args.frozen)
|
|
34457
|
+
return args.frozen;
|
|
33554
34458
|
if (args.sessionModelKey && (!args.modelKey || args.sessionModelKey === args.modelKey) || !args.modelKey && !args.sessionModelKey && args.sessionValue !== "5m") {
|
|
33555
34459
|
return {
|
|
33556
34460
|
value: args.sessionValue || "5m",
|
|
@@ -33558,24 +34462,14 @@ function resolveCacheTtlDisplay(args) {
|
|
|
33558
34462
|
modelKey: args.modelKey ?? args.sessionModelKey ?? undefined
|
|
33559
34463
|
};
|
|
33560
34464
|
}
|
|
33561
|
-
|
|
33562
|
-
|
|
33563
|
-
|
|
33564
|
-
|
|
33565
|
-
modelKey: args.modelKey
|
|
33566
|
-
};
|
|
33567
|
-
}
|
|
33568
|
-
const matched = resolveModelConfigValue(args.configured, args.modelKey);
|
|
33569
|
-
if (matched) {
|
|
33570
|
-
return { value: matched.value, source: "config", modelKey: args.modelKey };
|
|
33571
|
-
}
|
|
33572
|
-
return {
|
|
33573
|
-
value: args.configured.default ?? "5m",
|
|
33574
|
-
source: "default",
|
|
33575
|
-
modelKey: args.modelKey
|
|
33576
|
-
};
|
|
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;
|
|
33577
34469
|
}
|
|
33578
34470
|
function formatCacheTtlDisplay(display) {
|
|
34471
|
+
if (display.source === "OpenAI GPT-5.6+ default")
|
|
34472
|
+
return `Cache TTL: ${display.value} (${display.source})`;
|
|
33579
34473
|
if (display.source === "session")
|
|
33580
34474
|
return `Cache TTL: ${display.value} (session)`;
|
|
33581
34475
|
if (display.source === "config") {
|
|
@@ -33601,6 +34495,11 @@ function compressionText(summary) {
|
|
|
33601
34495
|
return "Waiting for enough conversation history";
|
|
33602
34496
|
}
|
|
33603
34497
|
}
|
|
34498
|
+
function runnerText(status) {
|
|
34499
|
+
const why = status.source === "configured" ? "configured" : `default for harness ${status.harness || "unknown"}`;
|
|
34500
|
+
const observed = status.observed === "last_completion" ? "" : " · no completion yet";
|
|
34501
|
+
return `${status.runner} (${why})${observed}`;
|
|
34502
|
+
}
|
|
33604
34503
|
function reclaimableText(summary) {
|
|
33605
34504
|
const count = Math.max(0, Math.floor(summary.reclaimable.toolOutputCount));
|
|
33606
34505
|
if (count === 0)
|
|
@@ -33642,6 +34541,12 @@ function renderUserStatusSummary(summary, style) {
|
|
|
33642
34541
|
],
|
|
33643
34542
|
["Search indexing", embeddingText(summary)]
|
|
33644
34543
|
];
|
|
34544
|
+
if (summary.historianRunner) {
|
|
34545
|
+
values.push(["Historian runner", runnerText(summary.historianRunner)]);
|
|
34546
|
+
}
|
|
34547
|
+
if (summary.dreamerRunner) {
|
|
34548
|
+
values.push(["Dreamer runner", runnerText(summary.dreamerRunner)]);
|
|
34549
|
+
}
|
|
33645
34550
|
if (summary.historianRefusal) {
|
|
33646
34551
|
values.push([
|
|
33647
34552
|
"Historian refusal",
|
|
@@ -34120,7 +35025,7 @@ function buildStatusView(source, options) {
|
|
|
34120
35025
|
// package.json
|
|
34121
35026
|
var package_default = {
|
|
34122
35027
|
name: "@cortexkit/pi-magic-context",
|
|
34123
|
-
version: "0.
|
|
35028
|
+
version: "0.44.1",
|
|
34124
35029
|
type: "module",
|
|
34125
35030
|
description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
|
|
34126
35031
|
main: "dist/index.js",
|
|
@@ -34147,6 +35052,7 @@ var package_default = {
|
|
|
34147
35052
|
"dist",
|
|
34148
35053
|
"README.md"
|
|
34149
35054
|
],
|
|
35055
|
+
"//": "The build intentionally bundles typebox (no --external typebox) and keeps it a regular dependency. OMP's extension loader rewrites every bare `typebox` import to its own omptype-based shim, whose schemas are callable objects rather than JSON Schema; they fail structuredClone during tool registration, so an external typebox import stops Magic Context loading on OMP. src/typebox-bundling.test.ts guards this.",
|
|
34150
35056
|
scripts: {
|
|
34151
35057
|
build: "bun ../../scripts/check-bun.mjs && tsc -p ../retina-local-fs/tsconfig.build.json && rm -f dist/index.js dist/subagent-entry.js dist/historian-calibration-extension.js dist/transformers-web.js dist/transformers-node-wasm.js dist/*-*.js && bun build ../plugin/src/features/magic-context/memory/transformers-web-entry.ts --outfile dist/transformers-web.js --target browser --format esm --external onnxruntime-web && bun ../plugin/scripts/build-transformers-node-wasm.ts dist && bun build src/index.ts src/subagent-entry.ts src/historian-calibration-extension.ts --outdir dist --target node --format esm --splitting --external @earendil-works/pi-coding-agent --external @earendil-works/pi-tui --external onnxruntime-node --external onnxruntime-web --external sharp --external node:sqlite",
|
|
34152
35058
|
"build:e2e-argv": "bun build src/subagent-runner.ts --outfile ../../tests/docker/.generated/subagent-runner-e2e.mjs --target node --format esm --external node:sqlite",
|
|
@@ -34161,7 +35067,7 @@ var package_default = {
|
|
|
34161
35067
|
prepublishOnly: "bun run build"
|
|
34162
35068
|
},
|
|
34163
35069
|
dependencies: {
|
|
34164
|
-
"@cortexkit/subc-client": "0.
|
|
35070
|
+
"@cortexkit/subc-client": "0.11.1",
|
|
34165
35071
|
"@jitl/quickjs-singlefile-cjs-release-asyncify": "0.32.0",
|
|
34166
35072
|
"ai-tokenizer": "^1.0.6",
|
|
34167
35073
|
"comment-json": "^5.0.0",
|
|
@@ -34183,6 +35089,7 @@ var package_default = {
|
|
|
34183
35089
|
"@types/better-sqlite3": "^7.6.13",
|
|
34184
35090
|
"@types/bun": "^1.3.10",
|
|
34185
35091
|
"@types/node": "^22.20.0",
|
|
35092
|
+
"pi-agent-core-087": "npm:@earendil-works/pi-agent-core@0.87.1",
|
|
34186
35093
|
"pi-ai-086": "npm:@earendil-works/pi-ai@0.86.0",
|
|
34187
35094
|
"pi-coding-agent-086": "npm:@earendil-works/pi-coding-agent@0.86.0",
|
|
34188
35095
|
"pi-coding-agent-087": "npm:@earendil-works/pi-coding-agent@0.87.1",
|
|
@@ -34530,6 +35437,7 @@ ${safeStringify(tool.parameters)}`);
|
|
|
34530
35437
|
sessionId
|
|
34531
35438
|
});
|
|
34532
35439
|
const cacheTtlDisplay = resolveCacheTtlDisplay({
|
|
35440
|
+
frozen: readSessionCacheTtl(deps.db, sessionId),
|
|
34533
35441
|
configured: deps.cacheTtlConfig ?? "5m",
|
|
34534
35442
|
configuredExplicitly: deps.cacheTtlConfigured === true,
|
|
34535
35443
|
modelKey,
|
|
@@ -34723,11 +35631,14 @@ No active Pi session is available.`,
|
|
|
34723
35631
|
}
|
|
34724
35632
|
try {
|
|
34725
35633
|
if (ctx.hasUI) {
|
|
35634
|
+
if (currentDeps.modelChainWarning)
|
|
35635
|
+
ctx.ui.notify(currentDeps.modelChainWarning, "error");
|
|
34726
35636
|
await showStatusDialog(pi, ctx, currentDeps);
|
|
34727
35637
|
return;
|
|
34728
35638
|
}
|
|
34729
35639
|
const statusDetail = buildPiStatusDetail(pi, ctx, currentDeps, sessionId);
|
|
34730
|
-
const statusText = formatPiStatusSummary(statusDetail)
|
|
35640
|
+
const statusText = `${formatPiStatusSummary(statusDetail)}${currentDeps.modelChainWarning ? `
|
|
35641
|
+
WARNING: ${currentDeps.modelChainWarning}` : ""}`;
|
|
34731
35642
|
const details = buildStatusDetails(currentDeps, statusDetail);
|
|
34732
35643
|
sendStatus({
|
|
34733
35644
|
title: "/ctx-status",
|
|
@@ -35436,7 +36347,7 @@ function persistPiMessageEndModelMeta(args) {
|
|
|
35436
36347
|
const modelKey = canonicalPiModelKey(msg.provider, msg.model);
|
|
35437
36348
|
if (!recordPiLiveModel(args.sessionId, modelKey, msg.timestamp))
|
|
35438
36349
|
return;
|
|
35439
|
-
const cacheTtl =
|
|
36350
|
+
const cacheTtl = resolveSessionCacheTtl(args.db, args.sessionId, args.cacheTtlConfig, modelKey).value;
|
|
35440
36351
|
const currentMeta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
35441
36352
|
updateSessionMeta(args.db, args.sessionId, {
|
|
35442
36353
|
...currentMeta.cacheTtl === cacheTtl ? {} : { cacheTtl },
|
|
@@ -35502,6 +36413,13 @@ function info(message, data) {
|
|
|
35502
36413
|
function warn(message, data) {
|
|
35503
36414
|
log(`${PREFIX2} WARN ${message}`, data);
|
|
35504
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
|
+
}
|
|
35505
36423
|
var migratedConfigDirs = new Set;
|
|
35506
36424
|
var loggedPiConfigDirs = new Set;
|
|
35507
36425
|
function ensureConfigLocationsMigrated(dir) {
|
|
@@ -35514,7 +36432,7 @@ function ensureConfigLocationsMigrated(dir) {
|
|
|
35514
36432
|
});
|
|
35515
36433
|
}
|
|
35516
36434
|
function logPiConfigLoad(args) {
|
|
35517
|
-
const key =
|
|
36435
|
+
const key = resolve4(args.dir);
|
|
35518
36436
|
if (args.dedupe && loggedPiConfigDirs.has(key))
|
|
35519
36437
|
return;
|
|
35520
36438
|
if (args.dedupe) {
|
|
@@ -35542,6 +36460,14 @@ function claimProtectedTagsDeprecationNoticeOnce() {
|
|
|
35542
36460
|
function resetClaimedProtectedTagsDeprecationNoticeForTesting() {
|
|
35543
36461
|
protectedTagsDeprecationClaimed = false;
|
|
35544
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
|
+
}
|
|
35545
36471
|
var __test = {
|
|
35546
36472
|
logPiConfigLoad,
|
|
35547
36473
|
resetLoggedPiConfigDirs() {
|
|
@@ -35575,6 +36501,13 @@ function logPiUsageBoundOnce(sessionId, reading, absoluteWall, reason) {
|
|
|
35575
36501
|
piUsageBoundLogSeen.add(key);
|
|
35576
36502
|
info(`message_end: session=${sessionId} bounded ${reason} ${reading} at trusted absolute wall ${absoluteWall}; pressure_proof_not_capacity`);
|
|
35577
36503
|
}
|
|
36504
|
+
function logPiUsageAboveWindowOnce(sessionId, reading, absoluteWall) {
|
|
36505
|
+
const key = `${sessionId}|accepted above window`;
|
|
36506
|
+
if (piUsageBoundLogSeen.has(key))
|
|
36507
|
+
return;
|
|
36508
|
+
piUsageBoundLogSeen.add(key);
|
|
36509
|
+
info(`message_end: session=${sessionId} provider usage ${reading} exceeds configured window ${absoluteWall}; counted as real pressure against the configured limit`);
|
|
36510
|
+
}
|
|
35578
36511
|
function resolvePiPressureContextLimit(args) {
|
|
35579
36512
|
let detectedContextLimit;
|
|
35580
36513
|
try {
|
|
@@ -35606,24 +36539,32 @@ async function persistPiPressureFromMessageEnd(args) {
|
|
|
35606
36539
|
});
|
|
35607
36540
|
const trustedAbsoluteWall = reportedGeometry && hasTrustedAbsoluteWall(reportedGeometry) ? reportedGeometry.derivation.absoluteWall : undefined;
|
|
35608
36541
|
const unboundedPressure = computePiPressure(usage, args.piContextWindow);
|
|
35609
|
-
const rawPressure = computePiPressure(usage, args.piContextWindow, trustedAbsoluteWall);
|
|
35610
|
-
if (unboundedPressure && trustedAbsoluteWall !== undefined && unboundedPressure.inputTokens > trustedAbsoluteWall) {
|
|
35611
|
-
logPiUsageBoundOnce(args.sessionId, unboundedPressure.inputTokens, trustedAbsoluteWall, "current reading");
|
|
35612
|
-
}
|
|
35613
36542
|
const msg = args.message && typeof args.message === "object" ? args.message : undefined;
|
|
35614
36543
|
const messageHadOverflowError = typeof msg?.errorMessage === "string" && detectOverflow(msg.errorMessage).isOverflow;
|
|
35615
|
-
const
|
|
35616
|
-
|
|
36544
|
+
const readingAboveTrustedWall = unboundedPressure !== null && trustedAbsoluteWall !== undefined && unboundedPressure.inputTokens > trustedAbsoluteWall;
|
|
36545
|
+
const requestAccepted = !messageHadOverflowError;
|
|
36546
|
+
if (readingAboveTrustedWall && unboundedPressure && trustedAbsoluteWall) {
|
|
36547
|
+
if (requestAccepted) {
|
|
36548
|
+
logPiUsageAboveWindowOnce(args.sessionId, unboundedPressure.inputTokens, trustedAbsoluteWall);
|
|
36549
|
+
} else {
|
|
36550
|
+
logPiUsageBoundOnce(args.sessionId, unboundedPressure.inputTokens, trustedAbsoluteWall, "current reading");
|
|
36551
|
+
}
|
|
36552
|
+
}
|
|
36553
|
+
const requestSucceeded = requestAccepted && !readingAboveTrustedWall;
|
|
36554
|
+
if (requestAccepted && unboundedPressure) {
|
|
35617
36555
|
const rawOverflow = getOverflowState(args.db, args.sessionId);
|
|
35618
36556
|
const detectedLimitMatchesModel = rawOverflow.detectedContextLimitModelKey === null || modelKey !== undefined && rawOverflow.detectedContextLimitModelKey === modelKey;
|
|
35619
|
-
if (rawOverflow.detectedContextLimit > 0 && detectedLimitMatchesModel &&
|
|
36557
|
+
if (rawOverflow.detectedContextLimit > 0 && detectedLimitMatchesModel && unboundedPressure.inputTokens > rawOverflow.detectedContextLimit) {
|
|
35620
36558
|
clearDetectedContextLimit(args.db, args.sessionId);
|
|
35621
|
-
info(`message_end: detected limit ${rawOverflow.detectedContextLimit} invalidated by a successful ${
|
|
36559
|
+
info(`message_end: detected limit ${rawOverflow.detectedContextLimit} invalidated by a successful ${unboundedPressure.inputTokens}-token request; using Pi contextWindow`);
|
|
35622
36560
|
}
|
|
35623
36561
|
}
|
|
35624
36562
|
const meta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
35625
36563
|
let observedSafeInputTokens = meta.observedSafeInputTokens ?? 0;
|
|
35626
|
-
const updates = {
|
|
36564
|
+
const updates = {};
|
|
36565
|
+
if (unboundedPressure !== null) {
|
|
36566
|
+
updates.lastResponseTime = Date.now();
|
|
36567
|
+
}
|
|
35627
36568
|
if (trustedAbsoluteWall !== undefined && observedSafeInputTokens > trustedAbsoluteWall) {
|
|
35628
36569
|
logPiUsageBoundOnce(args.sessionId, observedSafeInputTokens, trustedAbsoluteWall, "persisted floor");
|
|
35629
36570
|
observedSafeInputTokens = 0;
|
|
@@ -35644,8 +36585,10 @@ async function persistPiPressureFromMessageEnd(args) {
|
|
|
35644
36585
|
provenInputTokens: observedSafeInputTokens
|
|
35645
36586
|
});
|
|
35646
36587
|
const reportedContextLimit = reportedGeometry?.usableSoft ?? 0;
|
|
35647
|
-
const pressure = computePiPressure(usage, effectiveContextLimit, trustedAbsoluteWall);
|
|
36588
|
+
const pressure = computePiPressure(usage, effectiveContextLimit, requestAccepted ? undefined : trustedAbsoluteWall);
|
|
36589
|
+
let cacheAlert;
|
|
35648
36590
|
if (pressure) {
|
|
36591
|
+
notePiUsageReadingUsed(args.sessionId);
|
|
35649
36592
|
const provenSafeInputTokens = requestSucceeded ? Math.max(observedSafeInputTokens, pressure.inputTokens) : observedSafeInputTokens;
|
|
35650
36593
|
const contextLimit = requestSucceeded ? resolvePiPressureContextLimit({
|
|
35651
36594
|
db: args.db,
|
|
@@ -35659,7 +36602,7 @@ async function persistPiPressureFromMessageEnd(args) {
|
|
|
35659
36602
|
if (requestSucceeded && reportedContextLimit > 0 && reportedContextLimit < provenSafeInputTokens && !meta.cacheAlertSent) {
|
|
35660
36603
|
updates.cacheAlertSent = true;
|
|
35661
36604
|
const modelLabel = activeModel.provider && activeModel.id ? `${activeModel.provider}/${activeModel.id}` : "the active model";
|
|
35662
|
-
|
|
36605
|
+
cacheAlert = `⚠️ Magic Context: Pi reports a context limit of ${formatTokens(reportedContextLimit)} tokens for ${modelLabel}, but this session has sent ${formatTokens(provenSafeInputTokens)} tokens successfully. Magic Context will keep using the larger proven value for its pressure math. If Pi's model metadata is wrong for your provider, set contextWindow for that model in Pi's model configuration.`;
|
|
35663
36606
|
}
|
|
35664
36607
|
updates.lastContextPercentage = percentage;
|
|
35665
36608
|
updates.lastInputTokens = pressure.inputTokens;
|
|
@@ -35668,13 +36611,21 @@ async function persistPiPressureFromMessageEnd(args) {
|
|
|
35668
36611
|
updates.observedSafeInputTokens = provenSafeInputTokens;
|
|
35669
36612
|
}
|
|
35670
36613
|
} else if (usage === null && typeof args.piTokens === "number" && (trustedAbsoluteWall === undefined || args.piTokens <= trustedAbsoluteWall)) {
|
|
35671
|
-
|
|
35672
|
-
|
|
35673
|
-
|
|
35674
|
-
|
|
36614
|
+
if (args.piTokensIsRawBranchEstimate === true) {
|
|
36615
|
+
noteRawBranchEstimateSetAside(args.sessionId, args.piTokens, "message_end estimate");
|
|
36616
|
+
} else {
|
|
36617
|
+
notePiUsageReadingUsed(args.sessionId);
|
|
36618
|
+
updates.lastInputTokens = args.piTokens;
|
|
36619
|
+
if (effectiveContextLimit > 0) {
|
|
36620
|
+
updates.lastContextPercentage = args.piTokens / effectiveContextLimit * 100;
|
|
36621
|
+
updates.lastUsageContextLimit = effectiveContextLimit;
|
|
36622
|
+
}
|
|
35675
36623
|
}
|
|
35676
36624
|
}
|
|
35677
36625
|
updateSessionMeta(args.db, args.sessionId, updates);
|
|
36626
|
+
if (cacheAlert !== undefined) {
|
|
36627
|
+
await args.notifyIssue?.(cacheAlert);
|
|
36628
|
+
}
|
|
35678
36629
|
}
|
|
35679
36630
|
var PLUGIN_VERSION = (() => {
|
|
35680
36631
|
try {
|
|
@@ -35685,17 +36636,27 @@ var PLUGIN_VERSION = (() => {
|
|
|
35685
36636
|
}
|
|
35686
36637
|
})();
|
|
35687
36638
|
setHarness(PI_HARNESS_KIND);
|
|
35688
|
-
function resolveHistorianFromConfig(config, harness = PI_HARNESS_KIND) {
|
|
36639
|
+
function resolveHistorianFromConfig(config, harness = PI_HARNESS_KIND, modelRegistry) {
|
|
35689
36640
|
const historian = config.historian;
|
|
35690
36641
|
if (historian?.disable === true)
|
|
35691
36642
|
return;
|
|
35692
36643
|
const resolved = resolveHistorianModel(config, harness);
|
|
35693
|
-
const
|
|
36644
|
+
const validated = modelRegistry && resolved.primary ? validatePiDreamerModels([
|
|
36645
|
+
{
|
|
36646
|
+
task: "classify-memories",
|
|
36647
|
+
schedule: "",
|
|
36648
|
+
timeoutMinutes: 20,
|
|
36649
|
+
model: resolved.primary,
|
|
36650
|
+
fallbackModels: resolved.fallbacks
|
|
36651
|
+
}
|
|
36652
|
+
], modelRegistry, harness)[0] : undefined;
|
|
36653
|
+
const primary = validated ? typeof validated.model === "string" ? { model: validated.model } : validated.model : resolved.primary;
|
|
36654
|
+
const model = primary?.model;
|
|
35694
36655
|
if (!model)
|
|
35695
36656
|
return;
|
|
35696
36657
|
const historianContextLimit = resolveHistorianContextLimit(model);
|
|
35697
36658
|
const historianChunkTokens = deriveHistorianChunkTokens(historianContextLimit);
|
|
35698
|
-
const fallbackModels = resolved.fallbacks;
|
|
36659
|
+
const fallbackModels = validated?.fallbackModels ?? resolved.fallbacks;
|
|
35699
36660
|
return {
|
|
35700
36661
|
runner: new PiSubagentRunner,
|
|
35701
36662
|
model,
|
|
@@ -35706,7 +36667,7 @@ function resolveHistorianFromConfig(config, harness = PI_HARNESS_KIND) {
|
|
|
35706
36667
|
temperature: historian?.temperature,
|
|
35707
36668
|
maxOutputTokens: historian?.maxTokens,
|
|
35708
36669
|
twoPass: historian?.two_pass === true,
|
|
35709
|
-
thinkingLevel:
|
|
36670
|
+
thinkingLevel: primary?.qualifier,
|
|
35710
36671
|
executeThresholdPercentage: config.execute_threshold_percentage,
|
|
35711
36672
|
executeThresholdTokens: config.execute_threshold_tokens,
|
|
35712
36673
|
commitClusterTrigger: config.commit_cluster_trigger,
|
|
@@ -35760,7 +36721,7 @@ async function src_default(pi) {
|
|
|
35760
36721
|
mmapSizeMb: bootConfig.config.sqlite.mmap_size_mb
|
|
35761
36722
|
});
|
|
35762
36723
|
const storageDir = getMagicContextStorageDir();
|
|
35763
|
-
const dbPath =
|
|
36724
|
+
const dbPath = join11(storageDir, "context.db");
|
|
35764
36725
|
let openFailureCause = null;
|
|
35765
36726
|
const openStorage = async () => {
|
|
35766
36727
|
try {
|
|
@@ -35770,30 +36731,7 @@ async function src_default(pi) {
|
|
|
35770
36731
|
return null;
|
|
35771
36732
|
}
|
|
35772
36733
|
};
|
|
35773
|
-
const unavailableReason = () => {
|
|
35774
|
-
const migration = getMigrationOnOpenRefusal();
|
|
35775
|
-
const blockingProcesses = migration?.blockingProcesses ?? migration?.serverPids.map((pid) => ({ kind: "process", pid })) ?? [];
|
|
35776
|
-
const fence = getSchemaFenceRejection();
|
|
35777
|
-
if (migration && blockingProcesses.length > 0) {
|
|
35778
|
-
return {
|
|
35779
|
-
kind: "migration_guard",
|
|
35780
|
-
persistedVersion: migration.persistedVersion,
|
|
35781
|
-
supportedVersion: migration.supportedVersion,
|
|
35782
|
-
blockingProcesses
|
|
35783
|
-
};
|
|
35784
|
-
}
|
|
35785
|
-
if (fence) {
|
|
35786
|
-
return {
|
|
35787
|
-
kind: "schema_fence",
|
|
35788
|
-
persistedVersion: fence.persistedVersion,
|
|
35789
|
-
supportedVersion: fence.supportedVersion
|
|
35790
|
-
};
|
|
35791
|
-
}
|
|
35792
|
-
return {
|
|
35793
|
-
kind: "storage_failure",
|
|
35794
|
-
cause: migration?.unreadableFile ? `migration guard could not read RPC discovery file ${migration.unreadableFile}` : openFailureCause ?? `storage unavailable at ${dbPath} (cache schema newer than this binary, or open failed)`
|
|
35795
|
-
};
|
|
35796
|
-
};
|
|
36734
|
+
const unavailableReason = () => describeStorageUnavailability(openFailureCause ?? `storage unavailable at ${dbPath} (cache schema newer than this binary, or open failed)`);
|
|
35797
36735
|
const bootResult = await bootPiRuntimeWithDeadline({
|
|
35798
36736
|
deadlineMs: PI_BOOT_DEADLINE_MS,
|
|
35799
36737
|
openStorage,
|
|
@@ -35888,7 +36826,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
35888
36826
|
const projectIdentity = resolveProjectIdentityForSession(projectDir, config.allow_home_project) ?? "";
|
|
35889
36827
|
if (projectIdentity)
|
|
35890
36828
|
seenDreamerProjectIdentities.add(projectIdentity);
|
|
35891
|
-
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}`);
|
|
35892
36830
|
const compactionOff = !isCompactionEnabled(config);
|
|
35893
36831
|
setCtxReduceRegisteredGlobally(!compactionOff);
|
|
35894
36832
|
if (!compactionOff) {
|
|
@@ -35923,7 +36861,11 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
35923
36861
|
return;
|
|
35924
36862
|
}
|
|
35925
36863
|
await ensureProjectRegisteredFromPiDirectory(projectDir, db);
|
|
35926
|
-
|
|
36864
|
+
if (isUsableProjectIdentity(projectIdentity)) {
|
|
36865
|
+
info(`registered embedding config for project ${projectIdentity}`);
|
|
36866
|
+
} else {
|
|
36867
|
+
logNoProjectIdentityOnce(projectDir);
|
|
36868
|
+
}
|
|
35927
36869
|
const projectDepsByDir = new Map;
|
|
35928
36870
|
const liveReaders = new Map;
|
|
35929
36871
|
function liveReaderFor(dir, boot) {
|
|
@@ -35947,6 +36889,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
35947
36889
|
}
|
|
35948
36890
|
const buildContextOptions = (cfg, hist, auto) => ({
|
|
35949
36891
|
db: database,
|
|
36892
|
+
cacheTtlConfig: cfg.cache_ttl,
|
|
35950
36893
|
smartDrops: cfg.smart_drops === true,
|
|
35951
36894
|
protectedTokens: cfg.protected_tokens,
|
|
35952
36895
|
protectedTokenTierOverrides: getProtectedTokensTierOverrides(cfg) ?? {},
|
|
@@ -35973,21 +36916,15 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
35973
36916
|
language: cfg.language,
|
|
35974
36917
|
autoSearch: auto,
|
|
35975
36918
|
resolveForProject: resolveContextOptionsForProject,
|
|
36919
|
+
todowriteEnabled: cfg.todowrite.enabled,
|
|
35976
36920
|
compactionOff,
|
|
35977
36921
|
allowHomeProject: cfg.allow_home_project,
|
|
35978
36922
|
maybeAutoEmbedSession: (sessionId, dir, identity) => {
|
|
35979
36923
|
maybeAutoEmbedPiSession({
|
|
35980
36924
|
db: database,
|
|
35981
36925
|
projectDir: dir,
|
|
35982
|
-
projectIdentity: identity
|
|
35983
|
-
|
|
35984
|
-
}, sessionId, dir, identity, (text) => {
|
|
35985
|
-
sendCtxStatusMessage(pi, {
|
|
35986
|
-
title: "/ctx-embed",
|
|
35987
|
-
text,
|
|
35988
|
-
level: "info"
|
|
35989
|
-
});
|
|
35990
|
-
});
|
|
36926
|
+
projectIdentity: identity
|
|
36927
|
+
}, sessionId, dir, identity);
|
|
35991
36928
|
}
|
|
35992
36929
|
});
|
|
35993
36930
|
function buildProjectDeps(dir, identity, cfg, loadMetadata) {
|
|
@@ -36041,10 +36978,11 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36041
36978
|
function resolveCurrentProjectDeps(ctx) {
|
|
36042
36979
|
return resolveProjectDepsForDir(ctx.cwd);
|
|
36043
36980
|
}
|
|
36981
|
+
let activeModelRegistry;
|
|
36044
36982
|
function resolveContextOptionsForProject(dir) {
|
|
36045
36983
|
const project = resolveProjectDepsForDir(dir);
|
|
36046
36984
|
const sampled = historianRunConfig(project.config, liveReaderFor(dir, project.config).poll().effective);
|
|
36047
|
-
const historian = resolveHistorianFromConfig(sampled);
|
|
36985
|
+
const historian = resolveHistorianFromConfig(sampled, PI_HARNESS_KIND, activeModelRegistry);
|
|
36048
36986
|
return { ...project.contextOptions, historian };
|
|
36049
36987
|
}
|
|
36050
36988
|
const bootProjectDeps = buildProjectDeps(projectDir, projectIdentity, config, {
|
|
@@ -36053,9 +36991,13 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36053
36991
|
hasDeprecatedProtectedTags
|
|
36054
36992
|
});
|
|
36055
36993
|
projectDepsByDir.set(projectDir, bootProjectDeps);
|
|
36056
|
-
function syncDreamerProjectRegistration(current) {
|
|
36994
|
+
function syncDreamerProjectRegistration(current, modelRegistry) {
|
|
36057
36995
|
if (sessionShuttingDown)
|
|
36058
36996
|
return;
|
|
36997
|
+
if (!isUsableProjectIdentity(current.projectIdentity)) {
|
|
36998
|
+
logNoProjectIdentityOnce(current.projectDir);
|
|
36999
|
+
return;
|
|
37000
|
+
}
|
|
36059
37001
|
seenDreamerProjectIdentities.add(current.projectIdentity);
|
|
36060
37002
|
if (!current.dreamerConfig) {
|
|
36061
37003
|
unregisterPiDreamerProject({
|
|
@@ -36070,6 +37012,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36070
37012
|
projectIdentity: current.projectIdentity,
|
|
36071
37013
|
registrationOwner: dreamerRegistrationOwner,
|
|
36072
37014
|
config: current.dreamerConfig,
|
|
37015
|
+
modelRegistry,
|
|
36073
37016
|
sampleDreamRun: () => {
|
|
36074
37017
|
const fresh = liveReaderFor(current.projectDir, current.config).poll().effective;
|
|
36075
37018
|
const sampled = dreamerRunConfig(current.config, fresh);
|
|
@@ -36090,8 +37033,8 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36090
37033
|
});
|
|
36091
37034
|
}
|
|
36092
37035
|
registerPiDroppedInputGuard(pi);
|
|
36093
|
-
const todowriteEnabled = bootProjectDeps.config.todowrite.enabled
|
|
36094
|
-
const todowriteOverlayEnabled = todowriteEnabled && bootProjectDeps.config.todowrite.overlay
|
|
37036
|
+
const todowriteEnabled = bootProjectDeps.config.todowrite.enabled;
|
|
37037
|
+
const todowriteOverlayEnabled = todowriteEnabled && bootProjectDeps.config.todowrite.overlay;
|
|
36095
37038
|
registerMagicContextTools(pi, {
|
|
36096
37039
|
db,
|
|
36097
37040
|
ensureProjectRegistered: ensureProjectRegisteredFromPiDirectory,
|
|
@@ -36111,6 +37054,8 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36111
37054
|
pi.on("session_start", async (event, ctx) => {
|
|
36112
37055
|
projectDepsByDir.delete(ctx.cwd);
|
|
36113
37056
|
const current = resolveCurrentProjectDeps(ctx);
|
|
37057
|
+
activeModelRegistry = ctx.modelRegistry;
|
|
37058
|
+
syncDreamerProjectRegistration(current, ctx.modelRegistry);
|
|
36114
37059
|
syncCtxMemoryToolEnabled(pi, current.config.memory.enabled);
|
|
36115
37060
|
const failuresToShow = claimConfigParseFailuresOnce("pi", current.configParseFailures);
|
|
36116
37061
|
if (ctx.hasUI && failuresToShow.length > 0) {
|
|
@@ -36135,12 +37080,11 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36135
37080
|
});
|
|
36136
37081
|
});
|
|
36137
37082
|
const readLastTodoState = (sessionId) => getOrCreateSessionMeta(db, sessionId).lastTodoState;
|
|
36138
|
-
|
|
36139
|
-
|
|
36140
|
-
|
|
36141
|
-
const todoOverlay = todowriteOverlayEnabled ? registerTodoOverlay(pi, {
|
|
37083
|
+
const todoOverlay = registerConfiguredTodoLifecycle(pi, {
|
|
37084
|
+
configured: todowriteEnabled,
|
|
37085
|
+
overlay: bootProjectDeps.config.todowrite.overlay,
|
|
36142
37086
|
readLastTodoState
|
|
36143
|
-
})
|
|
37087
|
+
});
|
|
36144
37088
|
info(todowriteOverlayEnabled ? "registered todowrite overlay" : "registered todowrite overlay: DISABLED (todowrite.enabled=false or todowrite.overlay=false)");
|
|
36145
37089
|
registerPiContextHandler(pi, bootProjectDeps.contextOptions);
|
|
36146
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)");
|
|
@@ -36189,6 +37133,16 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36189
37133
|
runnable: current.dreamerEnabled,
|
|
36190
37134
|
scheduleSummary: summarizeDreamSchedule(current.config.dreamer)
|
|
36191
37135
|
},
|
|
37136
|
+
modelChainWarning: (() => {
|
|
37137
|
+
const registry = activeModelRegistry;
|
|
37138
|
+
if (!registry)
|
|
37139
|
+
return;
|
|
37140
|
+
const tasks = validatePiDreamerModels(buildDreamTaskRuntimeConfigs(current.config.dreamer, PI_HARNESS_KIND, current.config.language, current.config.mural.model), registry, PI_HARNESS_KIND);
|
|
37141
|
+
const empty = tasks.filter((task) => task.modelChainUnavailable).map((task) => task.task);
|
|
37142
|
+
if (!resolveHistorianFromConfig(current.config, PI_HARNESS_KIND, registry) && current.historianConfig)
|
|
37143
|
+
empty.push("historian");
|
|
37144
|
+
return empty.length ? `Pi model chain empty (no model found): ${empty.join(", ")}` : undefined;
|
|
37145
|
+
})(),
|
|
36192
37146
|
activeProfile: current.config.profile,
|
|
36193
37147
|
cacheTtlConfig: current.config.cache_ttl,
|
|
36194
37148
|
cacheTtlConfigured: current.cacheTtlConfigured,
|
|
@@ -36218,7 +37172,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36218
37172
|
resolveRuntimeDeps: (ctx) => {
|
|
36219
37173
|
const current = resolveCurrentProjectDeps(ctx);
|
|
36220
37174
|
const fresh = historianRunConfig(current.config, liveReaderFor(current.projectDir, current.config).poll().effective);
|
|
36221
|
-
const historian = resolveHistorianFromConfig(fresh
|
|
37175
|
+
const historian = resolveHistorianFromConfig(fresh, PI_HARNESS_KIND, activeModelRegistry);
|
|
36222
37176
|
return {
|
|
36223
37177
|
db,
|
|
36224
37178
|
runner: recompRunner,
|
|
@@ -36253,7 +37207,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36253
37207
|
resolveRuntimeDeps: (ctx) => {
|
|
36254
37208
|
const current = resolveCurrentProjectDeps(ctx);
|
|
36255
37209
|
const fresh = historianRunConfig(current.config, liveReaderFor(current.projectDir, current.config).poll().effective);
|
|
36256
|
-
const historian = resolveHistorianFromConfig(fresh
|
|
37210
|
+
const historian = resolveHistorianFromConfig(fresh, PI_HARNESS_KIND, activeModelRegistry);
|
|
36257
37211
|
return {
|
|
36258
37212
|
db,
|
|
36259
37213
|
runner: wrapupRunner,
|
|
@@ -36287,7 +37241,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36287
37241
|
dreamerEnabled: bootProjectDeps.dreamerEnabled,
|
|
36288
37242
|
resolveDreamerEnabled: (ctx) => resolveCurrentProjectDeps(ctx).dreamerEnabled,
|
|
36289
37243
|
onProjectSeen: (identity) => seenDreamerProjectIdentities.add(identity),
|
|
36290
|
-
ensureRegistered: (ctx) => syncDreamerProjectRegistration(resolveCurrentProjectDeps(ctx)),
|
|
37244
|
+
ensureRegistered: (ctx) => syncDreamerProjectRegistration(resolveCurrentProjectDeps(ctx), ctx.modelRegistry),
|
|
36291
37245
|
registrationOwner: dreamerRegistrationOwner
|
|
36292
37246
|
});
|
|
36293
37247
|
info("registered /ctx-dream");
|
|
@@ -36295,8 +37249,6 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36295
37249
|
db,
|
|
36296
37250
|
projectDir,
|
|
36297
37251
|
projectIdentity,
|
|
36298
|
-
memoryEnabled: bootProjectDeps.config.memory.enabled,
|
|
36299
|
-
resolveMemoryEnabled: (ctx) => resolveCurrentProjectDeps(ctx).config.memory.enabled,
|
|
36300
37252
|
resolveProject: (ctx) => {
|
|
36301
37253
|
const current = resolveCurrentProjectDeps(ctx);
|
|
36302
37254
|
return {
|
|
@@ -36340,7 +37292,8 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36340
37292
|
};
|
|
36341
37293
|
const effectiveConfig = effectiveProjectDeps.config;
|
|
36342
37294
|
try {
|
|
36343
|
-
|
|
37295
|
+
activeModelRegistry = ctx.modelRegistry;
|
|
37296
|
+
syncDreamerProjectRegistration(effectiveProjectDeps, ctx.modelRegistry);
|
|
36344
37297
|
} catch (err) {
|
|
36345
37298
|
warn("before_agent_start: dreamer registration sync threw:", err);
|
|
36346
37299
|
}
|
|
@@ -36540,6 +37493,14 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36540
37493
|
piContextWindowSource: "catalog",
|
|
36541
37494
|
piModel: ctx.model,
|
|
36542
37495
|
piTokens: piUsage && typeof piUsage.tokens === "number" ? piUsage.tokens : undefined,
|
|
37496
|
+
piTokensIsRawBranchEstimate: (() => {
|
|
37497
|
+
try {
|
|
37498
|
+
const branch = ctx.sessionManager.getBranch?.();
|
|
37499
|
+
return isPiLiveUsageRawBranchEstimate(branch);
|
|
37500
|
+
} catch {
|
|
37501
|
+
return false;
|
|
37502
|
+
}
|
|
37503
|
+
})(),
|
|
36543
37504
|
notifyIssue: async (message) => {
|
|
36544
37505
|
const uiNotify = ctx.ui?.notify;
|
|
36545
37506
|
if (typeof uiNotify === "function") {
|
|
@@ -36663,6 +37624,7 @@ export {
|
|
|
36663
37624
|
handlePiSessionBeforeCompact,
|
|
36664
37625
|
persistPiMessageEndModelMeta,
|
|
36665
37626
|
persistPiPressureFromMessageEnd,
|
|
37627
|
+
registerConfiguredTodoLifecycle,
|
|
36666
37628
|
resetClaimedProtectedTagsDeprecationNoticeForTesting,
|
|
36667
37629
|
resolveDreamerFromConfig,
|
|
36668
37630
|
resolveHistorianFromConfig,
|