@cortexkit/pi-magic-context 0.43.1 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-822b3fcs.js → index-2kj55q4e.js} +155 -28
- package/dist/{index-kyrajahw.js → index-8ytss1hp.js} +308 -190
- package/dist/{index-5v60m046.js → index-jscq7067.js} +1 -1
- package/dist/{index-17102c1m.js → index-mmkdxa5j.js} +1 -1
- package/dist/{index-bfd52y8p.js → index-tfzybajk.js} +22 -6
- package/dist/index.js +1202 -367
- package/dist/{message-time-backfill-f0v3yvza.js → message-time-backfill-3rp0w2z9.js} +3 -3
- package/dist/{read-session-chunk-4s09z8f5.js → read-session-chunk-2s116ah5.js} +6 -2
- package/dist/{safe-notification-target-d7f3t5qk.js → safe-notification-target-pd09ybr0.js} +2 -2
- package/dist/subagent-entry.js +4 -4
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
log,
|
|
10
10
|
sessionLog,
|
|
11
11
|
flushLogger
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-tfzybajk.js";
|
|
13
13
|
import {
|
|
14
14
|
COMPACTION_ENABLED_PATH,
|
|
15
15
|
isDreamerRunnable,
|
|
@@ -100,7 +100,9 @@ import {
|
|
|
100
100
|
escapeXmlContent,
|
|
101
101
|
getModuleNoteEvaluationBridge,
|
|
102
102
|
getContextStoreUuid,
|
|
103
|
+
getAuthorityManagedMarker,
|
|
103
104
|
drainMirrorPages,
|
|
105
|
+
V2_MEMORY_CATEGORIES,
|
|
104
106
|
parseCompartmentOutput,
|
|
105
107
|
resolveWorkspaceShareCategories,
|
|
106
108
|
resolveWorkspaceIdentitySet,
|
|
@@ -172,8 +174,8 @@ import {
|
|
|
172
174
|
clearDetectedContextLimit,
|
|
173
175
|
getStrippedPlaceholderIds,
|
|
174
176
|
applyStrippedPlaceholderDelta,
|
|
175
|
-
NEWEST_REASONING_BEARING_ASSISTANT,
|
|
176
177
|
THINKING_BINDING_RECOVERY_FROZEN_PREFIX,
|
|
178
|
+
THINKING_BINDING_STRIP_ORDER_END_MARKER,
|
|
177
179
|
thinkingBindingRecoveryFrozenId,
|
|
178
180
|
getThinkingBindingRecoveryTarget,
|
|
179
181
|
armThinkingBindingRecovery,
|
|
@@ -402,7 +404,7 @@ import {
|
|
|
402
404
|
registerTodoStateLifecycle,
|
|
403
405
|
syncCtxMemoryToolEnabled,
|
|
404
406
|
registerMagicContextTools
|
|
405
|
-
} from "./index-
|
|
407
|
+
} from "./index-8ytss1hp.js";
|
|
406
408
|
import {
|
|
407
409
|
CTX_REDUCE_KEEP,
|
|
408
410
|
newestCtxReduceTagNumbers,
|
|
@@ -497,6 +499,8 @@ import {
|
|
|
497
499
|
localBudget,
|
|
498
500
|
calibrationForModelKey,
|
|
499
501
|
historyLocalBudget,
|
|
502
|
+
SKELETON_REAL_INPUT_MAX_BYTES,
|
|
503
|
+
toolInputStringBytes,
|
|
500
504
|
setRawMessageProvider2,
|
|
501
505
|
withRawMessageProvider2,
|
|
502
506
|
cleanUserText2,
|
|
@@ -512,14 +516,14 @@ import {
|
|
|
512
516
|
getRawSessionTagKeysThrough2,
|
|
513
517
|
getLegacyProtectedTailStartOrdinal2,
|
|
514
518
|
readSessionChunk2
|
|
515
|
-
} from "./index-
|
|
519
|
+
} from "./index-2kj55q4e.js";
|
|
516
520
|
import {
|
|
517
521
|
pushNotification2
|
|
518
522
|
} from "./index-b3eqj1g6.js";
|
|
519
|
-
import"./index-
|
|
523
|
+
import"./index-jscq7067.js";
|
|
520
524
|
import {
|
|
521
525
|
logSlowWriteTransaction
|
|
522
|
-
} from "./index-
|
|
526
|
+
} from "./index-mmkdxa5j.js";
|
|
523
527
|
import {
|
|
524
528
|
__toESM
|
|
525
529
|
} from "./index-22jkk6wg.js";
|
|
@@ -527,7 +531,7 @@ import {
|
|
|
527
531
|
// src/index.ts
|
|
528
532
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
529
533
|
import { createRequire as createRequire2 } from "node:module";
|
|
530
|
-
import { join as join8, resolve as
|
|
534
|
+
import { join as join8, resolve as resolve4 } from "node:path";
|
|
531
535
|
|
|
532
536
|
// ../plugin/src/config/live-snapshot.ts
|
|
533
537
|
import { createHash } from "node:crypto";
|
|
@@ -1141,7 +1145,9 @@ var OVERFLOW_PATTERNS = [
|
|
|
1141
1145
|
/prompt too long; exceeded (?:max )?context length/i,
|
|
1142
1146
|
/too large for model with \d+ maximum context length/i,
|
|
1143
1147
|
/model_context_window_exceeded/i,
|
|
1144
|
-
/context size has been exceeded/i
|
|
1148
|
+
/context size has been exceeded/i,
|
|
1149
|
+
/prepared prompt exceeds engine max_context/i,
|
|
1150
|
+
/prompt exceeds (?:the )?.{0,32}\bmax_context\b/i
|
|
1145
1151
|
];
|
|
1146
1152
|
var LIMIT_EXTRACTION_PATTERNS = [
|
|
1147
1153
|
{ pattern: /maximum prompt length is (\d+)/i, provenance: "prompt_only" },
|
|
@@ -1162,11 +1168,15 @@ var LIMIT_EXTRACTION_PATTERNS = [
|
|
|
1162
1168
|
pattern: />\s*(\d+)\s*(?:tokens?\s*)?(?:maximum|max|limit)\b/i,
|
|
1163
1169
|
provenance: "prompt_only"
|
|
1164
1170
|
},
|
|
1171
|
+
{ pattern: /prepared prompt exceeds engine max_context\s+(\d+)/i, provenance: "unknown" },
|
|
1172
|
+
{ pattern: /prompt exceeds (?:the )?.{0,32}\bmax_context\s+(\d+)/i, provenance: "unknown" },
|
|
1165
1173
|
{ pattern: /max(?:imum)?.*context.*?(\d+)/i, provenance: "unknown" }
|
|
1166
1174
|
];
|
|
1167
1175
|
var MIN_PLAUSIBLE_LIMIT = 1024;
|
|
1168
1176
|
var MAX_PLAUSIBLE_LIMIT = 1e7;
|
|
1169
1177
|
var THINKING_BINDING_MISMATCH_PATTERN = /bound to a different conversation/i;
|
|
1178
|
+
var THINKING_BINDING_FAILING_PATH_PATTERN = /^\s*(messages\.\d+\.content\.\d+):/;
|
|
1179
|
+
var THINKING_BINDING_FIRST_CHANGED_PATTERN = /first at `?(messages\.\d+\.content\.\d+)`?/;
|
|
1170
1180
|
function extractErrorMessage(error) {
|
|
1171
1181
|
if (!error)
|
|
1172
1182
|
return "";
|
|
@@ -1195,29 +1205,6 @@ function extractErrorMessage(error) {
|
|
|
1195
1205
|
}
|
|
1196
1206
|
return String(error);
|
|
1197
1207
|
}
|
|
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
1208
|
function extractExplicitHttpStatus(error) {
|
|
1222
1209
|
if (!error || typeof error !== "object")
|
|
1223
1210
|
return;
|
|
@@ -1247,13 +1234,20 @@ function detectThinkingBindingMismatch(error) {
|
|
|
1247
1234
|
if (explicitStatus !== undefined && explicitStatus !== 400 || !THINKING_BINDING_MISMATCH_PATTERN.test(message)) {
|
|
1248
1235
|
return { isBindingMismatch: false };
|
|
1249
1236
|
}
|
|
1250
|
-
const
|
|
1237
|
+
const failingBlockPath = THINKING_BINDING_FAILING_PATH_PATTERN.exec(message)?.[1];
|
|
1238
|
+
const firstChangedPath = THINKING_BINDING_FIRST_CHANGED_PATTERN.exec(message)?.[1];
|
|
1251
1239
|
return {
|
|
1252
1240
|
isBindingMismatch: true,
|
|
1253
1241
|
matchedPattern: "bound to a different conversation",
|
|
1254
|
-
...
|
|
1242
|
+
...failingBlockPath ? { failingBlockPath } : {},
|
|
1243
|
+
...firstChangedPath ? { firstChangedPath } : {}
|
|
1255
1244
|
};
|
|
1256
1245
|
}
|
|
1246
|
+
function isPrefixBoundThinkingModel(providerID, modelID) {
|
|
1247
|
+
if (providerID?.toLowerCase() !== "anthropic" || !modelID)
|
|
1248
|
+
return false;
|
|
1249
|
+
return isFable51ThinkingBindingModel(providerID, modelID) || /(?:^|[-_.])opus[-_.]?5[-_.]5(?:$|[-_.])/i.test(modelID);
|
|
1250
|
+
}
|
|
1257
1251
|
function isFable51ThinkingBindingModel(providerID, modelID) {
|
|
1258
1252
|
if (providerID?.toLowerCase() !== "anthropic" || !modelID)
|
|
1259
1253
|
return false;
|
|
@@ -1586,6 +1580,31 @@ async function runSessionProjectBackfill(db, source, options = {}) {
|
|
|
1586
1580
|
return result;
|
|
1587
1581
|
}
|
|
1588
1582
|
|
|
1583
|
+
// ../plugin/src/features/magic-context/storage-unavailable-reason.ts
|
|
1584
|
+
function describeStorageUnavailability(fallbackCause) {
|
|
1585
|
+
const migration = getMigrationOnOpenRefusal();
|
|
1586
|
+
const blockingProcesses = migration?.blockingProcesses ?? migration?.serverPids.map((pid) => ({ kind: "process", pid })) ?? [];
|
|
1587
|
+
if (migration && (blockingProcesses.length > 0 || migration.unreadableFile)) {
|
|
1588
|
+
return {
|
|
1589
|
+
kind: "migration_guard",
|
|
1590
|
+
persistedVersion: migration.persistedVersion,
|
|
1591
|
+
supportedVersion: migration.supportedVersion,
|
|
1592
|
+
blockingProcesses,
|
|
1593
|
+
...migration.unreadableFile ? { unreadableFile: migration.unreadableFile } : {},
|
|
1594
|
+
...migration.unreadableArm ? { unreadableArm: migration.unreadableArm } : {}
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
const fence = getSchemaFenceRejection();
|
|
1598
|
+
if (fence) {
|
|
1599
|
+
return {
|
|
1600
|
+
kind: "schema_fence",
|
|
1601
|
+
persistedVersion: fence.persistedVersion,
|
|
1602
|
+
supportedVersion: fence.supportedVersion
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
return { kind: "storage_failure", cause: fallbackCause };
|
|
1606
|
+
}
|
|
1607
|
+
|
|
1589
1608
|
// ../plugin/src/features/magic-context/v22-deferred-backfill.ts
|
|
1590
1609
|
import { createHash as createHash2 } from "node:crypto";
|
|
1591
1610
|
import { realpathSync } from "node:fs";
|
|
@@ -1824,6 +1843,8 @@ function setCtxReduceRegisteredGlobally(registered) {
|
|
|
1824
1843
|
var availabilityBySession = new BoundedSessionMap(1000);
|
|
1825
1844
|
var permissionDeniedBySession = new BoundedSessionMap(2000);
|
|
1826
1845
|
var ctxReducePermissionDenyLogged = new BoundedSessionMap(1000);
|
|
1846
|
+
var ctxReduceSpawnPermissionDenied = new BoundedSessionMap(1000);
|
|
1847
|
+
var ctxReduceSpawnPermissionReads = new Map;
|
|
1827
1848
|
|
|
1828
1849
|
// ../plugin/src/hooks/magic-context/derive-budgets.ts
|
|
1829
1850
|
var TRIGGER_BUDGET_PERCENTAGE = 0.05;
|
|
@@ -2780,6 +2801,11 @@ var USER_FACING_FAILURES = {
|
|
|
2780
2801
|
sentence: "Some finished background sessions could not be removed from this host.",
|
|
2781
2802
|
action: "They are removed automatically the next time Magic Context runs inside a registered OpenCode service."
|
|
2782
2803
|
},
|
|
2804
|
+
historian_saved_history_misaligned: {
|
|
2805
|
+
code: "MC-H03",
|
|
2806
|
+
sentence: "History compression is paused because this session's saved summaries no longer line up with its messages.",
|
|
2807
|
+
action: "Run /ctx-recomp to rebuild them."
|
|
2808
|
+
},
|
|
2783
2809
|
recomp_unavailable: {
|
|
2784
2810
|
code: "MC-R01",
|
|
2785
2811
|
sentence: "History compression could not be rebuilt.",
|
|
@@ -2795,6 +2821,11 @@ var USER_FACING_FAILURES = {
|
|
|
2795
2821
|
sentence: "Memory maintenance could not reach its model.",
|
|
2796
2822
|
action: "Check the model connection, then run /ctx-dream again."
|
|
2797
2823
|
},
|
|
2824
|
+
dream_step_limit: {
|
|
2825
|
+
code: "MC-D10",
|
|
2826
|
+
sentence: "Memory maintenance stopped at its hidden agent step limit.",
|
|
2827
|
+
action: "This task needs less work per run; changing the model connection will not help."
|
|
2828
|
+
},
|
|
2798
2829
|
dream_empty_completion: {
|
|
2799
2830
|
code: "MC-D03",
|
|
2800
2831
|
sentence: "Memory maintenance received no usable response.",
|
|
@@ -2950,11 +2981,21 @@ var USER_FACING_FAILURES = {
|
|
|
2950
2981
|
sentence: "History compression is paused while the engine syncs.",
|
|
2951
2982
|
action: "Retry in a moment."
|
|
2952
2983
|
},
|
|
2984
|
+
history_compression_needs_message: {
|
|
2985
|
+
code: "MC-C12",
|
|
2986
|
+
sentence: "History compression has not seen this session since Magic Context reconnected.",
|
|
2987
|
+
action: "Send a message in this session first, then run /ctx-wrapup again."
|
|
2988
|
+
},
|
|
2953
2989
|
context_service_unavailable: {
|
|
2954
2990
|
code: "MC-C10",
|
|
2955
2991
|
sentence: "Magic Context is temporarily unavailable.",
|
|
2956
2992
|
action: "Retry in a moment."
|
|
2957
2993
|
},
|
|
2994
|
+
store_ahead_of_binary: {
|
|
2995
|
+
code: "MC-C13",
|
|
2996
|
+
sentence: "Magic Context refused to start: its store (store.db) was migrated by a newer ck-mc build than the one running.",
|
|
2997
|
+
action: "Update ck-mc, or roll back by restoring ck-mc together with context.db and store.db from the same backup."
|
|
2998
|
+
},
|
|
2958
2999
|
compaction_marker_missing: {
|
|
2959
3000
|
code: "MC-C11",
|
|
2960
3001
|
sentence: "The history boundary marker is missing from the OpenCode store, so requests carry the full session.",
|
|
@@ -2970,11 +3011,6 @@ var USER_FACING_FAILURES = {
|
|
|
2970
3011
|
sentence: "Memory authority is inconsistent between the host and module.",
|
|
2971
3012
|
action: "Run `ck doctor drain-authority` before changing Rust mode."
|
|
2972
3013
|
},
|
|
2973
|
-
rust_mode_unsupported: {
|
|
2974
|
-
code: "MC-S06",
|
|
2975
|
-
sentence: "Experimental Rust transform mode is not available on this OpenCode host.",
|
|
2976
|
-
action: 'Magic Context is running its TypeScript mode instead; set `transform_mode` to "ts" to stop requesting Rust.'
|
|
2977
|
-
},
|
|
2978
3014
|
dreamer_task_failing: {
|
|
2979
3015
|
code: "MC-S05",
|
|
2980
3016
|
sentence: "A background maintenance task keeps failing on its schedule.",
|
|
@@ -3006,6 +3042,7 @@ function renderCapabilityRefusal(capability) {
|
|
|
3006
3042
|
var DREAM_FAILURE_KEYS = {
|
|
3007
3043
|
provider_timeout: "dream_provider_timeout",
|
|
3008
3044
|
provider_error: "dream_provider_error",
|
|
3045
|
+
step_limit: "dream_step_limit",
|
|
3009
3046
|
empty_completion: "dream_empty_completion",
|
|
3010
3047
|
no_models: "dream_no_models",
|
|
3011
3048
|
child_aborted: "dream_child_aborted",
|
|
@@ -3035,6 +3072,10 @@ function renderEmbeddingFailure(failureClass, style = "markdown") {
|
|
|
3035
3072
|
return renderUserFacingFailure(EMBEDDING_FAILURE_KEYS[failureClass], style);
|
|
3036
3073
|
}
|
|
3037
3074
|
|
|
3075
|
+
// src/dreamer/index.ts
|
|
3076
|
+
import { homedir as homedir2 } from "node:os";
|
|
3077
|
+
import { parse, resolve as resolve3 } from "node:path";
|
|
3078
|
+
|
|
3038
3079
|
// ../plugin/src/features/magic-context/dreamer/open-opencode-db.ts
|
|
3039
3080
|
function openOpenCodeDb() {
|
|
3040
3081
|
const resolution = resolveOpenCodeDbPath();
|
|
@@ -3192,6 +3233,37 @@ class HiddenCompletionRefusal extends Error {
|
|
|
3192
3233
|
this.name = "HiddenCompletionRefusal";
|
|
3193
3234
|
}
|
|
3194
3235
|
}
|
|
3236
|
+
// ../plugin/src/v2/hooks/hidden-child.ts
|
|
3237
|
+
var HIDDEN_HISTORIAN_AGENT = "historian";
|
|
3238
|
+
var HIDDEN_DREAMER_AGENT = "dreamer-classifier";
|
|
3239
|
+
var HIDDEN_CURATE_AGENT = DREAMER_AGENT;
|
|
3240
|
+
var READ_TOOLS = ["read", "grep", "glob"];
|
|
3241
|
+
var AGENT_TOOLS = {
|
|
3242
|
+
[HIDDEN_HISTORIAN_AGENT]: [],
|
|
3243
|
+
[HIDDEN_DREAMER_AGENT]: [],
|
|
3244
|
+
[HIDDEN_CURATE_AGENT]: ["ctx_memory", "ctx_memory_list"],
|
|
3245
|
+
[DREAMER_MEMORY_MAPPER_AGENT]: READ_TOOLS,
|
|
3246
|
+
[DREAMER_PRIMER_INVESTIGATOR_AGENT]: [...READ_TOOLS, "ctx_search"],
|
|
3247
|
+
[DREAMER_RETROSPECTIVE_AGENT]: ["ctx_search"]
|
|
3248
|
+
};
|
|
3249
|
+
var AGENT_STEPS = {
|
|
3250
|
+
[HIDDEN_CURATE_AGENT]: 150,
|
|
3251
|
+
[DREAMER_MEMORY_MAPPER_AGENT]: 60,
|
|
3252
|
+
[DREAMER_DOCS_AGENT]: 60,
|
|
3253
|
+
[DREAMER_PRIMER_INVESTIGATOR_AGENT]: 40,
|
|
3254
|
+
[DREAMER_RETROSPECTIVE_AGENT]: 40
|
|
3255
|
+
};
|
|
3256
|
+
class HiddenAgentStepLimit extends Error {
|
|
3257
|
+
agent;
|
|
3258
|
+
cap;
|
|
3259
|
+
constructor(agent, cap) {
|
|
3260
|
+
super(`Hidden agent ${agent} exceeded its ${cap}-step limit`);
|
|
3261
|
+
this.name = "HiddenAgentStepLimit";
|
|
3262
|
+
this.agent = agent;
|
|
3263
|
+
this.cap = cap;
|
|
3264
|
+
}
|
|
3265
|
+
}
|
|
3266
|
+
|
|
3195
3267
|
// ../plugin/src/shared/assistant-message-extractor.ts
|
|
3196
3268
|
function asSessionMessage(value) {
|
|
3197
3269
|
if (!isRecord(value))
|
|
@@ -3290,6 +3362,14 @@ function copyPromptArgs(args, body) {
|
|
|
3290
3362
|
return { ...args, body: { ...body } };
|
|
3291
3363
|
}
|
|
3292
3364
|
var promptFailureDetails = new WeakMap;
|
|
3365
|
+
function isHostTimeoutError(error) {
|
|
3366
|
+
return error !== null && typeof error === "object" && error.name === "TimeoutError";
|
|
3367
|
+
}
|
|
3368
|
+
function isPromptTimeoutError(error) {
|
|
3369
|
+
if (isHostTimeoutError(error))
|
|
3370
|
+
return true;
|
|
3371
|
+
return error instanceof Error && /^prompt timed out after \d+ms$/.test(error.message);
|
|
3372
|
+
}
|
|
3293
3373
|
function getPromptFailureDetail(error) {
|
|
3294
3374
|
return error !== null && typeof error === "object" ? promptFailureDetails.get(error) ?? null : null;
|
|
3295
3375
|
}
|
|
@@ -3346,9 +3426,13 @@ function parseModelSuggestion(error) {
|
|
|
3346
3426
|
suggestion: suggestionMatch[1].trim()
|
|
3347
3427
|
};
|
|
3348
3428
|
}
|
|
3429
|
+
function externalAbortMessage(signal) {
|
|
3430
|
+
const reason = signal.reason;
|
|
3431
|
+
return `prompt aborted by external signal${reason instanceof Error && /^lease_(?:lost|expired):/.test(reason.message) ? `: ${reason.message}` : ""}`;
|
|
3432
|
+
}
|
|
3349
3433
|
async function promptWithTimeout(client, args, timeoutMs, signal, transport) {
|
|
3350
3434
|
if (signal?.aborted) {
|
|
3351
|
-
throw new Error(
|
|
3435
|
+
throw new Error(externalAbortMessage(signal));
|
|
3352
3436
|
}
|
|
3353
3437
|
const controller = new AbortController;
|
|
3354
3438
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -3368,7 +3452,7 @@ async function promptWithTimeout(client, args, timeoutMs, signal, transport) {
|
|
|
3368
3452
|
if (!transport || transport.childSessionId) {
|
|
3369
3453
|
await abortChildRun(client, transport?.childSessionId ?? args.path.id);
|
|
3370
3454
|
}
|
|
3371
|
-
throw new Error(
|
|
3455
|
+
throw new Error(externalAbortMessage(signal));
|
|
3372
3456
|
}
|
|
3373
3457
|
if (controller.signal.aborted) {
|
|
3374
3458
|
if (!transport || transport.childSessionId) {
|
|
@@ -3376,6 +3460,11 @@ async function promptWithTimeout(client, args, timeoutMs, signal, transport) {
|
|
|
3376
3460
|
}
|
|
3377
3461
|
throw new Error(`prompt timed out after ${timeoutMs}ms`);
|
|
3378
3462
|
}
|
|
3463
|
+
if (isHostTimeoutError(error)) {
|
|
3464
|
+
if (!transport || transport.childSessionId) {
|
|
3465
|
+
await abortChildRun(client, transport?.childSessionId ?? args.path.id);
|
|
3466
|
+
}
|
|
3467
|
+
}
|
|
3379
3468
|
throw error;
|
|
3380
3469
|
} finally {
|
|
3381
3470
|
clearTimeout(timeout);
|
|
@@ -3385,7 +3474,7 @@ async function promptWithTimeout(client, args, timeoutMs, signal, transport) {
|
|
|
3385
3474
|
if (!transport || transport.childSessionId) {
|
|
3386
3475
|
await abortChildRun(client, transport?.childSessionId ?? args.path.id);
|
|
3387
3476
|
}
|
|
3388
|
-
throw new Error(signal?.aborted ?
|
|
3477
|
+
throw new Error(signal?.aborted ? externalAbortMessage(signal) : `prompt timed out after ${timeoutMs}ms`);
|
|
3389
3478
|
}
|
|
3390
3479
|
}
|
|
3391
3480
|
async function abortChildRun(client, sessionId) {
|
|
@@ -3401,7 +3490,7 @@ async function abortChildRun(client, sessionId) {
|
|
|
3401
3490
|
}
|
|
3402
3491
|
}
|
|
3403
3492
|
function isNonRetryable(error, externalSignal) {
|
|
3404
|
-
if (externalSignal?.aborted)
|
|
3493
|
+
if (externalSignal?.aborted || error instanceof HiddenAgentStepLimit)
|
|
3405
3494
|
return true;
|
|
3406
3495
|
if (error instanceof Error) {
|
|
3407
3496
|
if (error.name === "AbortError")
|
|
@@ -3411,6 +3500,8 @@ function isNonRetryable(error, externalSignal) {
|
|
|
3411
3500
|
if (/^prompt timed out after \d+ms$/.test(error.message))
|
|
3412
3501
|
return true;
|
|
3413
3502
|
}
|
|
3503
|
+
if (isHostTimeoutError(error))
|
|
3504
|
+
return true;
|
|
3414
3505
|
if (detectOverflow(error).isOverflow)
|
|
3415
3506
|
return true;
|
|
3416
3507
|
return false;
|
|
@@ -3423,11 +3514,14 @@ function shortErr(error) {
|
|
|
3423
3514
|
}
|
|
3424
3515
|
function classifyPromptFailure(error, phase, externalSignal) {
|
|
3425
3516
|
const message = extractMessage(error);
|
|
3517
|
+
if (error instanceof HiddenAgentStepLimit)
|
|
3518
|
+
return "step_limit";
|
|
3426
3519
|
if (externalSignal?.aborted || message === "prompt aborted by external signal") {
|
|
3427
3520
|
return "child_aborted";
|
|
3428
3521
|
}
|
|
3429
|
-
if (/^prompt timed out after \d+ms$/.test(message))
|
|
3522
|
+
if (/^prompt timed out after \d+ms$/.test(message) || isHostTimeoutError(error)) {
|
|
3430
3523
|
return "provider_timeout";
|
|
3524
|
+
}
|
|
3431
3525
|
if (phase === "validation") {
|
|
3432
3526
|
if (/returned no (?:assistant )?output|no assistant output/i.test(message)) {
|
|
3433
3527
|
return "empty_completion";
|
|
@@ -3644,7 +3738,10 @@ async function promptSyncWithValidatedOutputRetry(client, args, options) {
|
|
|
3644
3738
|
}
|
|
3645
3739
|
}
|
|
3646
3740
|
log(`[${callContext}] all models exhausted; tried: ${failedAttempts.map((failure) => failure.attempt.label).join(", ")}; original error: ${shortErr(firstError)}; last error: ${shortErr(lastError)}`);
|
|
3647
|
-
|
|
3741
|
+
const cause = lastError ?? firstError;
|
|
3742
|
+
const exhausted = cause instanceof Error ? cause : new Error(String(cause ?? "All fallback models failed validation"));
|
|
3743
|
+
exhausted.message = `All models exhausted (${failedAttempts.map((failure) => failure.attempt.label).join(", ")}): ${exhausted.message}`;
|
|
3744
|
+
throwWithPromptFailure(exhausted, failedAttempts, args, timeoutMs, options.transport);
|
|
3648
3745
|
}
|
|
3649
3746
|
// ../plugin/src/shared/normalize-sdk-response.ts
|
|
3650
3747
|
function normalizeSDKResponse(response, fallback, options) {
|
|
@@ -3669,6 +3766,149 @@ function normalizeSDKResponse(response, fallback, options) {
|
|
|
3669
3766
|
}
|
|
3670
3767
|
return fallback;
|
|
3671
3768
|
}
|
|
3769
|
+
// ../plugin/src/shared/prompt-async-transport.ts
|
|
3770
|
+
var DEFAULT_POLL_INTERVAL_MS = 1000;
|
|
3771
|
+
var DEFAULT_START_GRACE_MS = 30000;
|
|
3772
|
+
var MESSAGE_WINDOW = 20;
|
|
3773
|
+
function sessionApi(client) {
|
|
3774
|
+
return client?.session;
|
|
3775
|
+
}
|
|
3776
|
+
function supportsPromptAsync(client) {
|
|
3777
|
+
const session = sessionApi(client);
|
|
3778
|
+
return typeof session?.promptAsync === "function" && typeof session?.status === "function" && typeof session?.messages === "function";
|
|
3779
|
+
}
|
|
3780
|
+
function createPromptAsyncTransport(client, childSessionId, options = {}) {
|
|
3781
|
+
if (!supportsPromptAsync(client))
|
|
3782
|
+
return;
|
|
3783
|
+
return Object.assign((request) => promptAsyncAndWaitForIdle(client, request, options), { childSessionId });
|
|
3784
|
+
}
|
|
3785
|
+
function infoOf(message) {
|
|
3786
|
+
const info = message?.info;
|
|
3787
|
+
return info && typeof info === "object" ? info : {};
|
|
3788
|
+
}
|
|
3789
|
+
function messageId(message) {
|
|
3790
|
+
const id = infoOf(message).id;
|
|
3791
|
+
return typeof id === "string" ? id : null;
|
|
3792
|
+
}
|
|
3793
|
+
function isSettledAssistant(message) {
|
|
3794
|
+
const info = infoOf(message);
|
|
3795
|
+
if (info.role !== "assistant")
|
|
3796
|
+
return false;
|
|
3797
|
+
return info.time?.completed != null || info.error != null || info.finish != null;
|
|
3798
|
+
}
|
|
3799
|
+
function unwrapData(response) {
|
|
3800
|
+
if (response && typeof response === "object" && "data" in response) {
|
|
3801
|
+
return response.data;
|
|
3802
|
+
}
|
|
3803
|
+
return response;
|
|
3804
|
+
}
|
|
3805
|
+
function describeRejection(error) {
|
|
3806
|
+
if (error instanceof Error)
|
|
3807
|
+
return error.message;
|
|
3808
|
+
try {
|
|
3809
|
+
return JSON.stringify(error);
|
|
3810
|
+
} catch {
|
|
3811
|
+
return String(error);
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
function abortError(signal) {
|
|
3815
|
+
return signal.reason ?? new Error("prompt_async wait aborted");
|
|
3816
|
+
}
|
|
3817
|
+
function sleep(ms, signal) {
|
|
3818
|
+
return new Promise((resolve, reject) => {
|
|
3819
|
+
if (signal?.aborted) {
|
|
3820
|
+
reject(abortError(signal));
|
|
3821
|
+
return;
|
|
3822
|
+
}
|
|
3823
|
+
const onAbort = () => {
|
|
3824
|
+
clearTimeout(timer);
|
|
3825
|
+
reject(abortError(signal));
|
|
3826
|
+
};
|
|
3827
|
+
const timer = setTimeout(() => {
|
|
3828
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3829
|
+
resolve();
|
|
3830
|
+
}, ms);
|
|
3831
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
3832
|
+
});
|
|
3833
|
+
}
|
|
3834
|
+
async function readMessages(session, sessionId, directory, signal) {
|
|
3835
|
+
const response = await session.messages?.({
|
|
3836
|
+
path: { id: sessionId },
|
|
3837
|
+
query: { ...directory ? { directory } : {}, limit: MESSAGE_WINDOW },
|
|
3838
|
+
...signal ? { signal } : {}
|
|
3839
|
+
});
|
|
3840
|
+
const data = unwrapData(response);
|
|
3841
|
+
return Array.isArray(data) ? data : [];
|
|
3842
|
+
}
|
|
3843
|
+
async function readStatus(session, sessionId, directory, signal) {
|
|
3844
|
+
try {
|
|
3845
|
+
const response = await session.status?.({
|
|
3846
|
+
...directory ? { query: { directory } } : {},
|
|
3847
|
+
...signal ? { signal } : {}
|
|
3848
|
+
});
|
|
3849
|
+
if (response && typeof response === "object" && "error" in response) {
|
|
3850
|
+
if (response.error)
|
|
3851
|
+
return null;
|
|
3852
|
+
}
|
|
3853
|
+
const data = unwrapData(response);
|
|
3854
|
+
if (!data || typeof data !== "object")
|
|
3855
|
+
return null;
|
|
3856
|
+
const entry = data[sessionId];
|
|
3857
|
+
const type = entry?.type;
|
|
3858
|
+
return typeof type === "string" ? type : "idle";
|
|
3859
|
+
} catch (error) {
|
|
3860
|
+
if (signal?.aborted)
|
|
3861
|
+
throw error;
|
|
3862
|
+
return null;
|
|
3863
|
+
}
|
|
3864
|
+
}
|
|
3865
|
+
async function promptAsyncAndWaitForIdle(client, request, options = {}) {
|
|
3866
|
+
const session = sessionApi(client);
|
|
3867
|
+
if (!session || !supportsPromptAsync(client)) {
|
|
3868
|
+
throw new Error("prompt_async transport is unavailable on this client");
|
|
3869
|
+
}
|
|
3870
|
+
const sessionId = request.path.id;
|
|
3871
|
+
const directory = request.query?.directory;
|
|
3872
|
+
const dir = typeof directory === "string" ? directory : undefined;
|
|
3873
|
+
const signal = request.signal;
|
|
3874
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
3875
|
+
const startGraceMs = options.startGraceMs ?? DEFAULT_START_GRACE_MS;
|
|
3876
|
+
const baseline = new Set((await readMessages(session, sessionId, dir, signal)).map(messageId).filter((id) => id !== null));
|
|
3877
|
+
const sent = await session.promptAsync?.(request);
|
|
3878
|
+
if (sent && typeof sent === "object" && "error" in sent) {
|
|
3879
|
+
const rejection = sent.error;
|
|
3880
|
+
if (rejection)
|
|
3881
|
+
throw new Error(`prompt_async was rejected: ${describeRejection(rejection)}`);
|
|
3882
|
+
}
|
|
3883
|
+
const sentAt = Date.now();
|
|
3884
|
+
let sawBusy = false;
|
|
3885
|
+
for (;; ) {
|
|
3886
|
+
await sleep(pollIntervalMs, signal);
|
|
3887
|
+
const status = await readStatus(session, sessionId, dir, signal);
|
|
3888
|
+
if (status === "busy" || status === "retry") {
|
|
3889
|
+
sawBusy = true;
|
|
3890
|
+
continue;
|
|
3891
|
+
}
|
|
3892
|
+
if (status === null)
|
|
3893
|
+
continue;
|
|
3894
|
+
const messages = await readMessages(session, sessionId, dir, signal);
|
|
3895
|
+
const last = messages.at(-1);
|
|
3896
|
+
const lastId = messageId(last);
|
|
3897
|
+
if (last && lastId !== null && !baseline.has(lastId) && isSettledAssistant(last))
|
|
3898
|
+
return;
|
|
3899
|
+
const fresh = messages.some((message) => {
|
|
3900
|
+
const id = messageId(message);
|
|
3901
|
+
return id !== null && !baseline.has(id);
|
|
3902
|
+
});
|
|
3903
|
+
if (sawBusy && fresh)
|
|
3904
|
+
return;
|
|
3905
|
+
if (Date.now() - sentAt >= startGraceMs) {
|
|
3906
|
+
if (fresh)
|
|
3907
|
+
return;
|
|
3908
|
+
throw new Error(`prompt_async did not start a run in child session ${sessionId} within ${startGraceMs}ms`);
|
|
3909
|
+
}
|
|
3910
|
+
}
|
|
3911
|
+
}
|
|
3672
3912
|
// ../plugin/src/shared/summarize-child-stderr.ts
|
|
3673
3913
|
var MAX_CHILD_STDERR_SUMMARY_LENGTH = 500;
|
|
3674
3914
|
var CHILD_ERROR_LINE_PATTERN = /^(?:[A-Za-z]*Error|SqliteError|Error)\b[^\n]*/;
|
|
@@ -3808,6 +4048,9 @@ function failedInvocationStatus(error) {
|
|
|
3808
4048
|
const message = describeError(error).brief;
|
|
3809
4049
|
if (/timed out after \d+ms|prompt timed out/i.test(message))
|
|
3810
4050
|
return "timed_out";
|
|
4051
|
+
if (error !== null && typeof error === "object" && error.name === "TimeoutError") {
|
|
4052
|
+
return "timed_out";
|
|
4053
|
+
}
|
|
3811
4054
|
if (/length-capped|no (?:assistant )?output|empty (?:assistant )?(?:output|text)/i.test(message)) {
|
|
3812
4055
|
return "empty";
|
|
3813
4056
|
}
|
|
@@ -4869,7 +5112,7 @@ function shouldDiscardLastHistorianCompartment(compartments, chunk) {
|
|
|
4869
5112
|
function validateHistorianOutput(text, sessionId, chunk, _priorCompartments, sequenceOffset) {
|
|
4870
5113
|
const parseStarted = startHistorianPublishStage(sessionId, "parse", `response_chars=${text.length}`);
|
|
4871
5114
|
const parsed = parseCompartmentOutput(text);
|
|
4872
|
-
finishHistorianPublishStage(sessionId, "parse", parseStarted, "completed", `compartments=${parsed.compartments.length}`);
|
|
5115
|
+
finishHistorianPublishStage(sessionId, "parse", parseStarted, "completed", `compartments=${parsed.compartments.length} dropped_fact_blocks=${parsed.droppedFactBlocks} dropped_facts=${parsed.droppedFacts}`);
|
|
4873
5116
|
const validationStarted = startHistorianPublishStage(sessionId, "validate");
|
|
4874
5117
|
const finish = (result) => {
|
|
4875
5118
|
finishHistorianPublishStage(sessionId, "validate", validationStarted, result.ok ? "completed" : "failed", result.ok ? `compartments=${result.compartments.length}` : `reason=${JSON.stringify(result.error)}`);
|
|
@@ -4908,6 +5151,7 @@ function validateHistorianOutput(text, sessionId, chunk, _priorCompartments, seq
|
|
|
4908
5151
|
ok: true,
|
|
4909
5152
|
compartments: mapped.compartments,
|
|
4910
5153
|
facts: parsed.facts,
|
|
5154
|
+
...parsed.droppedFactBlocks > 0 ? { droppedFactBlocks: parsed.droppedFactBlocks, droppedFacts: parsed.droppedFacts } : {},
|
|
4911
5155
|
userObservations: parsed.userObservations.length > 0 ? parsed.userObservations : undefined,
|
|
4912
5156
|
primerCandidates: parsed.primerCandidates.length > 0 ? parsed.primerCandidates.slice(0, 1) : undefined,
|
|
4913
5157
|
events: parsed.events.length > 0 ? parsed.events : undefined
|
|
@@ -5160,6 +5404,7 @@ function resolveHiddenCompletionExecutor(executor, client, db, directory, entryP
|
|
|
5160
5404
|
return createV1HiddenCompletionExecutor(client, db, directory);
|
|
5161
5405
|
}
|
|
5162
5406
|
function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
5407
|
+
const asyncChildren = new Set;
|
|
5163
5408
|
return {
|
|
5164
5409
|
capabilities: { tools: true, harness: "opencode" },
|
|
5165
5410
|
async open(run) {
|
|
@@ -5176,11 +5421,17 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
|
5176
5421
|
preferResponseOnMissingData: true
|
|
5177
5422
|
});
|
|
5178
5423
|
const id = typeof created?.id === "string" ? created.id : "";
|
|
5424
|
+
if (id && run.kind === "dreamer-task")
|
|
5425
|
+
asyncChildren.add(id);
|
|
5179
5426
|
return { id, childSessionId: id || undefined };
|
|
5180
5427
|
},
|
|
5181
|
-
async attempt(
|
|
5428
|
+
async attempt(handle, request) {
|
|
5182
5429
|
if (!client)
|
|
5183
5430
|
throw new Error("Hidden completion client is unavailable");
|
|
5431
|
+
if (asyncChildren.has(handle.id) && supportsPromptAsync(client)) {
|
|
5432
|
+
await promptAsyncAndWaitForIdle(client, request);
|
|
5433
|
+
return;
|
|
5434
|
+
}
|
|
5184
5435
|
await client.session.prompt(request);
|
|
5185
5436
|
},
|
|
5186
5437
|
async collect(handle, limit) {
|
|
@@ -5208,6 +5459,8 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
|
5208
5459
|
};
|
|
5209
5460
|
},
|
|
5210
5461
|
async close(handle, settlement) {
|
|
5462
|
+
if (handle?.id)
|
|
5463
|
+
asyncChildren.delete(handle.id);
|
|
5211
5464
|
if (!client)
|
|
5212
5465
|
return;
|
|
5213
5466
|
await teardownChildSession({
|
|
@@ -5219,6 +5472,9 @@ function createV1HiddenCompletionExecutor(client, db, directory) {
|
|
|
5219
5472
|
}
|
|
5220
5473
|
};
|
|
5221
5474
|
}
|
|
5475
|
+
function historianReasoningBudgetDiagnostic(outputTokens) {
|
|
5476
|
+
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`;
|
|
5477
|
+
}
|
|
5222
5478
|
async function runValidatedHistorianPass(args) {
|
|
5223
5479
|
const firstRun = await runHistorianPrompt({
|
|
5224
5480
|
...args,
|
|
@@ -5445,14 +5701,14 @@ async function runHistorianPrompt(args) {
|
|
|
5445
5701
|
}
|
|
5446
5702
|
const backoffMs = getHistorianRetryBackoffMs(retryIndex);
|
|
5447
5703
|
sessionLog(parentSessionId, `historian retry ${retryIndex + 1}/${MAX_HISTORIAN_RETRIES} after ${backoffMs}ms: ${errorMsg}`);
|
|
5448
|
-
await
|
|
5704
|
+
await sleep2(backoffMs);
|
|
5449
5705
|
}
|
|
5450
5706
|
}
|
|
5451
5707
|
completion = await executor.collect(handle, 50);
|
|
5452
5708
|
const lengthCapped = completion.lengthCapped;
|
|
5453
5709
|
const textResult = completion.text;
|
|
5454
5710
|
const reasoningResult = textResult ? null : completion.reasoning;
|
|
5455
|
-
const emptyError = !textResult && reasoningResult && lengthCapped ?
|
|
5711
|
+
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;
|
|
5456
5712
|
const invocationId = recordInvocation({
|
|
5457
5713
|
status: emptyError ? "empty" : "completed",
|
|
5458
5714
|
messages: completion.messages,
|
|
@@ -5582,7 +5838,7 @@ function isTransientHistorianPromptError(message) {
|
|
|
5582
5838
|
"overloaded"
|
|
5583
5839
|
].some((token) => normalized.includes(token));
|
|
5584
5840
|
}
|
|
5585
|
-
function
|
|
5841
|
+
function sleep2(ms) {
|
|
5586
5842
|
return new Promise((resolve) => {
|
|
5587
5843
|
setTimeout(resolve, ms);
|
|
5588
5844
|
});
|
|
@@ -5779,13 +6035,25 @@ function runLeaseGuardedWrite(db, holderId, leaseKey, fn, slowWriteThresholdMs)
|
|
|
5779
6035
|
return fn();
|
|
5780
6036
|
}, `lease-guarded-write:${leaseKey}`, slowWriteThresholdMs);
|
|
5781
6037
|
}
|
|
5782
|
-
var LEASE_HEARTBEAT_INTERVAL_MS =
|
|
6038
|
+
var LEASE_HEARTBEAT_INTERVAL_MS = 40 * 1000;
|
|
6039
|
+
function reacquireOwnedLease(db, holderId, leaseKey, generation) {
|
|
6040
|
+
const keys = rowKeys(leaseKey);
|
|
6041
|
+
return runImmediate(db, () => {
|
|
6042
|
+
if (getLeaseHolder(db, leaseKey) !== holderId || getLeaseGeneration(db, leaseKey) !== generation) {
|
|
6043
|
+
return false;
|
|
6044
|
+
}
|
|
6045
|
+
const now = Date.now();
|
|
6046
|
+
setDreamState(db, keys.heartbeat, String(now));
|
|
6047
|
+
setDreamState(db, keys.expiry, String(now + LEASE_DURATION_MS));
|
|
6048
|
+
return true;
|
|
6049
|
+
});
|
|
6050
|
+
}
|
|
5783
6051
|
function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisition = LEASE_HEARTBEAT_INTERVAL_MS) {
|
|
5784
6052
|
const intervalMs = typeof intervalOrAcquisition === "number" ? intervalOrAcquisition : LEASE_HEARTBEAT_INTERVAL_MS;
|
|
5785
6053
|
const acquisition = typeof intervalOrAcquisition === "number" ? undefined : intervalOrAcquisition;
|
|
5786
6054
|
let lost = false;
|
|
5787
|
-
|
|
5788
|
-
let
|
|
6055
|
+
const expectedGeneration = acquisition?.generation ?? getLeaseGeneration(db, leaseKey);
|
|
6056
|
+
let renewalFailures = 0;
|
|
5789
6057
|
const declareLost = (reason) => {
|
|
5790
6058
|
if (lost)
|
|
5791
6059
|
return;
|
|
@@ -5797,32 +6065,20 @@ function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisiti
|
|
|
5797
6065
|
return;
|
|
5798
6066
|
try {
|
|
5799
6067
|
if (renewLease(db, holderId, leaseKey, expectedGeneration === null ? undefined : expectedGeneration)) {
|
|
5800
|
-
lastConfirmedAt = Date.now();
|
|
5801
6068
|
return;
|
|
5802
6069
|
}
|
|
5803
|
-
if (expectedGeneration !== null &&
|
|
5804
|
-
declareLost("lease generation changed — another holder acquired it");
|
|
5805
|
-
return;
|
|
5806
|
-
}
|
|
5807
|
-
if (Date.now() - lastConfirmedAt > LEASE_DURATION_MS) {
|
|
5808
|
-
declareLost("lease lapsed past TTL — another holder may have run");
|
|
5809
|
-
return;
|
|
5810
|
-
}
|
|
5811
|
-
const reacquired = acquireLeaseWithAcquisition(db, holderId, leaseKey);
|
|
5812
|
-
if (reacquired) {
|
|
5813
|
-
if (expectedGeneration !== null && reacquired.generation !== expectedGeneration) {
|
|
5814
|
-
declareLost("lease generation changed during reacquisition");
|
|
5815
|
-
return;
|
|
5816
|
-
}
|
|
5817
|
-
expectedGeneration = reacquired.generation;
|
|
5818
|
-
lastConfirmedAt = Date.now();
|
|
6070
|
+
if (expectedGeneration !== null && reacquireOwnedLease(db, holderId, leaseKey, expectedGeneration))
|
|
5819
6071
|
return;
|
|
6072
|
+
const holder = getLeaseHolder(db, leaseKey);
|
|
6073
|
+
if (holder !== null && holder !== holderId) {
|
|
6074
|
+
declareLost(`lease_lost: taken by ${holder}`);
|
|
6075
|
+
} else if (getLeaseGeneration(db, leaseKey) !== expectedGeneration) {
|
|
6076
|
+
declareLost("lease_lost: generation changed");
|
|
6077
|
+
} else {
|
|
6078
|
+
declareLost("lease_expired: reacquire failed (holder missing)");
|
|
5820
6079
|
}
|
|
5821
|
-
declareLost("lease acquired by another holder");
|
|
5822
6080
|
} catch {
|
|
5823
|
-
|
|
5824
|
-
declareLost("lease renewal unconfirmed past TTL");
|
|
5825
|
-
}
|
|
6081
|
+
renewalFailures += 1;
|
|
5826
6082
|
}
|
|
5827
6083
|
};
|
|
5828
6084
|
beat();
|
|
@@ -5834,6 +6090,9 @@ function startLeaseHeartbeat(db, holderId, leaseKey, onLost, intervalOrAcquisiti
|
|
|
5834
6090
|
},
|
|
5835
6091
|
get lost() {
|
|
5836
6092
|
return lost;
|
|
6093
|
+
},
|
|
6094
|
+
get renewalFailures() {
|
|
6095
|
+
return renewalFailures;
|
|
5837
6096
|
}
|
|
5838
6097
|
};
|
|
5839
6098
|
}
|
|
@@ -5911,6 +6170,14 @@ function assertParsedManifestNonEmpty(parsedCount, expectedCount, text, expected
|
|
|
5911
6170
|
}
|
|
5912
6171
|
|
|
5913
6172
|
// ../plugin/src/features/magic-context/dreamer/module-apply.ts
|
|
6173
|
+
var loggedNotOwnerProjects = new Set;
|
|
6174
|
+
function logDreamerNotOwnerOnce(projectIdentity) {
|
|
6175
|
+
if (loggedNotOwnerProjects.has(projectIdentity))
|
|
6176
|
+
return;
|
|
6177
|
+
loggedNotOwnerProjects.add(projectIdentity);
|
|
6178
|
+
log(`[dreamer] ${projectIdentity}: module-managed project; skipping TS writes without an owner route`);
|
|
6179
|
+
}
|
|
6180
|
+
|
|
5914
6181
|
class DreamerModuleBusyError extends Error {
|
|
5915
6182
|
state;
|
|
5916
6183
|
transient = true;
|
|
@@ -6535,7 +6802,7 @@ async function runHiddenSingleShotPrompt(args) {
|
|
|
6535
6802
|
fetchOutput: () => args.executor.collect(handle, 50),
|
|
6536
6803
|
validateOutput: (completion) => {
|
|
6537
6804
|
if (completion.lengthCapped) {
|
|
6538
|
-
throw new Error(`${args.callContext} returned length-capped output`);
|
|
6805
|
+
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`);
|
|
6539
6806
|
}
|
|
6540
6807
|
const text = completion.text;
|
|
6541
6808
|
if (!text && !args.allowEmpty)
|
|
@@ -7108,12 +7375,45 @@ function validateClassifyManifest(text, expectedIds) {
|
|
|
7108
7375
|
return parsed;
|
|
7109
7376
|
}
|
|
7110
7377
|
|
|
7378
|
+
// ../plugin/src/features/magic-context/dreamer/failed-invocation-evidence.ts
|
|
7379
|
+
var FAILED_CHILD_READ_TIMEOUT_MS = 5000;
|
|
7380
|
+
var FAILED_CHILD_MESSAGE_LIMIT = 200;
|
|
7381
|
+
async function readFailedChildMessages(client, sessionId, directory) {
|
|
7382
|
+
if (!client || !sessionId)
|
|
7383
|
+
return;
|
|
7384
|
+
let timer;
|
|
7385
|
+
try {
|
|
7386
|
+
const response = await Promise.race([
|
|
7387
|
+
client.session.messages({
|
|
7388
|
+
path: { id: sessionId },
|
|
7389
|
+
query: { directory, limit: FAILED_CHILD_MESSAGE_LIMIT }
|
|
7390
|
+
}),
|
|
7391
|
+
new Promise((resolve) => {
|
|
7392
|
+
timer = setTimeout(() => resolve(null), FAILED_CHILD_READ_TIMEOUT_MS);
|
|
7393
|
+
})
|
|
7394
|
+
]);
|
|
7395
|
+
if (response === null)
|
|
7396
|
+
return;
|
|
7397
|
+
const messages = normalizeSDKResponse(response, [], {
|
|
7398
|
+
preferResponseOnMissingData: true
|
|
7399
|
+
});
|
|
7400
|
+
return Array.isArray(messages) ? messages : undefined;
|
|
7401
|
+
} catch (error) {
|
|
7402
|
+
log(`[dreamer] failed-child evidence read failed for ${sessionId}: ${String(error)}`);
|
|
7403
|
+
return;
|
|
7404
|
+
} finally {
|
|
7405
|
+
if (timer)
|
|
7406
|
+
clearTimeout(timer);
|
|
7407
|
+
}
|
|
7408
|
+
}
|
|
7409
|
+
|
|
7111
7410
|
// ../plugin/src/features/magic-context/dreamer/classify.ts
|
|
7112
7411
|
var MIN_POOL_TO_CLASSIFY = 10;
|
|
7113
7412
|
var FULL_POOL_CEILING = 100;
|
|
7114
7413
|
var STAGE3_ANCHOR_COUNT = 30;
|
|
7115
7414
|
var CLASSIFY_CHUNK_SIZE = 100;
|
|
7116
7415
|
var CLASSIFY_MODULE_RUN_TIMEOUT_MS = 660000;
|
|
7416
|
+
var HOST_COMPLETION_REQUIRED = "host_completion_required";
|
|
7117
7417
|
|
|
7118
7418
|
class ClassifyModuleFailureError extends Error {
|
|
7119
7419
|
transient = true;
|
|
@@ -7197,13 +7497,12 @@ async function runClassify(args) {
|
|
|
7197
7497
|
let stage;
|
|
7198
7498
|
let toClassify;
|
|
7199
7499
|
let anchors = [];
|
|
7500
|
+
const unclassifiedIds = new Set(getUnclassifiedMemoryIds(args.db, active.map((candidate) => candidate.contextMemory.id)));
|
|
7501
|
+
toClassify = active.filter((candidate) => unclassifiedIds.has(candidate.contextMemory.id));
|
|
7200
7502
|
if (active.length <= FULL_POOL_CEILING) {
|
|
7201
7503
|
stage = 2;
|
|
7202
|
-
toClassify = active;
|
|
7203
7504
|
} else {
|
|
7204
7505
|
stage = 3;
|
|
7205
|
-
const unclassifiedIds = new Set(getUnclassifiedMemoryIds(args.db, active.map((candidate) => candidate.contextMemory.id)));
|
|
7206
|
-
toClassify = active.filter((candidate) => unclassifiedIds.has(candidate.contextMemory.id));
|
|
7207
7506
|
const classified = active.filter((candidate) => !unclassifiedIds.has(candidate.contextMemory.id));
|
|
7208
7507
|
anchors = stratifiedAnchors(classified, STAGE3_ANCHOR_COUNT);
|
|
7209
7508
|
}
|
|
@@ -7224,7 +7523,7 @@ async function runClassify(args) {
|
|
|
7224
7523
|
chunks.push(toClassify.slice(i, i + CLASSIFY_CHUNK_SIZE));
|
|
7225
7524
|
}
|
|
7226
7525
|
const abortController = new AbortController;
|
|
7227
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
7526
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, (reason) => abortController.abort(new Error(reason)), args.leaseAcquisition);
|
|
7228
7527
|
try {
|
|
7229
7528
|
for (let i = 0;i < chunks.length; i += 1) {
|
|
7230
7529
|
const remainingMs = Math.max(0, args.deadline - Date.now());
|
|
@@ -7259,65 +7558,89 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
7259
7558
|
memories: chunk.map(toPromptMemory2),
|
|
7260
7559
|
anchors
|
|
7261
7560
|
});
|
|
7262
|
-
|
|
7263
|
-
const
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
const executor = resolveHiddenCompletionExecutor(args.hiddenCompletionExecutor, args.client, args.db, args.sessionDirectory, "classify-memories");
|
|
7268
|
-
closeExecutor = executor;
|
|
7269
|
-
handle = await executor.open({
|
|
7270
|
-
parentSessionId: args.parentSessionId,
|
|
7271
|
-
agent: DREAMER_CLASSIFIER_AGENT,
|
|
7272
|
-
kind: "dreamer-task",
|
|
7273
|
-
system: withContentLanguageDirective(CLASSIFY_SYSTEM_PROMPT, args.language),
|
|
7274
|
-
model: args.model,
|
|
7275
|
-
configuredModels: [...args.model ? [args.model] : [], ...args.fallbackModels ?? []],
|
|
7276
|
-
timeoutMs: sliceMs,
|
|
7277
|
-
title: "magic-context-dream-classify",
|
|
7278
|
-
directory: args.sessionDirectory,
|
|
7279
|
-
metadata: { task: "classify-memories" }
|
|
7280
|
-
});
|
|
7281
|
-
agentSessionId = handle.id || null;
|
|
7282
|
-
if (!agentSessionId)
|
|
7283
|
-
throw new Error("Could not create classify session.");
|
|
7284
|
-
const opened = handle;
|
|
7285
|
-
const run = await promptSyncWithValidatedOutputRetry(args.client, {
|
|
7286
|
-
path: { id: agentSessionId },
|
|
7287
|
-
query: { directory: args.sessionDirectory },
|
|
7288
|
-
body: {
|
|
7561
|
+
const runOnHostCarrier = async (system) => {
|
|
7562
|
+
const executor = resolveHiddenCompletionExecutor(args.hiddenCompletionExecutor, args.client, args.db, args.sessionDirectory, "classify-memories");
|
|
7563
|
+
closeExecutor = executor;
|
|
7564
|
+
handle = await executor.open({
|
|
7565
|
+
parentSessionId: args.parentSessionId,
|
|
7289
7566
|
agent: DREAMER_CLASSIFIER_AGENT,
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7298
|
-
|
|
7299
|
-
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7567
|
+
kind: "dreamer-task",
|
|
7568
|
+
system,
|
|
7569
|
+
model: args.model,
|
|
7570
|
+
configuredModels: [
|
|
7571
|
+
...args.model ? [args.model] : [],
|
|
7572
|
+
...args.fallbackModels ?? []
|
|
7573
|
+
],
|
|
7574
|
+
timeoutMs: sliceMs,
|
|
7575
|
+
title: "magic-context-dream-classify",
|
|
7576
|
+
directory: args.sessionDirectory,
|
|
7577
|
+
metadata: { task: "classify-memories" }
|
|
7578
|
+
});
|
|
7579
|
+
agentSessionId = handle.id || null;
|
|
7580
|
+
if (!agentSessionId)
|
|
7581
|
+
throw new Error("Could not create classify session.");
|
|
7582
|
+
const opened = handle;
|
|
7583
|
+
const run = await promptSyncWithValidatedOutputRetry(args.client, {
|
|
7584
|
+
path: { id: agentSessionId },
|
|
7585
|
+
query: { directory: args.sessionDirectory },
|
|
7586
|
+
body: {
|
|
7587
|
+
agent: DREAMER_CLASSIFIER_AGENT,
|
|
7588
|
+
system,
|
|
7589
|
+
...modelBodyField(args.model),
|
|
7590
|
+
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
7305
7591
|
}
|
|
7306
|
-
|
|
7307
|
-
|
|
7308
|
-
|
|
7309
|
-
|
|
7310
|
-
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7592
|
+
}, {
|
|
7593
|
+
transport: Object.assign((request) => executor.attempt(opened, request), { childSessionId: opened.childSessionId }),
|
|
7594
|
+
timeoutMs: sliceMs,
|
|
7595
|
+
signal,
|
|
7596
|
+
fallbackModels: args.fallbackModels,
|
|
7597
|
+
callContext: "dreamer:classify-memories",
|
|
7598
|
+
fetchOutput: () => executor.collect(opened, 50),
|
|
7599
|
+
validateOutput: (completion) => {
|
|
7600
|
+
const messages = completion.messages ?? [];
|
|
7601
|
+
if (completion.lengthCapped) {
|
|
7602
|
+
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");
|
|
7603
|
+
}
|
|
7604
|
+
const text = completion.text;
|
|
7605
|
+
if (!text)
|
|
7606
|
+
throw new Error("classify returned no output");
|
|
7607
|
+
try {
|
|
7608
|
+
validateClassifyManifest(text, new Set(chunk.map((candidate) => candidate.id)));
|
|
7609
|
+
} catch (error) {
|
|
7610
|
+
const providerFailure = providerOutputFailureFromInvalidManifest(messages, text);
|
|
7611
|
+
if (providerFailure)
|
|
7612
|
+
throw providerFailure;
|
|
7613
|
+
throw error;
|
|
7614
|
+
}
|
|
7615
|
+
return text;
|
|
7316
7616
|
}
|
|
7317
|
-
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
|
|
7617
|
+
});
|
|
7618
|
+
promptSettled = true;
|
|
7619
|
+
return run;
|
|
7620
|
+
};
|
|
7621
|
+
if (moduleRoute) {
|
|
7622
|
+
const { accounting, ...run } = await runClassifyThroughModule(args, chunk, anchors, signal, async (system) => {
|
|
7623
|
+
const run = await runOnHostCarrier(system);
|
|
7624
|
+
const output = run.output;
|
|
7625
|
+
return {
|
|
7626
|
+
text: run.validated,
|
|
7627
|
+
model: output.providerId && output.modelId ? `${output.providerId}/${output.modelId}` : run.attempt.label,
|
|
7628
|
+
length_capped: output.lengthCapped === true,
|
|
7629
|
+
usage: {
|
|
7630
|
+
input: output.usage?.input ?? 0,
|
|
7631
|
+
output: output.usage?.output ?? 0,
|
|
7632
|
+
cache_read: output.usage?.cacheRead ?? 0,
|
|
7633
|
+
cache_write: output.usage?.cacheWrite ?? 0
|
|
7634
|
+
}
|
|
7635
|
+
};
|
|
7636
|
+
});
|
|
7637
|
+
recordInvocation(args, startedAt, {
|
|
7638
|
+
status: "completed",
|
|
7639
|
+
moduleAccounting: accounting
|
|
7640
|
+
});
|
|
7641
|
+
return run;
|
|
7642
|
+
}
|
|
7643
|
+
const run = await runOnHostCarrier(withContentLanguageDirective(CLASSIFY_SYSTEM_PROMPT, args.language));
|
|
7321
7644
|
recordInvocation(args, startedAt, {
|
|
7322
7645
|
status: "completed",
|
|
7323
7646
|
messages: run.output.messages,
|
|
@@ -7330,7 +7653,8 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
7330
7653
|
log(`[dreamer] classify chunk failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
|
|
7331
7654
|
recordInvocation(args, startedAt, {
|
|
7332
7655
|
status: failedInvocationStatus(failure),
|
|
7333
|
-
error: failure
|
|
7656
|
+
error: failure,
|
|
7657
|
+
messages: args.hiddenCompletionExecutor ? undefined : await readFailedChildMessages(args.client, agentSessionId, args.sessionDirectory)
|
|
7334
7658
|
});
|
|
7335
7659
|
if (moduleRoute || failure instanceof HiddenCompletionRefusal || signal.aborted || failure instanceof DreamerProviderOutputFailureError || getPromptFailureDetail(failure)?.failureClass !== "parse_failed" && getPromptFailureDetail(failure) !== null)
|
|
7336
7660
|
throw failure;
|
|
@@ -7344,7 +7668,7 @@ async function classifyOneChunk(args, chunk, anchors, sliceMs, signal) {
|
|
|
7344
7668
|
});
|
|
7345
7669
|
}
|
|
7346
7670
|
}
|
|
7347
|
-
async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
7671
|
+
async function runClassifyThroughModule(args, chunk, anchors, signal, runOnHost) {
|
|
7348
7672
|
const prompt = buildClassifyPrompt({
|
|
7349
7673
|
projectPath: args.projectIdentity,
|
|
7350
7674
|
memories: chunk.map(toPromptMemory2),
|
|
@@ -7352,7 +7676,8 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
7352
7676
|
});
|
|
7353
7677
|
const modelChain = [args.model, ...args.fallbackModels ?? []].map(toModelEntry).filter((entry) => entry !== undefined).map((entry) => entry.model);
|
|
7354
7678
|
const resolvedModelChain = [...new Set(modelChain)];
|
|
7355
|
-
const
|
|
7679
|
+
const commandId = `classify:${args.moduleCommandId ?? Date.now()}:${createHash5("sha256").update(chunk.map((candidate) => candidate.id).join(",")).digest("hex").slice(0, 24)}`;
|
|
7680
|
+
const runTask = (hostCompletion) => args.moduleClient?.call({
|
|
7356
7681
|
sessionId: args.moduleSessionId,
|
|
7357
7682
|
projectRoot: args.moduleProjectRoot,
|
|
7358
7683
|
method: "dreamer.run_task",
|
|
@@ -7361,21 +7686,29 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
7361
7686
|
v: 1,
|
|
7362
7687
|
session_id: args.moduleSessionId,
|
|
7363
7688
|
task: "classify",
|
|
7364
|
-
command_id:
|
|
7689
|
+
command_id: commandId,
|
|
7365
7690
|
authority_generation: args.moduleAuthorityGeneration,
|
|
7366
|
-
|
|
7691
|
+
model_chain: resolvedModelChain,
|
|
7367
7692
|
payload: {
|
|
7368
7693
|
prompt_body: prompt,
|
|
7369
7694
|
items: chunk.map((candidate) => ({
|
|
7370
7695
|
memory_id: candidate.id,
|
|
7371
7696
|
content_hash: candidate.normalizedHash
|
|
7372
7697
|
}))
|
|
7373
|
-
}
|
|
7698
|
+
},
|
|
7699
|
+
...hostCompletion ? { host_completion: hostCompletion } : {}
|
|
7374
7700
|
},
|
|
7375
7701
|
signal,
|
|
7376
|
-
timeoutMs: CLASSIFY_MODULE_RUN_TIMEOUT_MS
|
|
7702
|
+
timeoutMs: Math.max(1, resolvedModelChain.length) * CLASSIFY_MODULE_RUN_TIMEOUT_MS + 30000
|
|
7377
7703
|
});
|
|
7378
|
-
const
|
|
7704
|
+
const unwrap = (response) => response?.result ?? response;
|
|
7705
|
+
let result = unwrap(await runTask());
|
|
7706
|
+
const asked = result;
|
|
7707
|
+
if (asked?.code === HOST_COMPLETION_REQUIRED) {
|
|
7708
|
+
if (typeof asked.system_prompt !== "string")
|
|
7709
|
+
throw new Error("module asked for a host classify completion without a system prompt");
|
|
7710
|
+
result = unwrap(await runTask(await runOnHost(asked.system_prompt)));
|
|
7711
|
+
}
|
|
7379
7712
|
if (!result || typeof result !== "object")
|
|
7380
7713
|
throw new Error("module returned invalid classify result");
|
|
7381
7714
|
const manifestText = result.manifest_text;
|
|
@@ -7384,6 +7717,7 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
7384
7717
|
if (result.truncated === true) {
|
|
7385
7718
|
throw new Error("classify returned length-capped output");
|
|
7386
7719
|
}
|
|
7720
|
+
const accounting = moduleClassifyAccounting(result);
|
|
7387
7721
|
const parsed = validateClassifyManifest(manifestText, new Set(chunk.map((candidate) => candidate.id)));
|
|
7388
7722
|
const rows = parsed.map((entry) => {
|
|
7389
7723
|
const candidate = chunk.find((item) => item.id === entry.id);
|
|
@@ -7456,7 +7790,39 @@ async function runClassifyThroughModule(args, chunk, anchors, signal) {
|
|
|
7456
7790
|
throw new Error(`module accepted unknown memory ${moduleId}`);
|
|
7457
7791
|
return candidate.contextMemory.id;
|
|
7458
7792
|
});
|
|
7459
|
-
return {
|
|
7793
|
+
return {
|
|
7794
|
+
classified: acceptedContextIds.length,
|
|
7795
|
+
changed: acceptedContextIds.length,
|
|
7796
|
+
accounting
|
|
7797
|
+
};
|
|
7798
|
+
}
|
|
7799
|
+
function nonNegativeCount(value) {
|
|
7800
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
|
|
7801
|
+
}
|
|
7802
|
+
function moduleClassifyAccounting(result) {
|
|
7803
|
+
const accounting = {};
|
|
7804
|
+
const usage = result.usage;
|
|
7805
|
+
if (usage && typeof usage === "object") {
|
|
7806
|
+
const record = usage;
|
|
7807
|
+
accounting.tokens = {
|
|
7808
|
+
input: nonNegativeCount(record.input),
|
|
7809
|
+
output: nonNegativeCount(record.output),
|
|
7810
|
+
cacheRead: nonNegativeCount(record.cache_read),
|
|
7811
|
+
cacheWrite: nonNegativeCount(record.cache_write)
|
|
7812
|
+
};
|
|
7813
|
+
}
|
|
7814
|
+
const diagnostics = result.diagnostics;
|
|
7815
|
+
const model = diagnostics && typeof diagnostics === "object" ? diagnostics.model : undefined;
|
|
7816
|
+
if (typeof model === "string") {
|
|
7817
|
+
const parsed = parseProviderModel(model);
|
|
7818
|
+
if (parsed) {
|
|
7819
|
+
accounting.providerId = parsed.providerID;
|
|
7820
|
+
accounting.modelId = parsed.modelID;
|
|
7821
|
+
} else if (model.trim()) {
|
|
7822
|
+
accounting.modelId = model.trim();
|
|
7823
|
+
}
|
|
7824
|
+
}
|
|
7825
|
+
return accounting;
|
|
7460
7826
|
}
|
|
7461
7827
|
function applyClassifications(args, chunk, manifestText) {
|
|
7462
7828
|
const byId = new Map(chunk.map((m) => [m.id, m]));
|
|
@@ -7501,6 +7867,11 @@ function recordInvocation(args, startedAt, params) {
|
|
|
7501
7867
|
providerId: params.completion.providerId,
|
|
7502
7868
|
modelId: params.completion.modelId
|
|
7503
7869
|
} : {},
|
|
7870
|
+
...params.moduleAccounting ? {
|
|
7871
|
+
tokens: params.moduleAccounting.tokens,
|
|
7872
|
+
providerId: params.moduleAccounting.providerId,
|
|
7873
|
+
modelId: params.moduleAccounting.modelId
|
|
7874
|
+
} : {},
|
|
7504
7875
|
error: params.error
|
|
7505
7876
|
});
|
|
7506
7877
|
}
|
|
@@ -8099,7 +8470,7 @@ async function guardedReadFile(projectRoot, repoRelativePath, signal, fileLimitB
|
|
|
8099
8470
|
const body = guardedReadFileBody(projectRoot, repoRelativePath, signal, fileLimitBytes);
|
|
8100
8471
|
let onAbort;
|
|
8101
8472
|
const abort = new Promise((_, reject) => {
|
|
8102
|
-
onAbort = () => reject(
|
|
8473
|
+
onAbort = () => reject(abortError2(signal));
|
|
8103
8474
|
if (signal.aborted)
|
|
8104
8475
|
onAbort();
|
|
8105
8476
|
else
|
|
@@ -8169,9 +8540,9 @@ async function closeLateOpenOnAbort(openPromise, signal) {
|
|
|
8169
8540
|
return handle;
|
|
8170
8541
|
if (handle)
|
|
8171
8542
|
handle.close().catch(() => {});
|
|
8172
|
-
throw
|
|
8543
|
+
throw abortError2(signal);
|
|
8173
8544
|
}
|
|
8174
|
-
function
|
|
8545
|
+
function abortError2(signal) {
|
|
8175
8546
|
return signal.reason instanceof SmartNoteNetworkError ? signal.reason : new SmartNoteNetworkError("SMART_NOTE_NETWORK: aborted");
|
|
8176
8547
|
}
|
|
8177
8548
|
function isPathInside(root, target) {
|
|
@@ -8990,9 +9361,9 @@ async function evaluateSmartNotes(args) {
|
|
|
8990
9361
|
throw new Error(`Dream lease lost during smart-notes ${phase}`);
|
|
8991
9362
|
}
|
|
8992
9363
|
};
|
|
8993
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => {
|
|
9364
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, (reason) => {
|
|
8994
9365
|
leaseLost = true;
|
|
8995
|
-
leaseAbortController.abort(new Error(
|
|
9366
|
+
leaseAbortController.abort(new Error(reason));
|
|
8996
9367
|
log("[dreamer] smart notes: lease lost — aborting");
|
|
8997
9368
|
args.onLeaseLost?.("smart notes");
|
|
8998
9369
|
}, args.leaseAcquisition);
|
|
@@ -9307,6 +9678,7 @@ async function confirmReadOnly(args, noteId, content, surfaceCondition, leaseSig
|
|
|
9307
9678
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
9308
9679
|
}
|
|
9309
9680
|
}, {
|
|
9681
|
+
transport: createPromptAsyncTransport(client, childSessionId),
|
|
9310
9682
|
timeoutMs: Math.max(1000, args.deadline - Date.now()),
|
|
9311
9683
|
signal: promptSignal.signal,
|
|
9312
9684
|
fallbackModels: args.fallbackModels,
|
|
@@ -9614,7 +9986,7 @@ function computeMapBatchSliceMs(remainingMs, batchesRemaining) {
|
|
|
9614
9986
|
return Math.min(remainingMs, Math.max(MAP_BATCH_FLOOR_MS, Math.floor(remainingMs / batchesRemaining)));
|
|
9615
9987
|
}
|
|
9616
9988
|
function isTimeoutClassError2(error) {
|
|
9617
|
-
return
|
|
9989
|
+
return isPromptTimeoutError(error);
|
|
9618
9990
|
}
|
|
9619
9991
|
function shouldRequeueIndependentMapping(state, content, repoDir) {
|
|
9620
9992
|
if (!state.hasSentinel || state.files.length > 0)
|
|
@@ -9669,7 +10041,7 @@ async function mapMemories(args) {
|
|
|
9669
10041
|
}
|
|
9670
10042
|
result.remaining = inputs.length;
|
|
9671
10043
|
const abortController = new AbortController;
|
|
9672
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
10044
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, (reason) => abortController.abort(new Error(reason)), args.leaseAcquisition);
|
|
9673
10045
|
try {
|
|
9674
10046
|
let consecutiveTimeouts = 0;
|
|
9675
10047
|
let timeoutStreakElapsedMs = [];
|
|
@@ -9784,6 +10156,7 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
|
|
|
9784
10156
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
9785
10157
|
}
|
|
9786
10158
|
}, {
|
|
10159
|
+
transport: createPromptAsyncTransport(client, agentSessionId),
|
|
9787
10160
|
timeoutMs: sliceMs,
|
|
9788
10161
|
signal,
|
|
9789
10162
|
fallbackModels: args.fallbackModels,
|
|
@@ -9818,7 +10191,11 @@ async function mapOneBatch(args, batch, sliceMs, signal) {
|
|
|
9818
10191
|
} catch (error) {
|
|
9819
10192
|
const desc = describeError(error);
|
|
9820
10193
|
log(`[dreamer] map-memories batch failed: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
|
|
9821
|
-
recordInvocation2(args, startedAt, {
|
|
10194
|
+
recordInvocation2(args, startedAt, {
|
|
10195
|
+
status: failedInvocationStatus(error),
|
|
10196
|
+
error,
|
|
10197
|
+
messages: await readFailedChildMessages(args.client, agentSessionId, args.sessionDirectory)
|
|
10198
|
+
});
|
|
9822
10199
|
if (error instanceof DreamerModuleFailureError)
|
|
9823
10200
|
throw error;
|
|
9824
10201
|
if (signal.aborted)
|
|
@@ -10143,7 +10520,7 @@ function pruneExpiredPrimerCandidatesForProject(db, projectIdentity, now = Date.
|
|
|
10143
10520
|
db.transaction(() => {
|
|
10144
10521
|
for (const id of toDelete)
|
|
10145
10522
|
stmt.run(id, projectIdentity);
|
|
10146
|
-
})();
|
|
10523
|
+
}).immediate();
|
|
10147
10524
|
return toDelete.length;
|
|
10148
10525
|
}
|
|
10149
10526
|
async function promotePrimers(args) {
|
|
@@ -10562,13 +10939,7 @@ var FRUSTRATION_MARKER_REGEX = /\b(?:not what i asked|i already (?:said|told you
|
|
|
10562
10939
|
var LEARNINGS_BLOCK_REGEX = /<learnings\b[^>]*>(.*?)<\/learnings>/is;
|
|
10563
10940
|
var LEARNING_REGEX = /<learning\b([^>]*)>(.*?)<\/learning>/gis;
|
|
10564
10941
|
var ATTR_REGEX = /([a-zA-Z_:-]+)\s*=\s*"([^"]*)"/g;
|
|
10565
|
-
var VALID_MEMORY_CATEGORIES = new Set(
|
|
10566
|
-
"PROJECT_RULES",
|
|
10567
|
-
"ARCHITECTURE",
|
|
10568
|
-
"CONSTRAINTS",
|
|
10569
|
-
"CONFIG_VALUES",
|
|
10570
|
-
"NAMING"
|
|
10571
|
-
]);
|
|
10942
|
+
var VALID_MEMORY_CATEGORIES = new Set(V2_MEMORY_CATEGORIES);
|
|
10572
10943
|
var RAW_QUOTE_REGEX = /["“”][^"“”]{4,}["“”]|'[^']{4,}'/;
|
|
10573
10944
|
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;
|
|
10574
10945
|
function parseRetrospectiveLearnings(text) {
|
|
@@ -11327,6 +11698,10 @@ function validateVerifyManifest(text, expectedIds) {
|
|
|
11327
11698
|
// ../plugin/src/features/magic-context/dreamer/verify.ts
|
|
11328
11699
|
var VERIFY_BATCH_SIZE = 50;
|
|
11329
11700
|
var IDENTICAL_PROVIDER_FAILURE_BATCH_LIMIT = 2;
|
|
11701
|
+
var VERIFY_BATCH_FLOOR_MS = 240000;
|
|
11702
|
+
function computeVerifyBatchSliceMs(remainingMs, batchesRemaining) {
|
|
11703
|
+
return Math.min(remainingMs, Math.max(VERIFY_BATCH_FLOOR_MS, Math.floor(remainingMs / batchesRemaining)));
|
|
11704
|
+
}
|
|
11330
11705
|
function closeBroadCycle(args, cycleStartAt) {
|
|
11331
11706
|
if (!args.forceBroad || cycleStartAt === undefined)
|
|
11332
11707
|
return;
|
|
@@ -11381,17 +11756,19 @@ async function runVerify(args) {
|
|
|
11381
11756
|
batches.push(gate.inScope.slice(i, i + VERIFY_BATCH_SIZE));
|
|
11382
11757
|
}
|
|
11383
11758
|
const abortController = new AbortController;
|
|
11384
|
-
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, () => abortController.abort(), args.leaseAcquisition);
|
|
11759
|
+
const heartbeat = startLeaseHeartbeat(args.db, args.holderId, args.leaseKey, (reason) => abortController.abort(new Error(reason)), args.leaseAcquisition);
|
|
11385
11760
|
let consecutiveProviderFailures = 0;
|
|
11386
11761
|
let priorProviderFailureFingerprint = null;
|
|
11387
11762
|
let lastProviderFailure = null;
|
|
11388
11763
|
try {
|
|
11389
11764
|
for (let i = 0;i < batches.length; i += 1) {
|
|
11390
11765
|
const remainingMs = Math.max(0, args.deadline - Date.now());
|
|
11391
|
-
if (remainingMs
|
|
11766
|
+
if (remainingMs < VERIFY_BATCH_FLOOR_MS) {
|
|
11767
|
+
result.stopReason = "deadline";
|
|
11768
|
+
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`);
|
|
11392
11769
|
break;
|
|
11393
|
-
|
|
11394
|
-
const sliceMs =
|
|
11770
|
+
}
|
|
11771
|
+
const sliceMs = computeVerifyBatchSliceMs(remainingMs, batches.length - i);
|
|
11395
11772
|
const counts = await verifyOneBatch(args, batches[i], sliceMs, abortController.signal);
|
|
11396
11773
|
result.verified += counts.verified;
|
|
11397
11774
|
result.updated += counts.updated;
|
|
@@ -11402,6 +11779,11 @@ async function runVerify(args) {
|
|
|
11402
11779
|
result.remaining -= batchProcessed;
|
|
11403
11780
|
result.batches += 1;
|
|
11404
11781
|
args.onProgress?.(result.verified + result.updated + result.archived + result.skipped + result.refused, result.refused);
|
|
11782
|
+
if (counts.timedOut) {
|
|
11783
|
+
result.stopReason = "batch-timeout";
|
|
11784
|
+
log(`[dreamer] ${args.forceBroad ? "verify-broad" : "verify"}: batch ${i + 1}/${batches.length} timed out after its ${sliceMs}ms slice; stopping with ${result.remaining} remaining`);
|
|
11785
|
+
break;
|
|
11786
|
+
}
|
|
11405
11787
|
if (counts.providerFailure) {
|
|
11406
11788
|
lastProviderFailure = counts.providerFailure;
|
|
11407
11789
|
if (counts.providerFailure.fingerprint === priorProviderFailureFingerprint) {
|
|
@@ -11490,6 +11872,7 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
11490
11872
|
parts: [{ type: "text", text: prompt, synthetic: true }]
|
|
11491
11873
|
}
|
|
11492
11874
|
}, {
|
|
11875
|
+
transport: createPromptAsyncTransport(client, agentSessionId),
|
|
11493
11876
|
timeoutMs: sliceMs,
|
|
11494
11877
|
signal,
|
|
11495
11878
|
fallbackModels: args.fallbackModels,
|
|
@@ -11524,8 +11907,24 @@ async function verifyOneBatch(args, batch, sliceMs, signal) {
|
|
|
11524
11907
|
const providerFailure = error instanceof DreamerProviderOutputFailureError ? error : undefined;
|
|
11525
11908
|
const promptFailure = getPromptFailureDetail(error);
|
|
11526
11909
|
log(`[dreamer] verify batch ${providerFailure ? "provider failure" : "failed"}: ${desc.brief}`, desc.stackHead ? { stackHead: desc.stackHead } : undefined);
|
|
11527
|
-
recordInvocation4(args, startedAt, {
|
|
11528
|
-
|
|
11910
|
+
recordInvocation4(args, startedAt, {
|
|
11911
|
+
status: failedInvocationStatus(error),
|
|
11912
|
+
error,
|
|
11913
|
+
messages: await readFailedChildMessages(args.client, agentSessionId, args.sessionDirectory)
|
|
11914
|
+
});
|
|
11915
|
+
if (error instanceof DreamerModuleFailureError || signal.aborted)
|
|
11916
|
+
throw error;
|
|
11917
|
+
if (promptFailure?.failureClass === "provider_timeout" || isPromptTimeoutError(error)) {
|
|
11918
|
+
return {
|
|
11919
|
+
verified: 0,
|
|
11920
|
+
updated: 0,
|
|
11921
|
+
archived: 0,
|
|
11922
|
+
skipped: 0,
|
|
11923
|
+
refused: 0,
|
|
11924
|
+
timedOut: true
|
|
11925
|
+
};
|
|
11926
|
+
}
|
|
11927
|
+
if (promptFailure !== null && promptFailure.failureClass !== "parse_failed" && !providerFailure)
|
|
11529
11928
|
throw error;
|
|
11530
11929
|
return {
|
|
11531
11930
|
verified: 0,
|
|
@@ -11767,6 +12166,16 @@ function dreamRunFailureDetail(error) {
|
|
|
11767
12166
|
}
|
|
11768
12167
|
const described = describeError(error);
|
|
11769
12168
|
const message = described.brief;
|
|
12169
|
+
if (error instanceof Error && error.name === "HiddenAgentStepLimit") {
|
|
12170
|
+
return {
|
|
12171
|
+
failure_class: "step_limit",
|
|
12172
|
+
model_attempted: null,
|
|
12173
|
+
models_tried: [],
|
|
12174
|
+
provider_error: null,
|
|
12175
|
+
timeout_ms: null,
|
|
12176
|
+
child_session_id: null
|
|
12177
|
+
};
|
|
12178
|
+
}
|
|
11770
12179
|
const providerFailure = error instanceof HiddenCompletionRefusal || error instanceof Error && error.name === "DreamerProviderOutputFailureError";
|
|
11771
12180
|
return {
|
|
11772
12181
|
failure_class: providerFailure ? "provider_error" : /no models?|model chain is empty/i.test(message) ? "no_models" : "unknown",
|
|
@@ -11906,11 +12315,16 @@ function createDreamTaskExecutor(deps) {
|
|
|
11906
12315
|
});
|
|
11907
12316
|
};
|
|
11908
12317
|
reportProgress(0);
|
|
12318
|
+
if (config.modelChainUnavailable) {
|
|
12319
|
+
return {
|
|
12320
|
+
status: "completed",
|
|
12321
|
+
detail: "skipped: Pi model chain is empty (no configured model resolves in Pi)"
|
|
12322
|
+
};
|
|
12323
|
+
}
|
|
11909
12324
|
const incompleteMessage = (remaining) => {
|
|
11910
12325
|
const processed = processedDreamTaskItems(backlogAtStart.pending, remaining);
|
|
11911
12326
|
return `${config.task} incomplete: ${remaining} remain (was ${backlogAtStart.pending} at run start; processed ${processed} this run)`;
|
|
11912
12327
|
};
|
|
11913
|
-
const parent = await resolveParentSessionId();
|
|
11914
12328
|
let moduleRoute;
|
|
11915
12329
|
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") {
|
|
11916
12330
|
try {
|
|
@@ -11926,6 +12340,19 @@ function createDreamTaskExecutor(deps) {
|
|
|
11926
12340
|
throw new DreamerModuleFailureError("authority.status", error);
|
|
11927
12341
|
}
|
|
11928
12342
|
}
|
|
12343
|
+
if (!moduleRoute && getAuthorityManagedMarker(db, projectIdentity) && [
|
|
12344
|
+
"curate",
|
|
12345
|
+
"map-memories",
|
|
12346
|
+
"compress-cues",
|
|
12347
|
+
"classify-memories",
|
|
12348
|
+
"verify",
|
|
12349
|
+
"verify-broad",
|
|
12350
|
+
"retrospective"
|
|
12351
|
+
].includes(config.task)) {
|
|
12352
|
+
logDreamerNotOwnerOnce(projectIdentity);
|
|
12353
|
+
return { status: "completed", detail: "skipped: module-managed memory; not owner" };
|
|
12354
|
+
}
|
|
12355
|
+
const parent = await resolveParentSessionId();
|
|
11929
12356
|
if (!leaseOwnershipMatches(db, holderId, leaseAcquisition.generation, leaseKey)) {
|
|
11930
12357
|
throw new Error("Dream lease lost during executor setup");
|
|
11931
12358
|
}
|
|
@@ -12115,13 +12542,14 @@ function createDreamTaskExecutor(deps) {
|
|
|
12115
12542
|
});
|
|
12116
12543
|
return { status: "completed" };
|
|
12117
12544
|
}
|
|
12118
|
-
const
|
|
12545
|
+
const batchTimedOut = result.stopReason === "batch-timeout";
|
|
12546
|
+
const error = batchTimedOut ? `${config.task}: a batch timed out within its time slice; ${result.remaining} remain` : incompleteMessage(result.remaining);
|
|
12119
12547
|
recordRun("failed", error, {
|
|
12120
12548
|
progress: verificationProgress,
|
|
12121
12549
|
memoryChanges: computeMemoryDelta(memoryBefore),
|
|
12122
12550
|
backlogAfter
|
|
12123
12551
|
});
|
|
12124
|
-
return { status: "failed", transient:
|
|
12552
|
+
return { status: "failed", transient: !batchTimedOut, error };
|
|
12125
12553
|
}
|
|
12126
12554
|
recordRun("completed", null, {
|
|
12127
12555
|
progress: verificationProgress,
|
|
@@ -12947,25 +13375,45 @@ function ensureSeeded(db, projectIdentity, config, now) {
|
|
|
12947
13375
|
const nextDueAt = nextDueAtMs(config.schedule, now);
|
|
12948
13376
|
seedTaskScheduleState(db, projectIdentity, config.task, nextDueAt, lastRunAt, config.schedule);
|
|
12949
13377
|
}
|
|
13378
|
+
function firstRepeatedCivilMinute(candidateMs) {
|
|
13379
|
+
const date = new Date(candidateMs);
|
|
13380
|
+
const first = new Date(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes()).getTime();
|
|
13381
|
+
return first < candidateMs ? first : null;
|
|
13382
|
+
}
|
|
12950
13383
|
function reconcileSchedule(db, projectIdentity, config, now) {
|
|
12951
13384
|
ensureSeeded(db, projectIdentity, config, now);
|
|
12952
|
-
|
|
12953
|
-
if (!stored || stored.schedule === config.schedule)
|
|
12954
|
-
return;
|
|
12955
|
-
if (config.schedule.trim() === "") {
|
|
12956
|
-
writeTaskScheduleState(db, { ...stored, schedule: config.schedule, nextDueAt: null });
|
|
12957
|
-
return;
|
|
12958
|
-
}
|
|
12959
|
-
if (stored.schedule === null && stored.nextDueAt !== null) {
|
|
12960
|
-
writeTaskScheduleState(db, { ...stored, schedule: config.schedule });
|
|
13385
|
+
if (getTaskScheduleState(db, projectIdentity, config.task)?.schedule === config.schedule)
|
|
12961
13386
|
return;
|
|
13387
|
+
const candidate = nextDueAtMs(config.schedule, now);
|
|
13388
|
+
const repeatedFirst = candidate === null ? null : firstRepeatedCivilMinute(candidate);
|
|
13389
|
+
const afterRepeatedFirst = repeatedFirst === null ? candidate : nextDueAtMs(config.schedule, now, repeatedFirst);
|
|
13390
|
+
db.exec("BEGIN IMMEDIATE");
|
|
13391
|
+
let committed = false;
|
|
13392
|
+
try {
|
|
13393
|
+
const stored = getTaskScheduleState(db, projectIdentity, config.task);
|
|
13394
|
+
if (stored && stored.schedule !== config.schedule) {
|
|
13395
|
+
if (stored.schedule === null && stored.nextDueAt !== null) {
|
|
13396
|
+
writeTaskScheduleState(db, { ...stored, schedule: config.schedule });
|
|
13397
|
+
} else {
|
|
13398
|
+
const nextDueAt = repeatedFirst !== null && candidate !== null && stored.nextDueAt !== null && stored.nextDueAt > candidate && stored.lastStatus !== null ? afterRepeatedFirst : candidate;
|
|
13399
|
+
const reconciledNextDueAt = stored.nextDueAt === null ? nextDueAt : nextDueAt === null ? stored.nextDueAt : Math.min(stored.nextDueAt, nextDueAt);
|
|
13400
|
+
writeTaskScheduleState(db, {
|
|
13401
|
+
...stored,
|
|
13402
|
+
schedule: config.schedule,
|
|
13403
|
+
nextDueAt: reconciledNextDueAt,
|
|
13404
|
+
retryCount: reconciledNextDueAt === stored.nextDueAt ? stored.retryCount : 0
|
|
13405
|
+
});
|
|
13406
|
+
}
|
|
13407
|
+
}
|
|
13408
|
+
db.exec("COMMIT");
|
|
13409
|
+
committed = true;
|
|
13410
|
+
} finally {
|
|
13411
|
+
if (!committed) {
|
|
13412
|
+
try {
|
|
13413
|
+
db.exec("ROLLBACK");
|
|
13414
|
+
} catch {}
|
|
13415
|
+
}
|
|
12962
13416
|
}
|
|
12963
|
-
writeTaskScheduleState(db, {
|
|
12964
|
-
...stored,
|
|
12965
|
-
schedule: config.schedule,
|
|
12966
|
-
nextDueAt: nextDueAtMs(config.schedule, now),
|
|
12967
|
-
retryCount: 0
|
|
12968
|
-
});
|
|
12969
13417
|
}
|
|
12970
13418
|
function planDueTasks(db, projectIdentity, tasks, now) {
|
|
12971
13419
|
const pruned = pruneNonCanonicalTaskRows(db, projectIdentity, CANONICAL_DREAM_TASKS);
|
|
@@ -12974,6 +13422,8 @@ function planDueTasks(db, projectIdentity, tasks, now) {
|
|
|
12974
13422
|
}
|
|
12975
13423
|
const due = [];
|
|
12976
13424
|
for (const config of tasks) {
|
|
13425
|
+
if (config.schedule.trim() === "")
|
|
13426
|
+
continue;
|
|
12977
13427
|
reconcileSchedule(db, projectIdentity, config, now);
|
|
12978
13428
|
const state = getTaskScheduleState(db, projectIdentity, config.task);
|
|
12979
13429
|
if (!state || state.nextDueAt === null)
|
|
@@ -13059,10 +13509,11 @@ async function runDomainGroup(deps, group, cb) {
|
|
|
13059
13509
|
}
|
|
13060
13510
|
try {
|
|
13061
13511
|
for (const due of [...group].sort((a, b) => compareTaskOrder(a.config.task, b.config.task))) {
|
|
13062
|
-
if (!
|
|
13512
|
+
if (!reacquireOwnedLease(db, holderId, leaseKey, acquisition.generation)) {
|
|
13063
13513
|
log(`[dreamer] domain lease lost (${leaseKey}) — stopping remaining task(s)`);
|
|
13064
13514
|
break;
|
|
13065
13515
|
}
|
|
13516
|
+
acquisition = { acquiredAt: Date.now(), generation: acquisition.generation };
|
|
13066
13517
|
if (!cb?.forceGate) {
|
|
13067
13518
|
const gatePass = evaluateTaskGate(due.config.task, {
|
|
13068
13519
|
db,
|
|
@@ -13651,7 +14102,8 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
13651
14102
|
}
|
|
13652
14103
|
const dreamerConfig = reg.dreamerConfig;
|
|
13653
14104
|
const dreamingEnabled = Boolean(dreamerConfig && dreamerConfig.disable !== true);
|
|
13654
|
-
const
|
|
14105
|
+
const configuredTasks = dreamingEnabled && dreamerConfig ? buildDreamTaskRuntimeConfigs(dreamerConfig, reg.harness, reg.language, reg.mural?.model) : [];
|
|
14106
|
+
const runtimeConfigs = reg.validateTaskModels?.(configuredTasks) ?? configuredTasks;
|
|
13655
14107
|
await sweepOrphanedInternalChildren(reg, runtimeConfigs.filter((config) => PRIVACY_SENSITIVE_CHILD_TASKS.includes(config.task)).map((config) => config.timeoutMinutes));
|
|
13656
14108
|
if (commitIndexingEnabled && reg.gitCommitIndexing) {
|
|
13657
14109
|
await sweepGitCommits({
|
|
@@ -13666,6 +14118,10 @@ async function sweepProject(reg, origin, db, gitCommitEnabled) {
|
|
|
13666
14118
|
}
|
|
13667
14119
|
try {
|
|
13668
14120
|
await runCompiledSmartNoteSweep(reg, db);
|
|
14121
|
+
} catch (error) {
|
|
14122
|
+
log(`[dreamer] compiled smart-note sweep failed for ${reg.projectIdentity}:`, error);
|
|
14123
|
+
}
|
|
14124
|
+
try {
|
|
13669
14125
|
const executor = createDreamTaskExecutor({
|
|
13670
14126
|
client: reg.client,
|
|
13671
14127
|
sessionDirectory: reg.directory,
|
|
@@ -13720,6 +14176,10 @@ async function sweepOrphanedInternalChildren(reg, privacyTimeoutMinutes) {
|
|
|
13720
14176
|
}
|
|
13721
14177
|
}
|
|
13722
14178
|
async function runCompiledSmartNoteSweep(reg, db) {
|
|
14179
|
+
if (getAuthorityManagedMarker(db, reg.projectIdentity)) {
|
|
14180
|
+
logDreamerNotOwnerOnce(reg.projectIdentity);
|
|
14181
|
+
return;
|
|
14182
|
+
}
|
|
13723
14183
|
const leaseKey = leaseKeyFor("evaluate-smart-notes", reg.projectIdentity);
|
|
13724
14184
|
const holderId = crypto.randomUUID();
|
|
13725
14185
|
if (!acquireLease(db, holderId, leaseKey))
|
|
@@ -15365,6 +15825,40 @@ function extractPiTextContent(content) {
|
|
|
15365
15825
|
}
|
|
15366
15826
|
|
|
15367
15827
|
// src/dreamer/index.ts
|
|
15828
|
+
var warnedUnknownModels = new Set;
|
|
15829
|
+
var modelAvailability = new WeakMap;
|
|
15830
|
+
function validatePiDreamerModels(tasks, registry) {
|
|
15831
|
+
let resolved = modelAvailability.get(registry);
|
|
15832
|
+
if (!resolved) {
|
|
15833
|
+
resolved = new Map;
|
|
15834
|
+
modelAvailability.set(registry, resolved);
|
|
15835
|
+
}
|
|
15836
|
+
return tasks.map((task) => {
|
|
15837
|
+
const entries = [task.model, ...task.fallbackModels ?? []].filter((entry) => entry !== undefined);
|
|
15838
|
+
const valid = entries.filter((entry) => {
|
|
15839
|
+
const model = typeof entry === "string" ? entry : entry.model;
|
|
15840
|
+
let available = resolved.get(model);
|
|
15841
|
+
if (available === undefined) {
|
|
15842
|
+
const separator = model.indexOf("/");
|
|
15843
|
+
available = separator > 0 && Boolean(registry.find(model.slice(0, separator), model.slice(separator + 1)));
|
|
15844
|
+
resolved.set(model, available);
|
|
15845
|
+
}
|
|
15846
|
+
if (available)
|
|
15847
|
+
return true;
|
|
15848
|
+
if (!warnedUnknownModels.has(model)) {
|
|
15849
|
+
log(`[dreamer] WARNING: dropping Pi model not found: ${model}`);
|
|
15850
|
+
warnedUnknownModels.add(model);
|
|
15851
|
+
}
|
|
15852
|
+
return false;
|
|
15853
|
+
});
|
|
15854
|
+
return {
|
|
15855
|
+
...task,
|
|
15856
|
+
model: valid[0],
|
|
15857
|
+
fallbackModels: valid.slice(1),
|
|
15858
|
+
modelChainUnavailable: entries.length > 0 && valid.length === 0
|
|
15859
|
+
};
|
|
15860
|
+
});
|
|
15861
|
+
}
|
|
15368
15862
|
var PI_DREAMER_PROJECTS = Symbol.for("magic-context.pi.dreamer-registered-projects");
|
|
15369
15863
|
function getRegisteredProjects() {
|
|
15370
15864
|
const globals = globalThis;
|
|
@@ -15393,7 +15887,8 @@ var sessionCounter = 0;
|
|
|
15393
15887
|
var piSubagentRunnerFactory = () => new PiSubagentRunner;
|
|
15394
15888
|
var startDreamScheduleTimerFn = startDreamScheduleTimer;
|
|
15395
15889
|
function registerPiDreamerProject(opts) {
|
|
15396
|
-
|
|
15890
|
+
const directory = resolve3(opts.projectDir);
|
|
15891
|
+
if (opts.config.disable === true || directory === parse(directory).root || directory === homedir2()) {
|
|
15397
15892
|
return;
|
|
15398
15893
|
}
|
|
15399
15894
|
const existing = registeredProjects2.get(opts.projectIdentity);
|
|
@@ -15406,7 +15901,7 @@ function registerPiDreamerProject(opts) {
|
|
|
15406
15901
|
callback(projectIdentity);
|
|
15407
15902
|
};
|
|
15408
15903
|
if (existing) {
|
|
15409
|
-
if (existing.generation && existing.projectDir === opts.projectDir) {
|
|
15904
|
+
if (existing.generation && existing.projectDir === opts.projectDir && (!opts.modelRegistry || existing.modelRegistry)) {
|
|
15410
15905
|
return;
|
|
15411
15906
|
}
|
|
15412
15907
|
existing.cleanup();
|
|
@@ -15419,12 +15914,14 @@ function registerPiDreamerProject(opts) {
|
|
|
15419
15914
|
});
|
|
15420
15915
|
let cleanup;
|
|
15421
15916
|
let cancelled = false;
|
|
15917
|
+
const modelRegistry = opts.modelRegistry;
|
|
15422
15918
|
startDreamScheduleTimerFn({
|
|
15423
15919
|
directory: opts.projectDir,
|
|
15424
15920
|
projectIdentity: opts.projectIdentity,
|
|
15425
15921
|
harness: opts.harness,
|
|
15426
15922
|
client,
|
|
15427
15923
|
dreamerConfig: opts.config,
|
|
15924
|
+
validateTaskModels: modelRegistry ? (tasks) => validatePiDreamerModels(tasks, modelRegistry) : undefined,
|
|
15428
15925
|
sampleDreamRun: opts.sampleDreamRun,
|
|
15429
15926
|
language: opts.language,
|
|
15430
15927
|
gitCommitIndexing: opts.gitCommitIndexing,
|
|
@@ -15456,7 +15953,7 @@ function registerPiDreamerProject(opts) {
|
|
|
15456
15953
|
const manualRun = runManualDream({
|
|
15457
15954
|
db: manualOpts.db,
|
|
15458
15955
|
projectIdentity: manualOpts.projectIdentity,
|
|
15459
|
-
tasks: buildDreamTaskRuntimeConfigs(dreamerConfig, manualOpts.harness, manualOpts.language, mural?.model),
|
|
15956
|
+
tasks: manualOpts.modelRegistry ? validatePiDreamerModels(buildDreamTaskRuntimeConfigs(dreamerConfig, manualOpts.harness, manualOpts.language, mural?.model), manualOpts.modelRegistry) : buildDreamTaskRuntimeConfigs(dreamerConfig, manualOpts.harness, manualOpts.language, mural?.model),
|
|
15460
15957
|
executor: createDreamTaskExecutor({
|
|
15461
15958
|
client: manualClient,
|
|
15462
15959
|
sessionDirectory: manualOpts.projectDir,
|
|
@@ -15489,7 +15986,8 @@ function registerPiDreamerProject(opts) {
|
|
|
15489
15986
|
cleanup?.();
|
|
15490
15987
|
},
|
|
15491
15988
|
runManual,
|
|
15492
|
-
projectDir: opts.projectDir
|
|
15989
|
+
projectDir: opts.projectDir,
|
|
15990
|
+
modelRegistry: opts.modelRegistry
|
|
15493
15991
|
});
|
|
15494
15992
|
}
|
|
15495
15993
|
async function runPiDreamForProject(projectIdentity, task, registrationOwner) {
|
|
@@ -16001,7 +16499,7 @@ function formatEmbedStatusText(coverage, drain) {
|
|
|
16001
16499
|
lines.push(`Synapse — ${formatSynapseLaneDescriptor(coverage.synapseDescriptor)}`);
|
|
16002
16500
|
}
|
|
16003
16501
|
lines.push(`This session: ${coverage.session.embedded} / ${coverage.session.total} compartments embedded`);
|
|
16004
|
-
lines.push(`Project memories: ${coverage.memories.embedded} / ${coverage.memories.total} embedded`);
|
|
16502
|
+
lines.push(coverage.memories.memoryEnabled === false ? "Project memories: off (memory disabled)" : `Project memories: ${coverage.memories.embedded} / ${coverage.memories.total} embedded`);
|
|
16005
16503
|
if (coverage.commits.gitEnabled) {
|
|
16006
16504
|
lines.push(`Git commits: ${coverage.commits.embedded} / ${coverage.commits.total}`);
|
|
16007
16505
|
} else {
|
|
@@ -16177,7 +16675,6 @@ No active Pi session is available.`,
|
|
|
16177
16675
|
projectDir: deps.projectDir,
|
|
16178
16676
|
projectIdentity: deps.projectIdentity
|
|
16179
16677
|
};
|
|
16180
|
-
const memoryEnabled = deps.resolveMemoryEnabled?.(ctx) ?? deps.memoryEnabled;
|
|
16181
16678
|
const sub = args.trim().toLowerCase();
|
|
16182
16679
|
if (sub === "pause") {
|
|
16183
16680
|
embedPauseBySession.add(sessionId);
|
|
@@ -16194,16 +16691,6 @@ Paused at ${cov.session.embedded}/${cov.session.total} compartments embedded.`,
|
|
|
16194
16691
|
});
|
|
16195
16692
|
return;
|
|
16196
16693
|
}
|
|
16197
|
-
if (memoryEnabled === false) {
|
|
16198
|
-
sendStatus({
|
|
16199
|
-
title: "/ctx-embed",
|
|
16200
|
-
text: `## /ctx-embed
|
|
16201
|
-
|
|
16202
|
-
Memory is disabled for this project, so there is no semantic embedding to backfill.`,
|
|
16203
|
-
level: "info"
|
|
16204
|
-
});
|
|
16205
|
-
return;
|
|
16206
|
-
}
|
|
16207
16694
|
await ensureProjectRegisteredFromPiDirectory(project.projectDir, deps.db);
|
|
16208
16695
|
if (sub === "start") {
|
|
16209
16696
|
const { text, level } = await runEmbedDrain(deps.db, project.projectIdentity, sessionId, {
|
|
@@ -16236,13 +16723,11 @@ ${statusText}`,
|
|
|
16236
16723
|
}
|
|
16237
16724
|
});
|
|
16238
16725
|
}
|
|
16239
|
-
function maybeAutoEmbedPiSession(deps, sessionId, projectDir, projectIdentity
|
|
16726
|
+
function maybeAutoEmbedPiSession(deps, sessionId, projectDir, projectIdentity) {
|
|
16240
16727
|
if (autoEmbedAttemptedBySession.has(sessionId))
|
|
16241
16728
|
return;
|
|
16242
16729
|
if (embedPauseBySession.has(sessionId))
|
|
16243
16730
|
return;
|
|
16244
|
-
if (deps.memoryEnabled === false)
|
|
16245
|
-
return;
|
|
16246
16731
|
autoEmbedAttemptedBySession.add(sessionId);
|
|
16247
16732
|
(async () => {
|
|
16248
16733
|
let drainReachedTerminal = false;
|
|
@@ -16278,7 +16763,7 @@ function executeFlush(db, sessionId) {
|
|
|
16278
16763
|
removePendingOp(db, sessionId, op.tagId);
|
|
16279
16764
|
dropped++;
|
|
16280
16765
|
}
|
|
16281
|
-
})();
|
|
16766
|
+
}).immediate();
|
|
16282
16767
|
const parts = [];
|
|
16283
16768
|
if (dropped > 0)
|
|
16284
16769
|
parts.push(`${dropped} dropped`);
|
|
@@ -16577,7 +17062,7 @@ function createTagger() {
|
|
|
16577
17062
|
db.transaction(() => {
|
|
16578
17063
|
getUpsertCounterStatement(db).run(sessionId, next, getHarness());
|
|
16579
17064
|
insertTag(db, sessionId, messageId, type, byteSize, next, reasoningByteSize, toolName, inputByteSize, toolOwnerMessageId, entryFingerprint, tokenCounts);
|
|
16580
|
-
})();
|
|
17065
|
+
}).immediate();
|
|
16581
17066
|
} catch (error) {
|
|
16582
17067
|
if (!isUniqueConstraintError(error)) {
|
|
16583
17068
|
throw error;
|
|
@@ -16813,7 +17298,8 @@ var canonicalReasons = new Set([
|
|
|
16813
17298
|
"ttl_expiry",
|
|
16814
17299
|
"epoch_change",
|
|
16815
17300
|
"coverage_fold",
|
|
16816
|
-
"profile_transition"
|
|
17301
|
+
"profile_transition",
|
|
17302
|
+
"host_compaction"
|
|
16817
17303
|
]);
|
|
16818
17304
|
var piReasonAliases = {
|
|
16819
17305
|
project_memory_change: "project_memory_epoch",
|
|
@@ -17047,6 +17533,72 @@ var RECENT_TOOL_SKELETON_WINDOW = 20;
|
|
|
17047
17533
|
function buildReplacementContent(tagId) {
|
|
17048
17534
|
return `[dropped §${tagId}§]`;
|
|
17049
17535
|
}
|
|
17536
|
+
function applyNewToolDrop(target, options) {
|
|
17537
|
+
if (!target)
|
|
17538
|
+
return { result: "absent", mode: "full" };
|
|
17539
|
+
if (options.inWindow && hasSmallToolInput(target) || options.keepSkeleton === true || target.cannotRemove?.() === true) {
|
|
17540
|
+
const strip = target.hasAttachments?.() === true;
|
|
17541
|
+
return {
|
|
17542
|
+
result: (strip ? target.skeletonStripped?.() : target.skeletonReal?.()) ?? "absent",
|
|
17543
|
+
mode: strip ? "skeleton_stripped" : "skeleton_real"
|
|
17544
|
+
};
|
|
17545
|
+
}
|
|
17546
|
+
const result = target.drop?.() ?? "absent";
|
|
17547
|
+
if (result === "truncated" && target.hasAttachments?.() === true) {
|
|
17548
|
+
return { result: target.skeletonStripped?.() ?? "absent", mode: "skeleton_stripped" };
|
|
17549
|
+
}
|
|
17550
|
+
return { result, mode: result === "truncated" ? "skeleton_real" : "full" };
|
|
17551
|
+
}
|
|
17552
|
+
function hasSmallToolInput(target) {
|
|
17553
|
+
const bytes = target?.inputStringBytes?.() ?? null;
|
|
17554
|
+
return bytes !== null && bytes <= SKELETON_REAL_INPUT_MAX_BYTES;
|
|
17555
|
+
}
|
|
17556
|
+
var CACHE_LOSING_FOLD_REASONS = new Set([
|
|
17557
|
+
"model_change",
|
|
17558
|
+
"system_hash",
|
|
17559
|
+
"ttl_idle",
|
|
17560
|
+
"host_compaction"
|
|
17561
|
+
]);
|
|
17562
|
+
function sameBytes(left, right) {
|
|
17563
|
+
if (left === null || right === null)
|
|
17564
|
+
return left === right;
|
|
17565
|
+
return Buffer.compare(Buffer.from(left), Buffer.from(right)) === 0;
|
|
17566
|
+
}
|
|
17567
|
+
function foldChangesServedPrefix(before, after) {
|
|
17568
|
+
if (!sameBytes(before.m0Bytes, after.m0Bytes))
|
|
17569
|
+
return true;
|
|
17570
|
+
if (!sameBytes(before.m1Bytes, after.m1Bytes))
|
|
17571
|
+
return true;
|
|
17572
|
+
return before.muralDataUrl !== after.muralDataUrl;
|
|
17573
|
+
}
|
|
17574
|
+
function foldBustsServedPrefix(reason, before, after) {
|
|
17575
|
+
return CACHE_LOSING_FOLD_REASONS.has(reason ?? "") || foldChangesServedPrefix(before, after);
|
|
17576
|
+
}
|
|
17577
|
+
function convertLegacyToolSkeletons(db, sessionId, targets) {
|
|
17578
|
+
const rows = db.prepare(`SELECT tag_number AS tagNumber, drop_mode AS dropMode
|
|
17579
|
+
FROM tags
|
|
17580
|
+
WHERE session_id = ? AND type = 'tool' AND status = 'dropped'
|
|
17581
|
+
AND drop_mode IN ('truncated', 'full')
|
|
17582
|
+
ORDER BY tag_number`).all(sessionId);
|
|
17583
|
+
const converted = new Map;
|
|
17584
|
+
for (const row of rows) {
|
|
17585
|
+
const target = targets.get(row.tagNumber);
|
|
17586
|
+
if (target?.canDrop?.() !== true)
|
|
17587
|
+
continue;
|
|
17588
|
+
const cannotRemove = target.cannotRemove?.() === true || target.requiresToolArcSkeleton === true || target.wouldStrandConversationEnd?.() === true;
|
|
17589
|
+
let mode;
|
|
17590
|
+
if (row.dropMode === "full") {
|
|
17591
|
+
if (target.cannotRemove?.() !== true)
|
|
17592
|
+
continue;
|
|
17593
|
+
mode = "skeleton_real";
|
|
17594
|
+
} else {
|
|
17595
|
+
mode = hasSmallToolInput(target) || cannotRemove ? "skeleton_real" : "full";
|
|
17596
|
+
}
|
|
17597
|
+
updateTagDropMode(db, sessionId, row.tagNumber, mode);
|
|
17598
|
+
converted.set(row.tagNumber, mode);
|
|
17599
|
+
}
|
|
17600
|
+
return converted;
|
|
17601
|
+
}
|
|
17050
17602
|
function applyPendingOperations(sessionId, db, targets, protectedTagIds, preloadedTags, preloadedPendingOps, syntheticPendingOps = [], editMarkerTagIds = new Set, onTagReduced, onBatchComplete) {
|
|
17051
17603
|
let didMutateMessage = false;
|
|
17052
17604
|
let diagnostics;
|
|
@@ -17106,7 +17658,8 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
|
|
|
17106
17658
|
let shouldPersistDrop = false;
|
|
17107
17659
|
if (isToolTag) {
|
|
17108
17660
|
if (editMarkerTagIds.has(pendingOp.tagId)) {
|
|
17109
|
-
const
|
|
17661
|
+
const strip = target?.hasAttachments?.() === true;
|
|
17662
|
+
const markResult = (strip ? target?.editMarkerStripped?.() : target?.editMarker?.()) ?? "absent";
|
|
17110
17663
|
if (markResult === "incomplete" || markResult === "absent") {
|
|
17111
17664
|
reject(`edit_marker_${markResult}`);
|
|
17112
17665
|
continue;
|
|
@@ -17114,34 +17667,23 @@ function applyPendingOperations(sessionId, db, targets, protectedTagIds, preload
|
|
|
17114
17667
|
didMutateMessage = true;
|
|
17115
17668
|
operationMutated = true;
|
|
17116
17669
|
onTagReduced?.({ tagNumber: pendingOp.tagId, mode: "edit_marker" });
|
|
17117
|
-
updateTagDropMode(db, sessionId, pendingOp.tagId, "edit_marker");
|
|
17118
|
-
shouldPersistDrop = true;
|
|
17119
|
-
} else if (skeletonWindow.has(pendingOp.tagId)) {
|
|
17120
|
-
const truncResult = target?.truncate?.() ?? "absent";
|
|
17121
|
-
if (truncResult === "incomplete" || synthetic && truncResult !== "truncated") {
|
|
17122
|
-
reject(`truncate_${truncResult}`);
|
|
17123
|
-
continue;
|
|
17124
|
-
}
|
|
17125
|
-
if (truncResult === "truncated") {
|
|
17126
|
-
didMutateMessage = true;
|
|
17127
|
-
operationMutated = true;
|
|
17128
|
-
onTagReduced?.({ tagNumber: pendingOp.tagId, mode: "truncated" });
|
|
17129
|
-
} else {
|
|
17130
|
-
reject(`truncate_${truncResult}`);
|
|
17131
|
-
}
|
|
17132
|
-
updateTagDropMode(db, sessionId, pendingOp.tagId, "truncated");
|
|
17670
|
+
updateTagDropMode(db, sessionId, pendingOp.tagId, strip ? "edit_marker_stripped" : "edit_marker");
|
|
17133
17671
|
shouldPersistDrop = true;
|
|
17134
17672
|
} else {
|
|
17135
|
-
const dropResult = target
|
|
17673
|
+
const { result: dropResult, mode: appliedMode } = applyNewToolDrop(target, {
|
|
17674
|
+
inWindow: skeletonWindow.has(pendingOp.tagId)
|
|
17675
|
+
});
|
|
17136
17676
|
if (dropResult === "incomplete" || synthetic && dropResult !== "removed" && dropResult !== "truncated") {
|
|
17137
17677
|
reject(`drop_${dropResult}`);
|
|
17138
17678
|
continue;
|
|
17139
17679
|
}
|
|
17140
|
-
const appliedMode = dropResult === "truncated" ? "truncated" : "full";
|
|
17141
17680
|
if (dropResult === "removed" || dropResult === "truncated") {
|
|
17142
17681
|
didMutateMessage = true;
|
|
17143
17682
|
operationMutated = true;
|
|
17144
|
-
onTagReduced?.({
|
|
17683
|
+
onTagReduced?.({
|
|
17684
|
+
tagNumber: pendingOp.tagId,
|
|
17685
|
+
mode: appliedMode === "full" ? "full" : "truncated"
|
|
17686
|
+
});
|
|
17145
17687
|
} else {
|
|
17146
17688
|
reject(`drop_${dropResult}`);
|
|
17147
17689
|
}
|
|
@@ -17208,11 +17750,24 @@ function applyFlushedStatuses(sessionId, db, targets, preloadedTags) {
|
|
|
17208
17750
|
if (tag.status === "dropped") {
|
|
17209
17751
|
const target = targets.get(tag.tagNumber);
|
|
17210
17752
|
if (tag.type === "tool") {
|
|
17211
|
-
if (tag.dropMode === "
|
|
17753
|
+
if (tag.dropMode === "edit_marker_stripped") {
|
|
17754
|
+
const result = target?.editMarkerStripped?.() ?? "absent";
|
|
17755
|
+
if (result === "truncated")
|
|
17756
|
+
didMutateMessage = true;
|
|
17757
|
+
} else if (tag.dropMode === "edit_marker") {
|
|
17212
17758
|
const markResult = target?.editMarker?.() ?? "absent";
|
|
17213
17759
|
if (markResult === "truncated") {
|
|
17214
17760
|
didMutateMessage = true;
|
|
17215
17761
|
}
|
|
17762
|
+
} else if (tag.dropMode === "skeleton_stripped") {
|
|
17763
|
+
const result = target?.skeletonStripped?.() ?? "absent";
|
|
17764
|
+
if (result === "truncated")
|
|
17765
|
+
didMutateMessage = true;
|
|
17766
|
+
} else if (tag.dropMode === "skeleton_real") {
|
|
17767
|
+
const result = target?.skeletonReal?.() ?? "absent";
|
|
17768
|
+
if (result === "truncated") {
|
|
17769
|
+
didMutateMessage = true;
|
|
17770
|
+
}
|
|
17216
17771
|
} else if (tag.dropMode === "truncated") {
|
|
17217
17772
|
const truncResult = target?.truncate?.() ?? "absent";
|
|
17218
17773
|
if (truncResult === "truncated") {
|
|
@@ -17558,7 +18113,7 @@ function applyCavemanCleanup(sessionId, db, targets, tags, config) {
|
|
|
17558
18113
|
else if (targetDepth === DEPTH_ULTRA)
|
|
17559
18114
|
result.compressedToUltra += 1;
|
|
17560
18115
|
}
|
|
17561
|
-
})();
|
|
18116
|
+
}).immediate();
|
|
17562
18117
|
const total = result.compressedToLite + result.compressedToFull + result.compressedToUltra;
|
|
17563
18118
|
if (total > 0) {
|
|
17564
18119
|
sessionLog(sessionId, `caveman cleanup: compressed ${total} text tags (lite=${result.compressedToLite}, full=${result.compressedToFull}, ultra=${result.compressedToUltra})`);
|
|
@@ -19480,6 +20035,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19480
20035
|
let any = false;
|
|
19481
20036
|
for (const occ of occurrences) {
|
|
19482
20037
|
if (occ.kind === "tool_use" && occ.part.setToolInput) {
|
|
20038
|
+
occ.originalInput ??= occ.part.getToolInput?.() ?? undefined;
|
|
19483
20039
|
if (occ.part.setToolInput(droppedInputMarker(tagId)))
|
|
19484
20040
|
any = true;
|
|
19485
20041
|
} else if (setToolContentOrText(occ.part, sentinel)) {
|
|
@@ -19488,6 +20044,28 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19488
20044
|
}
|
|
19489
20045
|
return any ? "truncated" : "absent";
|
|
19490
20046
|
};
|
|
20047
|
+
const complete = () => occurrences.some((occ) => occ.kind === "tool_use") && occurrences.some((occ) => occ.kind === "tool_result");
|
|
20048
|
+
const skeletonReal = () => {
|
|
20049
|
+
if (!complete())
|
|
20050
|
+
return "incomplete";
|
|
20051
|
+
const sentinel = `[dropped §${tagId}§]`;
|
|
20052
|
+
let any = false;
|
|
20053
|
+
for (const occ of occurrences) {
|
|
20054
|
+
if (occ.kind === "tool_use") {
|
|
20055
|
+
if (occ.originalInput && occ.part.setToolInput?.(occ.originalInput))
|
|
20056
|
+
any = true;
|
|
20057
|
+
} else if (setToolContentOrText(occ.part, sentinel)) {
|
|
20058
|
+
any = true;
|
|
20059
|
+
}
|
|
20060
|
+
}
|
|
20061
|
+
return any ? "truncated" : "absent";
|
|
20062
|
+
};
|
|
20063
|
+
const cannotRemove = () => {
|
|
20064
|
+
if (requiresToolArcSkeleton)
|
|
20065
|
+
return true;
|
|
20066
|
+
const authorization = occurrences.map((occ) => occ.part.canRemove?.());
|
|
20067
|
+
return !occurrences.every((occ, index) => occ.part.remove && authorization[index] !== false);
|
|
20068
|
+
};
|
|
19491
20069
|
return {
|
|
19492
20070
|
measureReclaim(skeleton) {
|
|
19493
20071
|
let beforeTools = 0;
|
|
@@ -19498,7 +20076,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19498
20076
|
const before = occ.kind === "tool_use" ? JSON.stringify(occ.part.getToolInput?.() ?? {}) : occ.part.getText() ?? "";
|
|
19499
20077
|
beforeTools += estimateTokens(before);
|
|
19500
20078
|
if (skeleton || !removable) {
|
|
19501
|
-
const after = occ.kind === "tool_use" ?
|
|
20079
|
+
const after = occ.kind === "tool_use" ? before : `[dropped §${tagId}§]`;
|
|
19502
20080
|
afterTools += estimateTokens(after);
|
|
19503
20081
|
}
|
|
19504
20082
|
}
|
|
@@ -19527,8 +20105,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19527
20105
|
return occurrences[0]?.part.getText() ?? null;
|
|
19528
20106
|
},
|
|
19529
20107
|
drop() {
|
|
19530
|
-
|
|
19531
|
-
if (!complete)
|
|
20108
|
+
if (!complete())
|
|
19532
20109
|
return "incomplete";
|
|
19533
20110
|
if (!requiresToolArcSkeleton) {
|
|
19534
20111
|
const authorization = occurrences.map((occ) => occ.part.canRemove?.());
|
|
@@ -19536,7 +20113,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19536
20113
|
return "incomplete";
|
|
19537
20114
|
if (occurrences.every((occ, index) => occ.part.remove && authorization[index] !== false)) {
|
|
19538
20115
|
if (conversationEnd?.wouldStrand(occurrences))
|
|
19539
|
-
return
|
|
20116
|
+
return skeletonReal();
|
|
19540
20117
|
let removed = false;
|
|
19541
20118
|
for (const occ of occurrences)
|
|
19542
20119
|
removed = occ.part.remove?.() || removed;
|
|
@@ -19554,6 +20131,19 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19554
20131
|
return any ? "removed" : "absent";
|
|
19555
20132
|
},
|
|
19556
20133
|
truncate,
|
|
20134
|
+
skeletonReal,
|
|
20135
|
+
cannotRemove,
|
|
20136
|
+
inputStringBytes() {
|
|
20137
|
+
for (const occ of occurrences) {
|
|
20138
|
+
if (occ.kind !== "tool_use")
|
|
20139
|
+
continue;
|
|
20140
|
+
return toolInputStringBytes(occ.originalInput ?? occ.part.getToolInput?.() ?? null);
|
|
20141
|
+
}
|
|
20142
|
+
return null;
|
|
20143
|
+
},
|
|
20144
|
+
wouldStrandConversationEnd() {
|
|
20145
|
+
return conversationEnd?.wouldStrand(occurrences) ?? false;
|
|
20146
|
+
},
|
|
19557
20147
|
editMarker() {
|
|
19558
20148
|
const sentinel = `[dropped §${tagId}§]`;
|
|
19559
20149
|
let any = false;
|
|
@@ -19572,9 +20162,7 @@ function buildAggregateTarget(tagId, occurrences, requiresToolArcSkeleton, conve
|
|
|
19572
20162
|
}
|
|
19573
20163
|
return any ? "truncated" : "absent";
|
|
19574
20164
|
},
|
|
19575
|
-
canDrop
|
|
19576
|
-
return occurrences.some((occ) => occ.kind === "tool_use") && occurrences.some((occ) => occ.kind === "tool_result");
|
|
19577
|
-
},
|
|
20165
|
+
canDrop: complete,
|
|
19578
20166
|
requiresToolArcSkeleton,
|
|
19579
20167
|
readInput() {
|
|
19580
20168
|
for (const occ of occurrences) {
|
|
@@ -19620,6 +20208,15 @@ function buildToolTarget(part, message, tagId) {
|
|
|
19620
20208
|
const changed = part.setToolInput ? part.setToolInput(droppedInputMarker(tagId)) : setToolContentOrText(part, `[dropped §${tagId}§]`);
|
|
19621
20209
|
return changed ? "truncated" : "absent";
|
|
19622
20210
|
},
|
|
20211
|
+
skeletonReal() {
|
|
20212
|
+
if (part.setToolInput)
|
|
20213
|
+
return "truncated";
|
|
20214
|
+
return setToolContentOrText(part, `[dropped §${tagId}§]`) ? "truncated" : "absent";
|
|
20215
|
+
},
|
|
20216
|
+
cannotRemove: () => part.setToolInput !== undefined,
|
|
20217
|
+
inputStringBytes() {
|
|
20218
|
+
return part.setToolInput ? toolInputStringBytes(part.getToolInput?.() ?? null) : 0;
|
|
20219
|
+
},
|
|
19623
20220
|
message: {
|
|
19624
20221
|
info: { id: message.info.id, role: message.info.role },
|
|
19625
20222
|
parts: []
|
|
@@ -19893,7 +20490,7 @@ async function runAutoSearchHintForPi(args) {
|
|
|
19893
20490
|
try {
|
|
19894
20491
|
const snapshot = getProjectEmbeddingSnapshot(options.projectPath);
|
|
19895
20492
|
const memoryEnabled = snapshot?.features.memoryEnabled ?? true;
|
|
19896
|
-
const embeddingEnabled = snapshot ? snapshot.
|
|
20493
|
+
const embeddingEnabled = snapshot ? snapshot.historyEnabled : true;
|
|
19897
20494
|
const gitCommitsEnabled = snapshot?.gitCommitEnabled ?? false;
|
|
19898
20495
|
const searchOptions = {
|
|
19899
20496
|
limit: 10,
|
|
@@ -19957,6 +20554,8 @@ import * as crypto2 from "node:crypto";
|
|
|
19957
20554
|
async function embedAndStoreCompartmentChunks(db, sessionId, projectPath, compartments) {
|
|
19958
20555
|
if (compartments.length === 0)
|
|
19959
20556
|
return;
|
|
20557
|
+
if (getProjectChunkEmbeddingModelId(projectPath) === "off")
|
|
20558
|
+
return;
|
|
19960
20559
|
const maxInputTokens = getProjectEmbeddingMaxInputTokens(projectPath);
|
|
19961
20560
|
for (const compartment of compartments) {
|
|
19962
20561
|
try {
|
|
@@ -20113,7 +20712,7 @@ function persistFilteredNoise(db, sessionId, chunk, eligibleEnd) {
|
|
|
20113
20712
|
}
|
|
20114
20713
|
]);
|
|
20115
20714
|
return true;
|
|
20116
|
-
})();
|
|
20715
|
+
}).immediate();
|
|
20117
20716
|
if (saved)
|
|
20118
20717
|
sessionLog(sessionId, `historian skipped ordinals ${start}-${eligibleEnd - 1}: all ${rows.length} raw rows excluded by chunk filters (no-content boundary marker)`);
|
|
20119
20718
|
return saved;
|
|
@@ -22710,8 +23309,7 @@ ${chunkText}`,
|
|
|
22710
23309
|
const discardedLast = newCompartments.length < emittedCompartments.length;
|
|
22711
23310
|
const weakLookaheadFinalCompartment = forceKeepLastCompartmentForChunk;
|
|
22712
23311
|
const skipUnanchoredPromotion = discardedLast || weakLookaheadFinalCompartment;
|
|
22713
|
-
const
|
|
22714
|
-
const promotionActive = embeddingActive && autoPromote !== false;
|
|
23312
|
+
const promotionActive = memoryEnabled !== false && autoPromote !== false;
|
|
22715
23313
|
const publishableEvents = (validatedPass.events ?? []).filter((e) => {
|
|
22716
23314
|
if (typeof e.atCompartment !== "number")
|
|
22717
23315
|
return !weakLookaheadFinalCompartment;
|
|
@@ -22844,7 +23442,7 @@ ${chunkText}`,
|
|
|
22844
23442
|
sessionLog(sessionId, "failed to store primer candidates:", error);
|
|
22845
23443
|
}
|
|
22846
23444
|
}
|
|
22847
|
-
if (
|
|
23445
|
+
if (newCompartments.length > 0) {
|
|
22848
23446
|
const chunksToEmbed = newCompartments.map((c, i) => ({
|
|
22849
23447
|
id: persistedIds[i],
|
|
22850
23448
|
startMessage: c.startMessage,
|
|
@@ -23227,7 +23825,7 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
|
|
|
23227
23825
|
const candidateTags = tags.filter((t) => t.status === "active" && t.type === "tool" && targets.get(t.tagNumber)?.canDrop?.());
|
|
23228
23826
|
const recentTags = new Set(candidateTags.slice().sort((a, b) => b.tagNumber - a.tagNumber).slice(0, 20).map((tag) => tag.tagNumber));
|
|
23229
23827
|
const calibration = sessionDecisionCalibration(db, sessionId);
|
|
23230
|
-
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)));
|
|
23828
|
+
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))));
|
|
23231
23829
|
const byTag = new Map(activeTags.map((tag) => [tag.tagNumber, tag]));
|
|
23232
23830
|
const droppableTags = candidateTags.flatMap((tag) => {
|
|
23233
23831
|
const measured = byTag.get(tag.tagNumber);
|
|
@@ -23256,18 +23854,18 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
|
|
|
23256
23854
|
continue;
|
|
23257
23855
|
const target = targets.get(tag.tagNumber);
|
|
23258
23856
|
const recent = (emergency.usagePercentage ?? 0) < 95 && newestEmergencyTags.has(tag.tagNumber);
|
|
23259
|
-
const
|
|
23260
|
-
|
|
23261
|
-
|
|
23857
|
+
const { result, mode } = applyNewToolDrop(target, {
|
|
23858
|
+
inWindow: recent,
|
|
23859
|
+
keepSkeleton: target?.requiresToolArcSkeleton === true
|
|
23860
|
+
});
|
|
23262
23861
|
if (result === "removed" || result === "truncated") {
|
|
23263
|
-
const appliedMode = skeleton || result === "truncated" ? "truncated" : "full";
|
|
23264
23862
|
updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
|
|
23265
|
-
updateTagDropMode(db, sessionId, tag.tagNumber,
|
|
23863
|
+
updateTagDropMode(db, sessionId, tag.tagNumber, mode);
|
|
23266
23864
|
droppedTools++;
|
|
23267
23865
|
emergencyDroppedTools++;
|
|
23268
23866
|
droppedTokenReductions.push({
|
|
23269
23867
|
tagNumber: tag.tagNumber,
|
|
23270
|
-
mode:
|
|
23868
|
+
mode: mode === "full" ? "full" : "truncated"
|
|
23271
23869
|
});
|
|
23272
23870
|
}
|
|
23273
23871
|
}
|
|
@@ -23291,10 +23889,10 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
|
|
|
23291
23889
|
if (!matched)
|
|
23292
23890
|
continue;
|
|
23293
23891
|
const target = targets.get(tag.tagNumber);
|
|
23294
|
-
const result = target
|
|
23892
|
+
const { result, mode } = applyNewToolDrop(target, { inWindow: false });
|
|
23295
23893
|
if (result === "incomplete")
|
|
23296
23894
|
continue;
|
|
23297
|
-
updateTagDropMode(db, sessionId, tag.tagNumber,
|
|
23895
|
+
updateTagDropMode(db, sessionId, tag.tagNumber, mode);
|
|
23298
23896
|
updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
|
|
23299
23897
|
if (result === "removed" || result === "truncated") {
|
|
23300
23898
|
droppedStaleReduceCalls++;
|
|
@@ -23375,17 +23973,18 @@ function applyPiHeuristicCleanup(sessionId, db, targets, piMessages, config, pre
|
|
|
23375
23973
|
for (let i = 0;i < group.length - 1; i++) {
|
|
23376
23974
|
const tag = group[i];
|
|
23377
23975
|
const target = targets.get(tag.tagNumber);
|
|
23378
|
-
const result = target
|
|
23976
|
+
const { result, mode } = applyNewToolDrop(target, {
|
|
23977
|
+
inWindow: false
|
|
23978
|
+
});
|
|
23379
23979
|
if (result === "incomplete")
|
|
23380
23980
|
continue;
|
|
23381
|
-
|
|
23382
|
-
updateTagDropMode(db, sessionId, tag.tagNumber, appliedMode);
|
|
23981
|
+
updateTagDropMode(db, sessionId, tag.tagNumber, mode);
|
|
23383
23982
|
updateTagStatus(db, sessionId, tag.tagNumber, "dropped");
|
|
23384
23983
|
if (result === "removed" || result === "truncated") {
|
|
23385
23984
|
deduplicatedTools++;
|
|
23386
23985
|
droppedTokenReductions.push({
|
|
23387
23986
|
tagNumber: tag.tagNumber,
|
|
23388
|
-
mode:
|
|
23987
|
+
mode: mode === "full" ? "full" : "truncated"
|
|
23389
23988
|
});
|
|
23390
23989
|
}
|
|
23391
23990
|
}
|
|
@@ -26151,7 +26750,7 @@ function messageRole(message) {
|
|
|
26151
26750
|
const role = recordValue(message, "role");
|
|
26152
26751
|
return typeof role === "string" ? role : undefined;
|
|
26153
26752
|
}
|
|
26154
|
-
function
|
|
26753
|
+
function messageId2(message) {
|
|
26155
26754
|
const id = recordValue(messageInfo(message), "id") ?? recordValue(message, "id");
|
|
26156
26755
|
return typeof id === "string" && id.length > 0 ? id : null;
|
|
26157
26756
|
}
|
|
@@ -26284,7 +26883,7 @@ function validateLkgSeam(prefix, tail, providerKey) {
|
|
|
26284
26883
|
const calls = new Set;
|
|
26285
26884
|
const results = new Set;
|
|
26286
26885
|
for (const message of all) {
|
|
26287
|
-
const id =
|
|
26886
|
+
const id = messageId2(message);
|
|
26288
26887
|
if (id !== null) {
|
|
26289
26888
|
if (ids.has(id))
|
|
26290
26889
|
return false;
|
|
@@ -26827,6 +27426,56 @@ function resolvePiPressureSnapshot(args) {
|
|
|
26827
27426
|
...validInferredLimit ? { contextLimit: inferredLimit } : {}
|
|
26828
27427
|
};
|
|
26829
27428
|
}
|
|
27429
|
+
var estimateSetAsideLogged = new Set;
|
|
27430
|
+
function notePiUsageReadingUsed(sessionId) {
|
|
27431
|
+
estimateSetAsideLogged.delete(sessionId);
|
|
27432
|
+
}
|
|
27433
|
+
function entryUsageTokens(usage) {
|
|
27434
|
+
if (!usage || typeof usage !== "object")
|
|
27435
|
+
return 0;
|
|
27436
|
+
const u = usage;
|
|
27437
|
+
const n = (value) => typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
27438
|
+
return n(u.totalTokens) || n(u.input) + n(u.output) + n(u.cacheRead) + n(u.cacheWrite);
|
|
27439
|
+
}
|
|
27440
|
+
function isPiLiveUsageRawBranchEstimate(branchEntries) {
|
|
27441
|
+
if (!branchEntries)
|
|
27442
|
+
return false;
|
|
27443
|
+
for (let index = branchEntries.length - 1;index >= 0; index -= 1) {
|
|
27444
|
+
const entry = branchEntries[index];
|
|
27445
|
+
if (!entry || typeof entry !== "object")
|
|
27446
|
+
continue;
|
|
27447
|
+
if (entry.type === "context_edit" || entry.type === "compaction")
|
|
27448
|
+
return true;
|
|
27449
|
+
if (entry.type !== "message")
|
|
27450
|
+
continue;
|
|
27451
|
+
const message = entry.message;
|
|
27452
|
+
if (message?.role === "assistant" && message.stopReason !== "aborted" && message.stopReason !== "error" && entryUsageTokens(message.usage) > 0) {
|
|
27453
|
+
return false;
|
|
27454
|
+
}
|
|
27455
|
+
}
|
|
27456
|
+
return false;
|
|
27457
|
+
}
|
|
27458
|
+
function noteRawBranchEstimateSetAside(sessionId, reading, source) {
|
|
27459
|
+
if (estimateSetAsideLogged.has(sessionId))
|
|
27460
|
+
return;
|
|
27461
|
+
estimateSetAsideLogged.add(sessionId);
|
|
27462
|
+
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`);
|
|
27463
|
+
}
|
|
27464
|
+
function resolvePiPressureSnapshotWithEstimateGuard(args) {
|
|
27465
|
+
const live = typeof args.liveInputTokens === "number" && Number.isFinite(args.liveInputTokens) ? args.liveInputTokens : 0;
|
|
27466
|
+
const setAsideEstimate = args.liveIsRawBranchEstimate === true && live > 0;
|
|
27467
|
+
const snapshot = resolvePiPressureSnapshot(setAsideEstimate ? {
|
|
27468
|
+
...args,
|
|
27469
|
+
liveInputTokens: undefined,
|
|
27470
|
+
...args.persistedFromLive ? { persistedInputTokens: 0, persistedPercentage: 0 } : {}
|
|
27471
|
+
} : args);
|
|
27472
|
+
if (setAsideEstimate) {
|
|
27473
|
+
noteRawBranchEstimateSetAside(args.sessionId, live, args.source);
|
|
27474
|
+
} else if (snapshot.inputTokens > 0) {
|
|
27475
|
+
notePiUsageReadingUsed(args.sessionId);
|
|
27476
|
+
}
|
|
27477
|
+
return snapshot;
|
|
27478
|
+
}
|
|
26830
27479
|
function formatPiPressureForLog(snapshot) {
|
|
26831
27480
|
return `usage=${snapshot.percentage.toFixed(1)}% (${snapshot.inputTokens} tokens, limit=${snapshot.contextLimit ?? "?"})`;
|
|
26832
27481
|
}
|
|
@@ -27283,12 +27932,12 @@ function handlePiProviderFailure(args) {
|
|
|
27283
27932
|
const model = typeof message.model === "string" ? message.model : undefined;
|
|
27284
27933
|
const binding = detectThinkingBindingMismatch(message.errorMessage);
|
|
27285
27934
|
if (binding.isBindingMismatch) {
|
|
27286
|
-
const enabled = args.thinkingBindingRecoveryEnabled !== false && !args.compactionOff &&
|
|
27935
|
+
const enabled = args.thinkingBindingRecoveryEnabled !== false && !args.compactionOff && isPrefixBoundThinkingModel(provider, model);
|
|
27287
27936
|
if (enabled) {
|
|
27288
27937
|
armThinkingBindingRecovery(args.db, args.sessionId);
|
|
27289
27938
|
clearPiLkgSessionState(args.sessionId);
|
|
27290
27939
|
dropSlot(args.sessionId, "thinking-binding-recovery-arm");
|
|
27291
|
-
reportBindingRecovery(args.sessionId, args.report, `
|
|
27940
|
+
reportBindingRecovery(args.sessionId, args.report, `thinking-binding recovery armed from message_end (provider paths: failing=${binding.failingBlockPath ?? "?"} firstChanged=${binding.firstChangedPath ?? "?"})`);
|
|
27292
27941
|
}
|
|
27293
27942
|
return { kind: "thinking_binding", armed: enabled };
|
|
27294
27943
|
}
|
|
@@ -27337,36 +27986,25 @@ function stripThinkingParts(message) {
|
|
|
27337
27986
|
function applyPiThinkingBindingRecovery(args) {
|
|
27338
27987
|
if (args.provider?.toLowerCase() !== "anthropic")
|
|
27339
27988
|
return null;
|
|
27340
|
-
const frozenEntryIds =
|
|
27341
|
-
|
|
27342
|
-
if (!frozenId.startsWith(THINKING_BINDING_RECOVERY_FROZEN_PREFIX))
|
|
27343
|
-
continue;
|
|
27344
|
-
const entryId = frozenId.slice(THINKING_BINDING_RECOVERY_FROZEN_PREFIX.length);
|
|
27345
|
-
if (entryId.length > 0)
|
|
27346
|
-
frozenEntryIds.add(entryId);
|
|
27347
|
-
}
|
|
27348
|
-
const flagTarget = isFable51ThinkingBindingModel(args.provider, args.model) ? getThinkingBindingRecoveryTarget(args.db, args.sessionId) : null;
|
|
27989
|
+
const frozenEntryIds = frozenBindingEntryIds(args.db, args.sessionId);
|
|
27990
|
+
const flagTarget = isPrefixBoundThinkingModel(args.provider, args.model) ? getThinkingBindingRecoveryTarget(args.db, args.sessionId) : null;
|
|
27349
27991
|
let applied = null;
|
|
27350
27992
|
if (flagTarget) {
|
|
27351
|
-
|
|
27352
|
-
|
|
27353
|
-
|
|
27354
|
-
|
|
27355
|
-
|
|
27356
|
-
|
|
27357
|
-
|
|
27358
|
-
|
|
27359
|
-
|
|
27360
|
-
|
|
27361
|
-
|
|
27362
|
-
|
|
27363
|
-
|
|
27364
|
-
|
|
27365
|
-
|
|
27366
|
-
frozenEntryIds.add(entryId);
|
|
27367
|
-
applied = { flagTarget, entryId };
|
|
27368
|
-
reportBindingRecovery(args.sessionId, args.report, `Fable thinking-binding recovery consumed on context pass target=${flagTarget} entry=${entryId}`);
|
|
27369
|
-
}
|
|
27993
|
+
const entryIds = new Set;
|
|
27994
|
+
for (let index = 0;index < args.messages.length; index += 1) {
|
|
27995
|
+
const entryId = args.entryIds[index];
|
|
27996
|
+
if (entryId && hasThinkingPart(args.messages[index]))
|
|
27997
|
+
entryIds.add(entryId);
|
|
27998
|
+
}
|
|
27999
|
+
const newEntryIds = [...entryIds].filter((id) => !frozenEntryIds.has(id));
|
|
28000
|
+
if (newEntryIds.length === 0 || addMergedReasoningStrippedIds(args.db, args.sessionId, [
|
|
28001
|
+
...newEntryIds.map(thinkingBindingRecoveryFrozenId),
|
|
28002
|
+
...args.endOfPassOrder ? [THINKING_BINDING_STRIP_ORDER_END_MARKER] : []
|
|
28003
|
+
])) {
|
|
28004
|
+
for (const id of newEntryIds)
|
|
28005
|
+
frozenEntryIds.add(id);
|
|
28006
|
+
applied = { flagTarget, entryIds: [...entryIds] };
|
|
28007
|
+
reportBindingRecovery(args.sessionId, args.report, `thinking-binding recovery consumed on context pass target=${flagTarget} entries=${applied.entryIds.length} [${applied.entryIds.join(",")}]`);
|
|
27370
28008
|
}
|
|
27371
28009
|
}
|
|
27372
28010
|
for (let index = 0;index < args.messages.length; index += 1) {
|
|
@@ -27376,6 +28014,76 @@ function applyPiThinkingBindingRecovery(args) {
|
|
|
27376
28014
|
}
|
|
27377
28015
|
return applied;
|
|
27378
28016
|
}
|
|
28017
|
+
function applyPiProactiveThinkingStrip(args) {
|
|
28018
|
+
if (!args.cacheBustingPass)
|
|
28019
|
+
return null;
|
|
28020
|
+
if (!isPrefixBoundThinkingModel(args.provider, args.model))
|
|
28021
|
+
return null;
|
|
28022
|
+
const entryIds = [];
|
|
28023
|
+
const indices = [];
|
|
28024
|
+
for (let index = 0;index < args.messages.length; index += 1) {
|
|
28025
|
+
const entryId = args.entryIds[index];
|
|
28026
|
+
if (!entryId || !hasThinkingPart(args.messages[index]))
|
|
28027
|
+
continue;
|
|
28028
|
+
entryIds.push(entryId);
|
|
28029
|
+
indices.push(index);
|
|
28030
|
+
}
|
|
28031
|
+
if (entryIds.length === 0)
|
|
28032
|
+
return null;
|
|
28033
|
+
let persisted = false;
|
|
28034
|
+
try {
|
|
28035
|
+
persisted = addMergedReasoningStrippedIds(args.db, args.sessionId, [
|
|
28036
|
+
...entryIds.map(thinkingBindingRecoveryFrozenId),
|
|
28037
|
+
THINKING_BINDING_STRIP_ORDER_END_MARKER
|
|
28038
|
+
]);
|
|
28039
|
+
} catch {
|
|
28040
|
+
persisted = false;
|
|
28041
|
+
}
|
|
28042
|
+
if (!persisted) {
|
|
28043
|
+
reportBindingRecovery(args.sessionId, args.report, "proactive thinking strip: persistence failed; serving the thinking unchanged");
|
|
28044
|
+
return null;
|
|
28045
|
+
}
|
|
28046
|
+
for (const index of indices)
|
|
28047
|
+
stripThinkingParts(args.messages[index]);
|
|
28048
|
+
reportBindingRecovery(args.sessionId, args.report, `proactive thinking strip: busting pass froze thinking of ${entryIds.length} entr${entryIds.length === 1 ? "y" : "ies"} [${entryIds.join(",")}]`);
|
|
28049
|
+
return { entryIds };
|
|
28050
|
+
}
|
|
28051
|
+
function frozenBindingEntryIds(db, sessionId) {
|
|
28052
|
+
const ids = new Set;
|
|
28053
|
+
for (const entry of getMergedReasoningStrippedIds(db, sessionId)) {
|
|
28054
|
+
if (!entry.startsWith(THINKING_BINDING_RECOVERY_FROZEN_PREFIX))
|
|
28055
|
+
continue;
|
|
28056
|
+
const entryId = entry.slice(THINKING_BINDING_RECOVERY_FROZEN_PREFIX.length);
|
|
28057
|
+
if (entryId.length > 0)
|
|
28058
|
+
ids.add(entryId);
|
|
28059
|
+
}
|
|
28060
|
+
return ids;
|
|
28061
|
+
}
|
|
28062
|
+
function resolvePiBindingStripOrder(args) {
|
|
28063
|
+
const ledger = getMergedReasoningStrippedIds(args.db, args.sessionId);
|
|
28064
|
+
if (ledger.has(THINKING_BINDING_STRIP_ORDER_END_MARKER))
|
|
28065
|
+
return "end";
|
|
28066
|
+
const frozen = frozenBindingEntryIds(args.db, args.sessionId);
|
|
28067
|
+
if (frozen.size === 0)
|
|
28068
|
+
return "end";
|
|
28069
|
+
let onBranch = false;
|
|
28070
|
+
let carriesThinking = false;
|
|
28071
|
+
for (let index = 0;index < args.messages.length; index += 1) {
|
|
28072
|
+
const entryId = args.entryIds[index];
|
|
28073
|
+
if (!entryId || !frozen.has(entryId))
|
|
28074
|
+
continue;
|
|
28075
|
+
onBranch = true;
|
|
28076
|
+
if (hasThinkingPart(args.messages[index]))
|
|
28077
|
+
carriesThinking = true;
|
|
28078
|
+
}
|
|
28079
|
+
const mayChangeOrder = onBranch && carriesThinking && args.bustPermittedAtStart;
|
|
28080
|
+
if (mayChangeOrder && addMergedReasoningStrippedIds(args.db, args.sessionId, [
|
|
28081
|
+
THINKING_BINDING_STRIP_ORDER_END_MARKER
|
|
28082
|
+
])) {
|
|
28083
|
+
return "end";
|
|
28084
|
+
}
|
|
28085
|
+
return "start";
|
|
28086
|
+
}
|
|
27379
28087
|
|
|
27380
28088
|
// src/reasoning-replay-pi.ts
|
|
27381
28089
|
var INLINE_THINKING_PATTERNS = [
|
|
@@ -27923,9 +28631,9 @@ var BASE_INTRO = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `#
|
|
|
27923
28631
|
|
|
27924
28632
|
Think of your context as a desk. Every message and every tool output lands on it, and each item arrives with a §N§ tag (§1§, §42§) — the tag is the item's handle.
|
|
27925
28633
|
|
|
27926
|
-
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.
|
|
28634
|
+
When an item no longer needs to stay on the desk for the work ahead, stamp it: \`ctx_reduce\` with its tag. Stamping does not remove anything — the item stays on the desk, fully readable. From time to time, when stamped items have piled up and the desk needs room, Magic Context clears them all in one sweep; you don't pick the moment, you only stamp. Stamp as soon as an item has served its purpose, not at the end of the turn, and do it silently: nobody wants to read "I'll drop these outputs". An output is used once you've taken what you need from it into your reasoning or your answer. Never stamp a user message for what it asks of you; a large paste inside one is fine once you have used it.
|
|
27927
28635
|
|
|
27928
|
-
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
|
|
28636
|
+
Nothing stamped is ever lost. A cleared item goes to the archive — a recent one leaves a \`[dropped §N§]\` placeholder on the desk, an older one leaves nothing — and \`ctx_expand(message=N)\` brings it back whole: text, tool input, tool output. Now and then Magic Context leaves a short reminder on the desk saying how much unstamped material is lying around. A reminder means stamping is overdue: act on it in your next step. It isn't a warning about the desk's size. The desk never gets smaller for it.
|
|
27929
28637
|
|
|
27930
28638
|
${TOOL_HISTORY_GUIDANCE}
|
|
27931
28639
|
|
|
@@ -27954,7 +28662,7 @@ var SMART_NOTE_GUIDANCE_LIGHT = `; a \`surface_condition\` leaves the note with
|
|
|
27954
28662
|
var TEMPORAL_AWARENESS_GUIDANCE_LIGHT = `, \`<!-- +Xm -->\` (time since your last reply)`;
|
|
27955
28663
|
var BASE_INTRO_LIGHT = (memoryEnabled, dreamerEnabled, temporalAwarenessEnabled) => `### Your desk
|
|
27956
28664
|
|
|
27957
|
-
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
|
|
28665
|
+
Your context is a desk. Every message and tool output lands on it with a §N§ tag as its handle. When an item no longer needs to stay for the work ahead, stamp it: \`ctx_reduce\` with its tag. Stamping removes nothing — the item stays readable; from time to time, when stamped items have piled up and the desk needs room, Magic Context clears them in one sweep (you only stamp, you don't pick the moment). Stamp as soon as an item has served its purpose, silently; never stamp a user message for what it asks (a used paste inside one is fine). An output is used once you've taken what you need from it into your reasoning or your answer. Nothing is lost: a cleared item goes to the archive (a recent one leaves \`[dropped §N§]\`, an older one nothing) and \`ctx_expand(message=N)\` brings it back whole. Occasional reminders about unstamped material may appear. A reminder means stamping is overdue: act on it in your next step. It isn't a warning about the desk's size. The desk never gets smaller.
|
|
27958
28666
|
|
|
27959
28667
|
${TOOL_HISTORY_GUIDANCE_LIGHT}
|
|
27960
28668
|
|
|
@@ -29437,7 +30145,7 @@ function databaseIsInTransaction(db) {
|
|
|
29437
30145
|
}
|
|
29438
30146
|
function runImmediateTransaction(db, fn) {
|
|
29439
30147
|
if (databaseIsInTransaction(db)) {
|
|
29440
|
-
return db.transaction(fn)();
|
|
30148
|
+
return db.transaction(fn).immediate();
|
|
29441
30149
|
}
|
|
29442
30150
|
const transactionStartedAt = performance.now();
|
|
29443
30151
|
db.exec("BEGIN IMMEDIATE");
|
|
@@ -29619,6 +30327,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
29619
30327
|
logTransformTiming(sessionId, "findSessionId", tFindSession, `messages=${event.messages.length}`);
|
|
29620
30328
|
const tEntryBranch = performance.now();
|
|
29621
30329
|
const branchEntries = readPiBranchEntriesForContext(ctx, sessionId);
|
|
30330
|
+
const piLiveUsageIsRawBranchEstimate = isPiLiveUsageRawBranchEstimate(branchEntries);
|
|
29622
30331
|
schedulePiTransformDecisionResolve({
|
|
29623
30332
|
db: options.db,
|
|
29624
30333
|
sessionId,
|
|
@@ -29651,14 +30360,29 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
29651
30360
|
const lkgInputIdByRef = new Map;
|
|
29652
30361
|
for (const input of lkgPassSnapshot.inputs)
|
|
29653
30362
|
lkgInputIdByRef.set(event.messages[input.messageIndex], input.id);
|
|
29654
|
-
const
|
|
30363
|
+
const bindingStripOrder = resolvePiBindingStripOrder({
|
|
30364
|
+
db: options.db,
|
|
30365
|
+
sessionId,
|
|
30366
|
+
messages: event.messages,
|
|
30367
|
+
entryIds: lkgEntryIds ?? [],
|
|
30368
|
+
bustPermittedAtStart: hasPendingMaterialization(sessionId)
|
|
30369
|
+
});
|
|
30370
|
+
const startOfPassBindingRecovery = bindingStripOrder === "start" ? applyPiThinkingBindingRecovery({
|
|
29655
30371
|
db: options.db,
|
|
29656
30372
|
sessionId,
|
|
29657
30373
|
messages: event.messages,
|
|
29658
30374
|
entryIds: lkgEntryIds ?? [],
|
|
29659
30375
|
provider: lkgProviderKey ?? undefined,
|
|
29660
30376
|
model: ctx.model?.id
|
|
29661
|
-
});
|
|
30377
|
+
}) : null;
|
|
30378
|
+
const bindingEntryIdByRef = new Map;
|
|
30379
|
+
if (lkgEntryIds) {
|
|
30380
|
+
for (let index = 0;index < event.messages.length; index += 1) {
|
|
30381
|
+
const entryId = lkgEntryIds[index];
|
|
30382
|
+
if (entryId)
|
|
30383
|
+
bindingEntryIdByRef.set(event.messages[index], entryId);
|
|
30384
|
+
}
|
|
30385
|
+
}
|
|
29662
30386
|
const tMeta = performance.now();
|
|
29663
30387
|
const sessionMetaForUsage = getOrCreateSessionMeta(options.db, sessionId);
|
|
29664
30388
|
sessionMetaForPass = sessionMetaForUsage;
|
|
@@ -29868,7 +30592,11 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
29868
30592
|
if (!usedPersistedUsage && isSaneLimit(usageContextLimit) && usageInputTokens > 0) {
|
|
29869
30593
|
usagePercentage = usageInputTokens / usageContextLimit * 100;
|
|
29870
30594
|
}
|
|
29871
|
-
({ percentage: usagePercentage, inputTokens: usageInputTokens } =
|
|
30595
|
+
({ percentage: usagePercentage, inputTokens: usageInputTokens } = resolvePiPressureSnapshotWithEstimateGuard({
|
|
30596
|
+
sessionId,
|
|
30597
|
+
source: "transform",
|
|
30598
|
+
liveIsRawBranchEstimate: piLiveUsageIsRawBranchEstimate,
|
|
30599
|
+
persistedFromLive: !usedPersistedUsage,
|
|
29872
30600
|
persistedPercentage: usagePercentage,
|
|
29873
30601
|
persistedInputTokens: usageInputTokens,
|
|
29874
30602
|
liveInputTokens: piUsage?.tokens,
|
|
@@ -30046,6 +30774,7 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
30046
30774
|
sessionMeta,
|
|
30047
30775
|
piUsage,
|
|
30048
30776
|
minimumPercentage: usagePercentage,
|
|
30777
|
+
liveIsRawBranchEstimate: piLiveUsageIsRawBranchEstimate,
|
|
30049
30778
|
historianStateSnapshot: historianStateForPass,
|
|
30050
30779
|
publishedHistoryRide: isCacheBusting
|
|
30051
30780
|
});
|
|
@@ -30123,6 +30852,34 @@ function registerPiContextHandler(pi, baseOptions) {
|
|
|
30123
30852
|
sessionLog(sessionId, `synthetic todowrite injection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
30124
30853
|
}
|
|
30125
30854
|
logTransformTiming(sessionId, "todoCapture", tTodoCapture);
|
|
30855
|
+
const tThinkingBinding = performance.now();
|
|
30856
|
+
const outputEntryIds = resolvePiLkgOutputEntryIds(outputMessages, result.syntheticLeadingCount, (message) => result.lkgEntryIdByRef.get(message) ?? result.postCommitEntryIdByRef.get(message) ?? bindingEntryIdByRef.get(message)).map((entryId) => entryId ?? undefined);
|
|
30857
|
+
const thinkingBindingRecoveryApplied = bindingStripOrder === "end" ? applyPiThinkingBindingRecovery({
|
|
30858
|
+
db: options.db,
|
|
30859
|
+
sessionId,
|
|
30860
|
+
messages: outputMessages,
|
|
30861
|
+
entryIds: outputEntryIds,
|
|
30862
|
+
provider: lkgProviderKey ?? undefined,
|
|
30863
|
+
model: ctx.model?.id,
|
|
30864
|
+
endOfPassOrder: true
|
|
30865
|
+
}) : startOfPassBindingRecovery;
|
|
30866
|
+
if (!options.compactionOff && !sessionMeta.isSubagent && bindingStripOrder === "end") {
|
|
30867
|
+
try {
|
|
30868
|
+
applyPiProactiveThinkingStrip({
|
|
30869
|
+
db: options.db,
|
|
30870
|
+
sessionId,
|
|
30871
|
+
messages: outputMessages,
|
|
30872
|
+
entryIds: outputEntryIds,
|
|
30873
|
+
provider: lkgProviderKey ?? undefined,
|
|
30874
|
+
model: ctx.model?.id,
|
|
30875
|
+
cacheBustingPass: isCacheBusting || result.executedWorkThisPass,
|
|
30876
|
+
report: (line) => sessionLog(sessionId, line)
|
|
30877
|
+
});
|
|
30878
|
+
} catch (err) {
|
|
30879
|
+
sessionLog(sessionId, `proactive thinking strip failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
30880
|
+
}
|
|
30881
|
+
}
|
|
30882
|
+
logTransformTiming(sessionId, "thinkingBinding", tThinkingBinding);
|
|
30126
30883
|
const tChannelAccounting = performance.now();
|
|
30127
30884
|
try {
|
|
30128
30885
|
const sessionMetaForCh1 = sessionMeta;
|
|
@@ -30602,7 +31359,11 @@ function maybeFireHistorian(args) {
|
|
|
30602
31359
|
};
|
|
30603
31360
|
usageSource = "piUsage fallback";
|
|
30604
31361
|
}
|
|
30605
|
-
usage =
|
|
31362
|
+
usage = resolvePiPressureSnapshotWithEstimateGuard({
|
|
31363
|
+
sessionId,
|
|
31364
|
+
source: "historian trigger",
|
|
31365
|
+
liveIsRawBranchEstimate: args.liveIsRawBranchEstimate,
|
|
31366
|
+
persistedFromLive: usageSource === "piUsage fallback",
|
|
30606
31367
|
persistedPercentage: usage.percentage,
|
|
30607
31368
|
persistedInputTokens: usage.inputTokens,
|
|
30608
31369
|
liveInputTokens: piUsage?.tokens,
|
|
@@ -30925,6 +31686,7 @@ async function runPipeline(args) {
|
|
|
30925
31686
|
const foldDueDecision = piM0State ? mustMaterializePi(piM0State, args.db, injectionPassSnapshot?.compartments, injectionPassSnapshot) : { value: false, reason: null };
|
|
30926
31687
|
const firstRenderBust = piM0State !== undefined && !(injectionPassSnapshot?.cachedRow?.cached_m0_bytes && injectionPassSnapshot.cachedRow.cached_m1_bytes);
|
|
30927
31688
|
let foldExecutedThisPass = false;
|
|
31689
|
+
let foldBustsServedPrefixThisPass = false;
|
|
30928
31690
|
let publishedM1RefreshedThisPass = false;
|
|
30929
31691
|
let prefixPreflightContended = false;
|
|
30930
31692
|
const softRefreshOpportunity = args.schedulerDecision === "execute";
|
|
@@ -30938,6 +31700,18 @@ async function runPipeline(args) {
|
|
|
30938
31700
|
prefixPreflightContended = preFoldInjectionResult.contentionExhausted === true;
|
|
30939
31701
|
publishedM1RefreshedThisPass = !prefixPreflightContended && persistedM0BeforeFold.cachedM1Bytes?.toString("utf8") !== getOrCreateSessionMeta(args.db, args.sessionId).cachedM1Bytes?.toString("utf8");
|
|
30940
31702
|
foldExecutedThisPass = foldExecutesThisPass(foldDueDecision.value || softRefreshOpportunity, preFoldInjectionResult.m0Materialized === true);
|
|
31703
|
+
if (foldExecutedThisPass) {
|
|
31704
|
+
const afterFold = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
31705
|
+
foldBustsServedPrefixThisPass = foldBustsServedPrefix(foldDueDecision.reason, {
|
|
31706
|
+
m0Bytes: persistedM0BeforeFold.cachedM0Bytes ?? null,
|
|
31707
|
+
m1Bytes: persistedM0BeforeFold.cachedM1Bytes ?? null,
|
|
31708
|
+
muralDataUrl: persistedM0BeforeFold.cachedM0MuralDataUrl ?? null
|
|
31709
|
+
}, {
|
|
31710
|
+
m0Bytes: afterFold.cachedM0Bytes ?? null,
|
|
31711
|
+
m1Bytes: afterFold.cachedM1Bytes ?? null,
|
|
31712
|
+
muralDataUrl: afterFold.cachedM0MuralDataUrl ?? null
|
|
31713
|
+
});
|
|
31714
|
+
}
|
|
30941
31715
|
if (preFoldInjectionResult.m0Materialized) {
|
|
30942
31716
|
injectionPassSnapshot = createPiM0M1PassSnapshot({
|
|
30943
31717
|
db: args.db,
|
|
@@ -30965,7 +31739,7 @@ async function runPipeline(args) {
|
|
|
30965
31739
|
sessionLog(args.sessionId, `pi m[0] HARD fold pre-execution failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
30966
31740
|
}
|
|
30967
31741
|
const mismatch = foldDueDecision.mismatch ? ` mismatch=${JSON.stringify(foldDueDecision.mismatch)}` : "";
|
|
30968
|
-
sessionLog(args.sessionId, `pi m[0] HARD fold decision: reason=${foldDueDecision.reason ?? "unknown"}${mismatch} executed=${foldExecutedThisPass}`);
|
|
31742
|
+
sessionLog(args.sessionId, `pi m[0] HARD fold decision: reason=${foldDueDecision.reason ?? "unknown"}${mismatch} executed=${foldExecutedThisPass} bustsServedPrefix=${foldBustsServedPrefixThisPass}`);
|
|
30969
31743
|
}
|
|
30970
31744
|
const executePressureEligible = args.schedulerDecision === "execute" || emergencyDropEligible;
|
|
30971
31745
|
if (!executePressureEligible) {
|
|
@@ -30976,7 +31750,7 @@ async function runPipeline(args) {
|
|
|
30976
31750
|
const routinePressureAlreadyApplied = !args.sessionMeta.isSubagent && executePressureEligible && routinePressureAppliedBySession.get(args.sessionId) === true;
|
|
30977
31751
|
const hasPendingMaterializeSignal = hasPendingMaterialization(args.sessionId);
|
|
30978
31752
|
const rideSignals = {
|
|
30979
|
-
hardFold:
|
|
31753
|
+
hardFold: foldBustsServedPrefixThisPass || firstRenderBust,
|
|
30980
31754
|
force: (args.forceMaterialization === true || emergencyDropEligible) && (args.contextUsage.percentage >= 95 || getEmergencyInputSample(args.db, args.sessionId) === 0),
|
|
30981
31755
|
explicitFlush: hasPendingMaterializeSignal || deferredMaterializeEligible && !prefixPreflightContended,
|
|
30982
31756
|
publishedHistory: !prefixPreflightContended && (args.isCacheBusting || publishedM1RefreshedThisPass || canConsumeDeferredLate && deferredHistoryWasPendingAtPassStart)
|
|
@@ -30992,7 +31766,7 @@ async function runPipeline(args) {
|
|
|
30992
31766
|
onRejectedProjectOverride: (warning) => sessionLog(args.sessionId, warning)
|
|
30993
31767
|
});
|
|
30994
31768
|
let protectionFloorResolution = resolveProtectionFloor();
|
|
30995
|
-
const shouldRunHeuristics = args.heuristics !== undefined && isCacheBustingPass && (rideSignals.publishedHistory || args.forceMaterialization === true || hasPendingMaterializeSignal || deferredMaterializeEligible ||
|
|
31769
|
+
const shouldRunHeuristics = args.heuristics !== undefined && isCacheBustingPass && (rideSignals.publishedHistory || args.forceMaterialization === true || hasPendingMaterializeSignal || deferredMaterializeEligible || foldBustsServedPrefixThisPass || firstRenderBust || args.schedulerDecision === "execute" && !alreadyRanHeuristicsThisTurn);
|
|
30996
31770
|
const tFallbackIdentity = performance.now();
|
|
30997
31771
|
const hasFallbackMessageTags = hasPiFallbackMessageTags(args.db, args.sessionId);
|
|
30998
31772
|
const entryFingerprintByMessageId = buildEntryFingerprintMap(args.messages, stableIdResolver, args.reusableMessageIds, hasFallbackMessageTags);
|
|
@@ -31032,6 +31806,19 @@ async function runPipeline(args) {
|
|
|
31032
31806
|
} : undefined
|
|
31033
31807
|
});
|
|
31034
31808
|
logTransformTiming(args.sessionId, "tagMessages", tTag);
|
|
31809
|
+
if (foldBustsServedPrefixThisPass) {
|
|
31810
|
+
try {
|
|
31811
|
+
let converted = 0;
|
|
31812
|
+
args.db.transaction(() => {
|
|
31813
|
+
converted = convertLegacyToolSkeletons(args.db, args.sessionId, targets).size;
|
|
31814
|
+
}).immediate();
|
|
31815
|
+
if (converted > 0) {
|
|
31816
|
+
sessionLog(args.sessionId, `pi HARD fold converted ${converted} legacy dropped-tool skeleton(s) to real-or-absent`);
|
|
31817
|
+
}
|
|
31818
|
+
} catch (error) {
|
|
31819
|
+
sessionLog(args.sessionId, `pi legacy dropped-tool skeleton conversion failed (kept legacy bytes): ${error instanceof Error ? error.message : String(error)}`);
|
|
31820
|
+
}
|
|
31821
|
+
}
|
|
31035
31822
|
try {
|
|
31036
31823
|
if (!args.sessionMeta.isSubagent) {
|
|
31037
31824
|
const hasRecentCommit = detectRecentCommit(args.messages);
|
|
@@ -31058,12 +31845,13 @@ async function runPipeline(args) {
|
|
|
31058
31845
|
mutationGateObserverForTests?.({
|
|
31059
31846
|
foldDue: foldDueDecision.value,
|
|
31060
31847
|
foldExecuted: foldExecutedThisPass,
|
|
31848
|
+
foldBustsServedPrefix: foldBustsServedPrefixThisPass,
|
|
31061
31849
|
shouldApplyPendingOps,
|
|
31062
31850
|
shouldRunHeuristics,
|
|
31063
31851
|
shouldRunReasoningCleanup: args.reasoningClearing !== undefined && shouldRunHeuristics
|
|
31064
31852
|
});
|
|
31065
31853
|
if (shouldApplyPendingOps) {
|
|
31066
|
-
const applyReason = hasPendingMaterializeSignal ? "explicit_flush" : deferredMaterialize ? "deferred_publication" : args.forceMaterialization ? "force_materialization" :
|
|
31854
|
+
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})`;
|
|
31067
31855
|
const pendingOpsDepth = getPendingOpsCount(args.db, args.sessionId);
|
|
31068
31856
|
const pendingDecisionLog = `pending ops WILL APPLY — reason=${applyReason}, pendingOps=${pendingOpsDepth === null ? "not loaded (deferred pass)" : pendingOpsDepth} context=${args.contextUsage.percentage.toFixed(1)}%`;
|
|
31069
31857
|
sessionLog(args.sessionId, pendingDecisionLog);
|
|
@@ -31150,7 +31938,7 @@ async function runPipeline(args) {
|
|
|
31150
31938
|
const activeTags = allTagsForPass.filter((tag) => tag.status === "active");
|
|
31151
31939
|
logTransformTiming(args.sessionId, "getTagsBySessionSnapshot", tActiveTags, `all=${allTagsForPass.length} active=${activeTags.length}`);
|
|
31152
31940
|
if (shouldRunHeuristics) {
|
|
31153
|
-
const reason = args.forceMaterialization ? "force_materialization" :
|
|
31941
|
+
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})`;
|
|
31154
31942
|
const heuristicsDecisionLog = `heuristics WILL RUN — reason=${reason}, context=${args.contextUsage.percentage.toFixed(1)}%, turn=n/a`;
|
|
31155
31943
|
sessionLog(args.sessionId, heuristicsDecisionLog);
|
|
31156
31944
|
pendingDecisionLogObserverForTests?.(heuristicsDecisionLog);
|
|
@@ -31163,7 +31951,7 @@ async function runPipeline(args) {
|
|
|
31163
31951
|
if (shouldRunHeuristics && args.heuristics) {
|
|
31164
31952
|
try {
|
|
31165
31953
|
const tHeuristic = performance.now();
|
|
31166
|
-
const independentMutationBeforeHeuristics = pendingOpsDidMutate ||
|
|
31954
|
+
const independentMutationBeforeHeuristics = pendingOpsDidMutate || foldBustsServedPrefixThisPass;
|
|
31167
31955
|
if (args.forceMaterialization === true && independentMutationBeforeHeuristics && getEmergencyInputSample(args.db, args.sessionId) > 0) {
|
|
31168
31956
|
clearEmergencyDropSample(args.db, args.sessionId);
|
|
31169
31957
|
}
|
|
@@ -31937,6 +32725,10 @@ ${result}`;
|
|
|
31937
32725
|
});
|
|
31938
32726
|
}
|
|
31939
32727
|
|
|
32728
|
+
// ../plugin/src/features/magic-context/store-generation-rebase.ts
|
|
32729
|
+
var rebasesInFlight = new WeakMap;
|
|
32730
|
+
var repairCheckedSessions = new WeakMap;
|
|
32731
|
+
|
|
31940
32732
|
// ../plugin/src/hooks/magic-context/historian-state-file.ts
|
|
31941
32733
|
import { mkdirSync as mkdirSync5, unlinkSync as unlinkSync2, writeFileSync as writeFileSync7 } from "node:fs";
|
|
31942
32734
|
function cleanupHistorianStateFile(path) {
|
|
@@ -32000,6 +32792,7 @@ async function sendStatusNotification(_client, sessionId, text, params) {
|
|
|
32000
32792
|
var inconsistentProducerWindows = new Set;
|
|
32001
32793
|
var HISTORIAN_ALERT_COOLDOWN_MS2 = 60 * 1000;
|
|
32002
32794
|
var lastHistorianAlertBySession2 = new Map;
|
|
32795
|
+
var STORED_COMPARTMENT_FAILURE_BACKOFF_MS = 30 * 60 * 1000;
|
|
32003
32796
|
|
|
32004
32797
|
// ../plugin/src/hooks/magic-context/compartment-runner-recomp.ts
|
|
32005
32798
|
function insertRecompCompartmentRows(db, sessionId, compartments, now) {
|
|
@@ -32138,7 +32931,7 @@ Found ${existingStaging.compartments.length} staged compartment(s) from ${existi
|
|
|
32138
32931
|
clearInjectionCache(sessionId);
|
|
32139
32932
|
}
|
|
32140
32933
|
promoted.facts;
|
|
32141
|
-
|
|
32934
|
+
{
|
|
32142
32935
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
32143
32936
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
32144
32937
|
const liveCompartments = getCompartments(db, sessionId);
|
|
@@ -32355,7 +33148,7 @@ Another process acquired the compartment-state lease before recomp could publish
|
|
|
32355
33148
|
queueDropsForCompartmentalizedMessages(db, sessionId, lastCompartmentEnd, compartmentTagKeys);
|
|
32356
33149
|
}
|
|
32357
33150
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
32358
|
-
|
|
33151
|
+
{
|
|
32359
33152
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
32360
33153
|
await deps.ensureProjectRegistered?.(sessionDirectory, db);
|
|
32361
33154
|
const liveCompartments = getCompartments(db, sessionId);
|
|
@@ -32517,7 +33310,7 @@ Could not acquire the compartment-state lease for this session.`;
|
|
|
32517
33310
|
clearInjectionCache(sessionId);
|
|
32518
33311
|
}
|
|
32519
33312
|
deps.onCompartmentStatePublished?.(sessionId);
|
|
32520
|
-
|
|
33313
|
+
{
|
|
32521
33314
|
const projectIdentity = resolveProjectIdentity(sessionDirectory);
|
|
32522
33315
|
const liveCompartments = getCompartments(db, sessionId);
|
|
32523
33316
|
const chunksToEmbed = liveCompartments.map((c) => ({
|
|
@@ -33544,6 +34337,11 @@ function compressionText(summary) {
|
|
|
33544
34337
|
return "Waiting for enough conversation history";
|
|
33545
34338
|
}
|
|
33546
34339
|
}
|
|
34340
|
+
function runnerText(status) {
|
|
34341
|
+
const why = status.source === "configured" ? "configured" : `default for harness ${status.harness || "unknown"}`;
|
|
34342
|
+
const observed = status.observed === "last_completion" ? "" : " · no completion yet";
|
|
34343
|
+
return `${status.runner} (${why})${observed}`;
|
|
34344
|
+
}
|
|
33547
34345
|
function reclaimableText(summary) {
|
|
33548
34346
|
const count = Math.max(0, Math.floor(summary.reclaimable.toolOutputCount));
|
|
33549
34347
|
if (count === 0)
|
|
@@ -33585,6 +34383,12 @@ function renderUserStatusSummary(summary, style) {
|
|
|
33585
34383
|
],
|
|
33586
34384
|
["Search indexing", embeddingText(summary)]
|
|
33587
34385
|
];
|
|
34386
|
+
if (summary.historianRunner) {
|
|
34387
|
+
values.push(["Historian runner", runnerText(summary.historianRunner)]);
|
|
34388
|
+
}
|
|
34389
|
+
if (summary.dreamerRunner) {
|
|
34390
|
+
values.push(["Dreamer runner", runnerText(summary.dreamerRunner)]);
|
|
34391
|
+
}
|
|
33588
34392
|
if (summary.historianRefusal) {
|
|
33589
34393
|
values.push([
|
|
33590
34394
|
"Historian refusal",
|
|
@@ -34063,7 +34867,7 @@ function buildStatusView(source, options) {
|
|
|
34063
34867
|
// package.json
|
|
34064
34868
|
var package_default = {
|
|
34065
34869
|
name: "@cortexkit/pi-magic-context",
|
|
34066
|
-
version: "0.
|
|
34870
|
+
version: "0.44.0",
|
|
34067
34871
|
type: "module",
|
|
34068
34872
|
description: "Pi and OMP coding agent extension for Magic Context — cross-session memory and context management",
|
|
34069
34873
|
main: "dist/index.js",
|
|
@@ -34090,6 +34894,7 @@ var package_default = {
|
|
|
34090
34894
|
"dist",
|
|
34091
34895
|
"README.md"
|
|
34092
34896
|
],
|
|
34897
|
+
"//": "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.",
|
|
34093
34898
|
scripts: {
|
|
34094
34899
|
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",
|
|
34095
34900
|
"build:e2e-argv": "bun build src/subagent-runner.ts --outfile ../../tests/docker/.generated/subagent-runner-e2e.mjs --target node --format esm --external node:sqlite",
|
|
@@ -34104,7 +34909,7 @@ var package_default = {
|
|
|
34104
34909
|
prepublishOnly: "bun run build"
|
|
34105
34910
|
},
|
|
34106
34911
|
dependencies: {
|
|
34107
|
-
"@cortexkit/subc-client": "0.
|
|
34912
|
+
"@cortexkit/subc-client": "0.11.1",
|
|
34108
34913
|
"@jitl/quickjs-singlefile-cjs-release-asyncify": "0.32.0",
|
|
34109
34914
|
"ai-tokenizer": "^1.0.6",
|
|
34110
34915
|
"comment-json": "^5.0.0",
|
|
@@ -34126,6 +34931,7 @@ var package_default = {
|
|
|
34126
34931
|
"@types/better-sqlite3": "^7.6.13",
|
|
34127
34932
|
"@types/bun": "^1.3.10",
|
|
34128
34933
|
"@types/node": "^22.20.0",
|
|
34934
|
+
"pi-agent-core-087": "npm:@earendil-works/pi-agent-core@0.87.1",
|
|
34129
34935
|
"pi-ai-086": "npm:@earendil-works/pi-ai@0.86.0",
|
|
34130
34936
|
"pi-coding-agent-086": "npm:@earendil-works/pi-coding-agent@0.86.0",
|
|
34131
34937
|
"pi-coding-agent-087": "npm:@earendil-works/pi-coding-agent@0.87.1",
|
|
@@ -34666,11 +35472,14 @@ No active Pi session is available.`,
|
|
|
34666
35472
|
}
|
|
34667
35473
|
try {
|
|
34668
35474
|
if (ctx.hasUI) {
|
|
35475
|
+
if (currentDeps.modelChainWarning)
|
|
35476
|
+
ctx.ui.notify(currentDeps.modelChainWarning, "error");
|
|
34669
35477
|
await showStatusDialog(pi, ctx, currentDeps);
|
|
34670
35478
|
return;
|
|
34671
35479
|
}
|
|
34672
35480
|
const statusDetail = buildPiStatusDetail(pi, ctx, currentDeps, sessionId);
|
|
34673
|
-
const statusText = formatPiStatusSummary(statusDetail)
|
|
35481
|
+
const statusText = `${formatPiStatusSummary(statusDetail)}${currentDeps.modelChainWarning ? `
|
|
35482
|
+
WARNING: ${currentDeps.modelChainWarning}` : ""}`;
|
|
34674
35483
|
const details = buildStatusDetails(currentDeps, statusDetail);
|
|
34675
35484
|
sendStatus({
|
|
34676
35485
|
title: "/ctx-status",
|
|
@@ -35457,7 +36266,7 @@ function ensureConfigLocationsMigrated(dir) {
|
|
|
35457
36266
|
});
|
|
35458
36267
|
}
|
|
35459
36268
|
function logPiConfigLoad(args) {
|
|
35460
|
-
const key =
|
|
36269
|
+
const key = resolve4(args.dir);
|
|
35461
36270
|
if (args.dedupe && loggedPiConfigDirs.has(key))
|
|
35462
36271
|
return;
|
|
35463
36272
|
if (args.dedupe) {
|
|
@@ -35518,6 +36327,13 @@ function logPiUsageBoundOnce(sessionId, reading, absoluteWall, reason) {
|
|
|
35518
36327
|
piUsageBoundLogSeen.add(key);
|
|
35519
36328
|
info(`message_end: session=${sessionId} bounded ${reason} ${reading} at trusted absolute wall ${absoluteWall}; pressure_proof_not_capacity`);
|
|
35520
36329
|
}
|
|
36330
|
+
function logPiUsageAboveWindowOnce(sessionId, reading, absoluteWall) {
|
|
36331
|
+
const key = `${sessionId}|accepted above window`;
|
|
36332
|
+
if (piUsageBoundLogSeen.has(key))
|
|
36333
|
+
return;
|
|
36334
|
+
piUsageBoundLogSeen.add(key);
|
|
36335
|
+
info(`message_end: session=${sessionId} provider usage ${reading} exceeds configured window ${absoluteWall}; counted as real pressure against the configured limit`);
|
|
36336
|
+
}
|
|
35521
36337
|
function resolvePiPressureContextLimit(args) {
|
|
35522
36338
|
let detectedContextLimit;
|
|
35523
36339
|
try {
|
|
@@ -35549,24 +36365,32 @@ async function persistPiPressureFromMessageEnd(args) {
|
|
|
35549
36365
|
});
|
|
35550
36366
|
const trustedAbsoluteWall = reportedGeometry && hasTrustedAbsoluteWall(reportedGeometry) ? reportedGeometry.derivation.absoluteWall : undefined;
|
|
35551
36367
|
const unboundedPressure = computePiPressure(usage, args.piContextWindow);
|
|
35552
|
-
const rawPressure = computePiPressure(usage, args.piContextWindow, trustedAbsoluteWall);
|
|
35553
|
-
if (unboundedPressure && trustedAbsoluteWall !== undefined && unboundedPressure.inputTokens > trustedAbsoluteWall) {
|
|
35554
|
-
logPiUsageBoundOnce(args.sessionId, unboundedPressure.inputTokens, trustedAbsoluteWall, "current reading");
|
|
35555
|
-
}
|
|
35556
36368
|
const msg = args.message && typeof args.message === "object" ? args.message : undefined;
|
|
35557
36369
|
const messageHadOverflowError = typeof msg?.errorMessage === "string" && detectOverflow(msg.errorMessage).isOverflow;
|
|
35558
|
-
const
|
|
35559
|
-
|
|
36370
|
+
const readingAboveTrustedWall = unboundedPressure !== null && trustedAbsoluteWall !== undefined && unboundedPressure.inputTokens > trustedAbsoluteWall;
|
|
36371
|
+
const requestAccepted = !messageHadOverflowError;
|
|
36372
|
+
if (readingAboveTrustedWall && unboundedPressure && trustedAbsoluteWall) {
|
|
36373
|
+
if (requestAccepted) {
|
|
36374
|
+
logPiUsageAboveWindowOnce(args.sessionId, unboundedPressure.inputTokens, trustedAbsoluteWall);
|
|
36375
|
+
} else {
|
|
36376
|
+
logPiUsageBoundOnce(args.sessionId, unboundedPressure.inputTokens, trustedAbsoluteWall, "current reading");
|
|
36377
|
+
}
|
|
36378
|
+
}
|
|
36379
|
+
const requestSucceeded = requestAccepted && !readingAboveTrustedWall;
|
|
36380
|
+
if (requestAccepted && unboundedPressure) {
|
|
35560
36381
|
const rawOverflow = getOverflowState(args.db, args.sessionId);
|
|
35561
36382
|
const detectedLimitMatchesModel = rawOverflow.detectedContextLimitModelKey === null || modelKey !== undefined && rawOverflow.detectedContextLimitModelKey === modelKey;
|
|
35562
|
-
if (rawOverflow.detectedContextLimit > 0 && detectedLimitMatchesModel &&
|
|
36383
|
+
if (rawOverflow.detectedContextLimit > 0 && detectedLimitMatchesModel && unboundedPressure.inputTokens > rawOverflow.detectedContextLimit) {
|
|
35563
36384
|
clearDetectedContextLimit(args.db, args.sessionId);
|
|
35564
|
-
info(`message_end: detected limit ${rawOverflow.detectedContextLimit} invalidated by a successful ${
|
|
36385
|
+
info(`message_end: detected limit ${rawOverflow.detectedContextLimit} invalidated by a successful ${unboundedPressure.inputTokens}-token request; using Pi contextWindow`);
|
|
35565
36386
|
}
|
|
35566
36387
|
}
|
|
35567
36388
|
const meta = getOrCreateSessionMeta(args.db, args.sessionId);
|
|
35568
36389
|
let observedSafeInputTokens = meta.observedSafeInputTokens ?? 0;
|
|
35569
|
-
const updates = {
|
|
36390
|
+
const updates = {};
|
|
36391
|
+
if (unboundedPressure !== null) {
|
|
36392
|
+
updates.lastResponseTime = Date.now();
|
|
36393
|
+
}
|
|
35570
36394
|
if (trustedAbsoluteWall !== undefined && observedSafeInputTokens > trustedAbsoluteWall) {
|
|
35571
36395
|
logPiUsageBoundOnce(args.sessionId, observedSafeInputTokens, trustedAbsoluteWall, "persisted floor");
|
|
35572
36396
|
observedSafeInputTokens = 0;
|
|
@@ -35587,8 +36411,10 @@ async function persistPiPressureFromMessageEnd(args) {
|
|
|
35587
36411
|
provenInputTokens: observedSafeInputTokens
|
|
35588
36412
|
});
|
|
35589
36413
|
const reportedContextLimit = reportedGeometry?.usableSoft ?? 0;
|
|
35590
|
-
const pressure = computePiPressure(usage, effectiveContextLimit, trustedAbsoluteWall);
|
|
36414
|
+
const pressure = computePiPressure(usage, effectiveContextLimit, requestAccepted ? undefined : trustedAbsoluteWall);
|
|
36415
|
+
let cacheAlert;
|
|
35591
36416
|
if (pressure) {
|
|
36417
|
+
notePiUsageReadingUsed(args.sessionId);
|
|
35592
36418
|
const provenSafeInputTokens = requestSucceeded ? Math.max(observedSafeInputTokens, pressure.inputTokens) : observedSafeInputTokens;
|
|
35593
36419
|
const contextLimit = requestSucceeded ? resolvePiPressureContextLimit({
|
|
35594
36420
|
db: args.db,
|
|
@@ -35602,7 +36428,7 @@ async function persistPiPressureFromMessageEnd(args) {
|
|
|
35602
36428
|
if (requestSucceeded && reportedContextLimit > 0 && reportedContextLimit < provenSafeInputTokens && !meta.cacheAlertSent) {
|
|
35603
36429
|
updates.cacheAlertSent = true;
|
|
35604
36430
|
const modelLabel = activeModel.provider && activeModel.id ? `${activeModel.provider}/${activeModel.id}` : "the active model";
|
|
35605
|
-
|
|
36431
|
+
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.`;
|
|
35606
36432
|
}
|
|
35607
36433
|
updates.lastContextPercentage = percentage;
|
|
35608
36434
|
updates.lastInputTokens = pressure.inputTokens;
|
|
@@ -35611,13 +36437,21 @@ async function persistPiPressureFromMessageEnd(args) {
|
|
|
35611
36437
|
updates.observedSafeInputTokens = provenSafeInputTokens;
|
|
35612
36438
|
}
|
|
35613
36439
|
} else if (usage === null && typeof args.piTokens === "number" && (trustedAbsoluteWall === undefined || args.piTokens <= trustedAbsoluteWall)) {
|
|
35614
|
-
|
|
35615
|
-
|
|
35616
|
-
|
|
35617
|
-
|
|
36440
|
+
if (args.piTokensIsRawBranchEstimate === true) {
|
|
36441
|
+
noteRawBranchEstimateSetAside(args.sessionId, args.piTokens, "message_end estimate");
|
|
36442
|
+
} else {
|
|
36443
|
+
notePiUsageReadingUsed(args.sessionId);
|
|
36444
|
+
updates.lastInputTokens = args.piTokens;
|
|
36445
|
+
if (effectiveContextLimit > 0) {
|
|
36446
|
+
updates.lastContextPercentage = args.piTokens / effectiveContextLimit * 100;
|
|
36447
|
+
updates.lastUsageContextLimit = effectiveContextLimit;
|
|
36448
|
+
}
|
|
35618
36449
|
}
|
|
35619
36450
|
}
|
|
35620
36451
|
updateSessionMeta(args.db, args.sessionId, updates);
|
|
36452
|
+
if (cacheAlert !== undefined) {
|
|
36453
|
+
await args.notifyIssue?.(cacheAlert);
|
|
36454
|
+
}
|
|
35621
36455
|
}
|
|
35622
36456
|
var PLUGIN_VERSION = (() => {
|
|
35623
36457
|
try {
|
|
@@ -35628,17 +36462,27 @@ var PLUGIN_VERSION = (() => {
|
|
|
35628
36462
|
}
|
|
35629
36463
|
})();
|
|
35630
36464
|
setHarness(PI_HARNESS_KIND);
|
|
35631
|
-
function resolveHistorianFromConfig(config, harness = PI_HARNESS_KIND) {
|
|
36465
|
+
function resolveHistorianFromConfig(config, harness = PI_HARNESS_KIND, modelRegistry) {
|
|
35632
36466
|
const historian = config.historian;
|
|
35633
36467
|
if (historian?.disable === true)
|
|
35634
36468
|
return;
|
|
35635
36469
|
const resolved = resolveHistorianModel(config, harness);
|
|
35636
|
-
const
|
|
36470
|
+
const validated = modelRegistry && resolved.primary ? validatePiDreamerModels([
|
|
36471
|
+
{
|
|
36472
|
+
task: "classify-memories",
|
|
36473
|
+
schedule: "",
|
|
36474
|
+
timeoutMinutes: 20,
|
|
36475
|
+
model: resolved.primary,
|
|
36476
|
+
fallbackModels: resolved.fallbacks
|
|
36477
|
+
}
|
|
36478
|
+
], modelRegistry)[0] : undefined;
|
|
36479
|
+
const primary = validated ? typeof validated.model === "string" ? { model: validated.model } : validated.model : resolved.primary;
|
|
36480
|
+
const model = primary?.model;
|
|
35637
36481
|
if (!model)
|
|
35638
36482
|
return;
|
|
35639
36483
|
const historianContextLimit = resolveHistorianContextLimit(model);
|
|
35640
36484
|
const historianChunkTokens = deriveHistorianChunkTokens(historianContextLimit);
|
|
35641
|
-
const fallbackModels = resolved.fallbacks;
|
|
36485
|
+
const fallbackModels = validated?.fallbackModels ?? resolved.fallbacks;
|
|
35642
36486
|
return {
|
|
35643
36487
|
runner: new PiSubagentRunner,
|
|
35644
36488
|
model,
|
|
@@ -35649,7 +36493,7 @@ function resolveHistorianFromConfig(config, harness = PI_HARNESS_KIND) {
|
|
|
35649
36493
|
temperature: historian?.temperature,
|
|
35650
36494
|
maxOutputTokens: historian?.maxTokens,
|
|
35651
36495
|
twoPass: historian?.two_pass === true,
|
|
35652
|
-
thinkingLevel:
|
|
36496
|
+
thinkingLevel: primary?.qualifier,
|
|
35653
36497
|
executeThresholdPercentage: config.execute_threshold_percentage,
|
|
35654
36498
|
executeThresholdTokens: config.execute_threshold_tokens,
|
|
35655
36499
|
commitClusterTrigger: config.commit_cluster_trigger,
|
|
@@ -35713,30 +36557,7 @@ async function src_default(pi) {
|
|
|
35713
36557
|
return null;
|
|
35714
36558
|
}
|
|
35715
36559
|
};
|
|
35716
|
-
const unavailableReason = () => {
|
|
35717
|
-
const migration = getMigrationOnOpenRefusal();
|
|
35718
|
-
const blockingProcesses = migration?.blockingProcesses ?? migration?.serverPids.map((pid) => ({ kind: "process", pid })) ?? [];
|
|
35719
|
-
const fence = getSchemaFenceRejection();
|
|
35720
|
-
if (migration && blockingProcesses.length > 0) {
|
|
35721
|
-
return {
|
|
35722
|
-
kind: "migration_guard",
|
|
35723
|
-
persistedVersion: migration.persistedVersion,
|
|
35724
|
-
supportedVersion: migration.supportedVersion,
|
|
35725
|
-
blockingProcesses
|
|
35726
|
-
};
|
|
35727
|
-
}
|
|
35728
|
-
if (fence) {
|
|
35729
|
-
return {
|
|
35730
|
-
kind: "schema_fence",
|
|
35731
|
-
persistedVersion: fence.persistedVersion,
|
|
35732
|
-
supportedVersion: fence.supportedVersion
|
|
35733
|
-
};
|
|
35734
|
-
}
|
|
35735
|
-
return {
|
|
35736
|
-
kind: "storage_failure",
|
|
35737
|
-
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)`
|
|
35738
|
-
};
|
|
35739
|
-
};
|
|
36560
|
+
const unavailableReason = () => describeStorageUnavailability(openFailureCause ?? `storage unavailable at ${dbPath} (cache schema newer than this binary, or open failed)`);
|
|
35740
36561
|
const bootResult = await bootPiRuntimeWithDeadline({
|
|
35741
36562
|
deadlineMs: PI_BOOT_DEADLINE_MS,
|
|
35742
36563
|
openStorage,
|
|
@@ -35922,15 +36743,8 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
35922
36743
|
maybeAutoEmbedPiSession({
|
|
35923
36744
|
db: database,
|
|
35924
36745
|
projectDir: dir,
|
|
35925
|
-
projectIdentity: identity
|
|
35926
|
-
|
|
35927
|
-
}, sessionId, dir, identity, (text) => {
|
|
35928
|
-
sendCtxStatusMessage(pi, {
|
|
35929
|
-
title: "/ctx-embed",
|
|
35930
|
-
text,
|
|
35931
|
-
level: "info"
|
|
35932
|
-
});
|
|
35933
|
-
});
|
|
36746
|
+
projectIdentity: identity
|
|
36747
|
+
}, sessionId, dir, identity);
|
|
35934
36748
|
}
|
|
35935
36749
|
});
|
|
35936
36750
|
function buildProjectDeps(dir, identity, cfg, loadMetadata) {
|
|
@@ -35984,10 +36798,11 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
35984
36798
|
function resolveCurrentProjectDeps(ctx) {
|
|
35985
36799
|
return resolveProjectDepsForDir(ctx.cwd);
|
|
35986
36800
|
}
|
|
36801
|
+
let activeModelRegistry;
|
|
35987
36802
|
function resolveContextOptionsForProject(dir) {
|
|
35988
36803
|
const project = resolveProjectDepsForDir(dir);
|
|
35989
36804
|
const sampled = historianRunConfig(project.config, liveReaderFor(dir, project.config).poll().effective);
|
|
35990
|
-
const historian = resolveHistorianFromConfig(sampled);
|
|
36805
|
+
const historian = resolveHistorianFromConfig(sampled, PI_HARNESS_KIND, activeModelRegistry);
|
|
35991
36806
|
return { ...project.contextOptions, historian };
|
|
35992
36807
|
}
|
|
35993
36808
|
const bootProjectDeps = buildProjectDeps(projectDir, projectIdentity, config, {
|
|
@@ -35996,7 +36811,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
35996
36811
|
hasDeprecatedProtectedTags
|
|
35997
36812
|
});
|
|
35998
36813
|
projectDepsByDir.set(projectDir, bootProjectDeps);
|
|
35999
|
-
function syncDreamerProjectRegistration(current) {
|
|
36814
|
+
function syncDreamerProjectRegistration(current, modelRegistry) {
|
|
36000
36815
|
if (sessionShuttingDown)
|
|
36001
36816
|
return;
|
|
36002
36817
|
seenDreamerProjectIdentities.add(current.projectIdentity);
|
|
@@ -36013,6 +36828,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36013
36828
|
projectIdentity: current.projectIdentity,
|
|
36014
36829
|
registrationOwner: dreamerRegistrationOwner,
|
|
36015
36830
|
config: current.dreamerConfig,
|
|
36831
|
+
modelRegistry,
|
|
36016
36832
|
sampleDreamRun: () => {
|
|
36017
36833
|
const fresh = liveReaderFor(current.projectDir, current.config).poll().effective;
|
|
36018
36834
|
const sampled = dreamerRunConfig(current.config, fresh);
|
|
@@ -36054,6 +36870,8 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36054
36870
|
pi.on("session_start", async (event, ctx) => {
|
|
36055
36871
|
projectDepsByDir.delete(ctx.cwd);
|
|
36056
36872
|
const current = resolveCurrentProjectDeps(ctx);
|
|
36873
|
+
activeModelRegistry = ctx.modelRegistry;
|
|
36874
|
+
syncDreamerProjectRegistration(current, ctx.modelRegistry);
|
|
36057
36875
|
syncCtxMemoryToolEnabled(pi, current.config.memory.enabled);
|
|
36058
36876
|
const failuresToShow = claimConfigParseFailuresOnce("pi", current.configParseFailures);
|
|
36059
36877
|
if (ctx.hasUI && failuresToShow.length > 0) {
|
|
@@ -36132,6 +36950,16 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36132
36950
|
runnable: current.dreamerEnabled,
|
|
36133
36951
|
scheduleSummary: summarizeDreamSchedule(current.config.dreamer)
|
|
36134
36952
|
},
|
|
36953
|
+
modelChainWarning: (() => {
|
|
36954
|
+
const registry = activeModelRegistry;
|
|
36955
|
+
if (!registry)
|
|
36956
|
+
return;
|
|
36957
|
+
const tasks = validatePiDreamerModels(buildDreamTaskRuntimeConfigs(current.config.dreamer, PI_HARNESS_KIND, current.config.language, current.config.mural.model), registry);
|
|
36958
|
+
const empty = tasks.filter((task) => task.modelChainUnavailable).map((task) => task.task);
|
|
36959
|
+
if (!resolveHistorianFromConfig(current.config, PI_HARNESS_KIND, registry) && current.historianConfig)
|
|
36960
|
+
empty.push("historian");
|
|
36961
|
+
return empty.length ? `Pi model chain empty (no model found): ${empty.join(", ")}` : undefined;
|
|
36962
|
+
})(),
|
|
36135
36963
|
activeProfile: current.config.profile,
|
|
36136
36964
|
cacheTtlConfig: current.config.cache_ttl,
|
|
36137
36965
|
cacheTtlConfigured: current.cacheTtlConfigured,
|
|
@@ -36161,7 +36989,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36161
36989
|
resolveRuntimeDeps: (ctx) => {
|
|
36162
36990
|
const current = resolveCurrentProjectDeps(ctx);
|
|
36163
36991
|
const fresh = historianRunConfig(current.config, liveReaderFor(current.projectDir, current.config).poll().effective);
|
|
36164
|
-
const historian = resolveHistorianFromConfig(fresh
|
|
36992
|
+
const historian = resolveHistorianFromConfig(fresh, PI_HARNESS_KIND, activeModelRegistry);
|
|
36165
36993
|
return {
|
|
36166
36994
|
db,
|
|
36167
36995
|
runner: recompRunner,
|
|
@@ -36196,7 +37024,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36196
37024
|
resolveRuntimeDeps: (ctx) => {
|
|
36197
37025
|
const current = resolveCurrentProjectDeps(ctx);
|
|
36198
37026
|
const fresh = historianRunConfig(current.config, liveReaderFor(current.projectDir, current.config).poll().effective);
|
|
36199
|
-
const historian = resolveHistorianFromConfig(fresh
|
|
37027
|
+
const historian = resolveHistorianFromConfig(fresh, PI_HARNESS_KIND, activeModelRegistry);
|
|
36200
37028
|
return {
|
|
36201
37029
|
db,
|
|
36202
37030
|
runner: wrapupRunner,
|
|
@@ -36230,7 +37058,7 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36230
37058
|
dreamerEnabled: bootProjectDeps.dreamerEnabled,
|
|
36231
37059
|
resolveDreamerEnabled: (ctx) => resolveCurrentProjectDeps(ctx).dreamerEnabled,
|
|
36232
37060
|
onProjectSeen: (identity) => seenDreamerProjectIdentities.add(identity),
|
|
36233
|
-
ensureRegistered: (ctx) => syncDreamerProjectRegistration(resolveCurrentProjectDeps(ctx)),
|
|
37061
|
+
ensureRegistered: (ctx) => syncDreamerProjectRegistration(resolveCurrentProjectDeps(ctx), ctx.modelRegistry),
|
|
36234
37062
|
registrationOwner: dreamerRegistrationOwner
|
|
36235
37063
|
});
|
|
36236
37064
|
info("registered /ctx-dream");
|
|
@@ -36238,8 +37066,6 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36238
37066
|
db,
|
|
36239
37067
|
projectDir,
|
|
36240
37068
|
projectIdentity,
|
|
36241
|
-
memoryEnabled: bootProjectDeps.config.memory.enabled,
|
|
36242
|
-
resolveMemoryEnabled: (ctx) => resolveCurrentProjectDeps(ctx).config.memory.enabled,
|
|
36243
37069
|
resolveProject: (ctx) => {
|
|
36244
37070
|
const current = resolveCurrentProjectDeps(ctx);
|
|
36245
37071
|
return {
|
|
@@ -36283,7 +37109,8 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36283
37109
|
};
|
|
36284
37110
|
const effectiveConfig = effectiveProjectDeps.config;
|
|
36285
37111
|
try {
|
|
36286
|
-
|
|
37112
|
+
activeModelRegistry = ctx.modelRegistry;
|
|
37113
|
+
syncDreamerProjectRegistration(effectiveProjectDeps, ctx.modelRegistry);
|
|
36287
37114
|
} catch (err) {
|
|
36288
37115
|
warn("before_agent_start: dreamer registration sync threw:", err);
|
|
36289
37116
|
}
|
|
@@ -36483,6 +37310,14 @@ async function startPiMagicContextRuntime(pi, database, dbPath) {
|
|
|
36483
37310
|
piContextWindowSource: "catalog",
|
|
36484
37311
|
piModel: ctx.model,
|
|
36485
37312
|
piTokens: piUsage && typeof piUsage.tokens === "number" ? piUsage.tokens : undefined,
|
|
37313
|
+
piTokensIsRawBranchEstimate: (() => {
|
|
37314
|
+
try {
|
|
37315
|
+
const branch = ctx.sessionManager.getBranch?.();
|
|
37316
|
+
return isPiLiveUsageRawBranchEstimate(branch);
|
|
37317
|
+
} catch {
|
|
37318
|
+
return false;
|
|
37319
|
+
}
|
|
37320
|
+
})(),
|
|
36486
37321
|
notifyIssue: async (message) => {
|
|
36487
37322
|
const uiNotify = ctx.ui?.notify;
|
|
36488
37323
|
if (typeof uiNotify === "function") {
|