johns-harness 2026.9.26 → 2026.9.27
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/CHANGELOG.md +5 -0
- package/README.md +5 -5
- package/dist/compact-B247y5Qt.js +31 -20
- package/dist/pi-embedded-C6ITuRXf.js +31 -20
- package/dist/pi-embedded-DoQsYfIY.js +31 -20
- package/dist/reply-C5LKjXcC.js +31 -20
- package/docs/PATCHES.md +17 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2026.9.27
|
|
4
|
+
|
|
5
|
+
- Family 74: the local active-session pressure guard compacts on exactly one trigger, estimated active-context tokens against the active model's declared context window (`ceil(0.7 x window)`, floored at `max(compaction.reserveTokensFloor, 50000)`; undeclared windows fall back to the runtime default, `DEFAULT_CONTEXT_TOKENS`). The fixed 1 MB transcript-bytes, 220-message and 3 GiB heap backstops are removed as triggers, so a session with 221 small messages and 528 KB no longer compacts early while a large context still compacts on real token pressure. The 5-minute cooldown, the 24-message floor and the failed-attempt growth gate remain as anti-thrash throttles, and the emergency compaction path is untouched. `contextRatio`, `minIntervalMs` and `minMessagesAfterCompaction` are the config surface; legacy `transcriptBytes`/`messageCount`/`heapUsedBytes` keys are accepted and ignored.
|
|
6
|
+
- Roll back with `npm i -g johns-harness@2026.9.26`.
|
|
7
|
+
|
|
3
8
|
## 2026.9.26
|
|
4
9
|
|
|
5
10
|
- Family 73: the `content-story`, `dashboard` and `cold-outreach` skills are removed from the bundled set on request, leaving eight generic bundled skills (`code-ops`, `web-research`, `plan-archival`, `todos`, `arch-viz`, `gcp-logs`, `activity-logging`, `outlook`). They load by description match exactly as before, workspace copies override them, and `enabled: false` and `allowBundled` still apply. Nothing else changes from 2026.9.25.
|
package/README.md
CHANGED
|
@@ -85,8 +85,8 @@ node johnness.mjs --help
|
|
|
85
85
|
### Verify
|
|
86
86
|
|
|
87
87
|
```bash
|
|
88
|
-
npm test #
|
|
89
|
-
bash scripts/verify-patches.sh #
|
|
88
|
+
npm test # 915 tests against the installed dependency tree
|
|
89
|
+
bash scripts/verify-patches.sh # 459 checks across every patch family
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
## Launch a swarm with one command
|
|
@@ -132,7 +132,7 @@ Coding agents today run as isolated processes. Two agents on the same repository
|
|
|
132
132
|
- **Memory built for production.** Tiered recall that traces from consolidated reflections down to the verbatim record, surviving compaction and shared across the swarm. Installed and enabled by default.
|
|
133
133
|
- **Production authority per commit.** Promotion is granted to an exact SHA, never to a branch name, so one worker's authorization never covers another worker's commits.
|
|
134
134
|
- **An append-only action log.** Agents record every consequential action to `ACTION_LOG.md` and read it before acting.
|
|
135
|
-
- **A fixed runtime surface.** The core does not grow on a schedule. New mechanisms enter only to solve a demonstrated production failure, one narrow, tested, reversible patch at a time:
|
|
135
|
+
- **A fixed runtime surface.** The core does not grow on a schedule. New mechanisms enter only to solve a demonstrated production failure, one narrow, tested, reversible patch at a time: 74 patch families, each with a regression test and a rollback path.
|
|
136
136
|
- **Reliability with a definition.** Bounded retries, explicit failure states, exact-once continuation, context-pressure recovery, durable delivery, and supervised gateway recovery.
|
|
137
137
|
- **Coding first, phone optional.** Direct the work at a high level from a chat channel while agents plan, implement, test, coordinate, and stage releases unattended.
|
|
138
138
|
- **Local voice.** Optional native Whisper transcription of inbound audio, entirely on your machine. Off by default. [Setup](docs/NATIVE-WHISPER-MUSE.md).
|
|
@@ -199,7 +199,7 @@ The log is a [`RULES.md`](RULES.md) workspace convention enforced through the ac
|
|
|
199
199
|
|
|
200
200
|
## Patch families
|
|
201
201
|
|
|
202
|
-
The runtime carries
|
|
202
|
+
The runtime carries 74 patch families plus the 65.1 safe-update amendment. Each is a production fix applied at the source with a regression test, a durable patch marker, and a rollback path. A verifier runs 459 checks against the package tree and installed dependencies, and 915 tests run against the installed dependency tree.
|
|
203
203
|
|
|
204
204
|
Every family follows the same six steps: reproduce the failure, trace the exact runtime path, make the smallest source-level change that restores the invariant, add a regression test and a patch marker, run the verifier, and retain rollback artifacts. The full index: [`docs/PATCHES.md`](docs/PATCHES.md).
|
|
205
205
|
|
|
@@ -218,7 +218,7 @@ Every family follows the same six steps: reproduce the failure, trace the exact
|
|
|
218
218
|
## Documentation
|
|
219
219
|
|
|
220
220
|
- [`docs/index.md`](docs/index.md): runtime docs, from gateway and channels to plugins, nodes, and CLI reference.
|
|
221
|
-
- [`docs/PATCHES.md`](docs/PATCHES.md): the
|
|
221
|
+
- [`docs/PATCHES.md`](docs/PATCHES.md): the 74 patch families, one record each.
|
|
222
222
|
- [`docs/NATIVE-WHISPER-MUSE.md`](docs/NATIVE-WHISPER-MUSE.md): local Whisper transcription setup.
|
|
223
223
|
- [`RULES.md`](RULES.md): the default operating rules, including Rule Zero on production authorization.
|
|
224
224
|
|
package/dist/compact-B247y5Qt.js
CHANGED
|
@@ -7894,9 +7894,7 @@ function resolveTranscriptPolicy(params) {
|
|
|
7894
7894
|
|
|
7895
7895
|
//#region johnness local active-session pressure guard
|
|
7896
7896
|
const LOCAL_PRESSURE_GUARD_DEFAULTS = {
|
|
7897
|
-
|
|
7898
|
-
messageCount: 220,
|
|
7899
|
-
heapUsedBytes: 3221225472,
|
|
7897
|
+
contextRatio: 0.7,
|
|
7900
7898
|
minIntervalMs: 300000,
|
|
7901
7899
|
minMessagesAfterCompaction: 24
|
|
7902
7900
|
};
|
|
@@ -7907,14 +7905,24 @@ function localPressureGuardNumber(value, fallback) {
|
|
|
7907
7905
|
function localPressureGuardSettings(cfg) {
|
|
7908
7906
|
const raw = cfg?.agents?.defaults?.activeSessionPressure ?? cfg?.session?.activePressure ?? {};
|
|
7909
7907
|
if (raw?.enabled === false) return null;
|
|
7908
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: legacy transcriptBytes/messageCount/heapUsedBytes keys are accepted without error and ignored. Config surface: enabled, contextRatio, minIntervalMs, minMessagesAfterCompaction. */
|
|
7909
|
+
const contextRatio = localPressureGuardNumber(raw.contextRatio, LOCAL_PRESSURE_GUARD_DEFAULTS.contextRatio);
|
|
7910
7910
|
return {
|
|
7911
|
-
|
|
7912
|
-
messageCount: localPressureGuardNumber(raw.messageCount ?? raw.maxMessages, LOCAL_PRESSURE_GUARD_DEFAULTS.messageCount),
|
|
7913
|
-
heapUsedBytes: localPressureGuardNumber(raw.heapUsedBytes ?? raw.maxHeapUsedBytes, LOCAL_PRESSURE_GUARD_DEFAULTS.heapUsedBytes),
|
|
7911
|
+
contextRatio: contextRatio > 0 ? contextRatio : LOCAL_PRESSURE_GUARD_DEFAULTS.contextRatio,
|
|
7914
7912
|
minIntervalMs: localPressureGuardNumber(raw.minIntervalMs, LOCAL_PRESSURE_GUARD_DEFAULTS.minIntervalMs),
|
|
7915
7913
|
minMessagesAfterCompaction: localPressureGuardNumber(raw.minMessagesAfterCompaction, LOCAL_PRESSURE_GUARD_DEFAULTS.minMessagesAfterCompaction)
|
|
7916
7914
|
};
|
|
7917
7915
|
}
|
|
7916
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single pressure trigger — estimated active-context tokens vs the active model's declared context window; the window falls back to DEFAULT_CONTEXT_TOKENS when undeclared. See docs/PATCHES.md family 74. */
|
|
7917
|
+
function localPressureGuardContextWindowTokens(model) {
|
|
7918
|
+
const declared = typeof model?.contextWindow === "number" && Number.isFinite(model.contextWindow) ? Math.floor(model.contextWindow) : 0;
|
|
7919
|
+
return declared > 0 ? declared : DEFAULT_CONTEXT_TOKENS;
|
|
7920
|
+
}
|
|
7921
|
+
function localPressureGuardContextThreshold(settings, contextWindowTokens, cfg) {
|
|
7922
|
+
const reserveTokensFloor = localPressureGuardNumber(cfg?.agents?.defaults?.compaction?.reserveTokensFloor, 2e4);
|
|
7923
|
+
const floor = Math.max(reserveTokensFloor, 50000);
|
|
7924
|
+
return Math.max(Math.ceil(settings.contextRatio * contextWindowTokens), floor);
|
|
7925
|
+
}
|
|
7918
7926
|
/* JOHNNESS_PATCH_APPEND_ONLY_PRESSURE_BASELINE: derive a restart-safe byte baseline from the append-only JSONL so transcriptBytes pressure measures NEW growth since the last successful compaction rather than total (never-shrinking) file size. See docs/PATCHES.md family 22. Scans getEntries() newest->oldest for the newest SUCCESSFUL johnness.active-pressure-refresh marker (failed !== true) and returns its recorded post-compaction size (postCompactionBytes, else transcriptBytes). Returns 0 for legacy sessions with no such marker, so a first over-limit session still compacts once. */
|
|
7919
7927
|
function computeActivePressureBaselineBytes(sessionManager) {
|
|
7920
7928
|
try {
|
|
@@ -8072,12 +8080,12 @@ function compactionRotationNumber(value, fallback) {
|
|
|
8072
8080
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
8073
8081
|
}
|
|
8074
8082
|
function compactionRotationSettings(cfg) {
|
|
8075
|
-
const pressure = localPressureGuardSettings(cfg) ?? { transcriptBytes: 1048576 };
|
|
8076
8083
|
const raw = cfg?.agents?.defaults?.activeSessionPressure ?? cfg?.session?.activePressure ?? {};
|
|
8077
8084
|
if (raw?.rotateAfterCompaction === false) return null;
|
|
8078
|
-
|
|
8085
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: the legacy transcriptBytes threshold no longer exists; the rotation size budget keeps its historical 1 MiB-derived default so default rotation behavior is unchanged. */
|
|
8086
|
+
const threshold = 1048576;
|
|
8079
8087
|
const configuredMax = compactionRotationNumber(raw.rotationMaxBytes, 0);
|
|
8080
|
-
const maxBytes = configuredMax > 0 ? configuredMax :
|
|
8088
|
+
const maxBytes = configuredMax > 0 ? configuredMax : Math.max(131072, Math.min(524288, Math.floor(threshold * .45)));
|
|
8081
8089
|
return {
|
|
8082
8090
|
maxBytes,
|
|
8083
8091
|
maxMessages: Math.max(4, Math.floor(compactionRotationNumber(raw.rotationMaxMessages, 80))),
|
|
@@ -8213,18 +8221,20 @@ async function maybeRefreshActiveSessionForPressure(params) {
|
|
|
8213
8221
|
const heapUsedBytes = typeof process?.memoryUsage === "function" ? process.memoryUsage().heapUsed : 0;
|
|
8214
8222
|
const __hasCompactedContext = Array.isArray(params.session.messages) && params.session.messages.some((message) => message?.role === "compactionSummary");
|
|
8215
8223
|
const __alreadyRotated = params.sessionManager.getEntries?.().some((entry) => entry?.type === "custom" && entry?.customType === "johnness.compaction-session-rotation");
|
|
8216
|
-
|
|
8224
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: the existing-compacted-lineage rotation follows the same single context-token trigger; the byte gate is gone (family 74). */
|
|
8225
|
+
const __cwcWindowTokens = localPressureGuardContextWindowTokens(params.session?.model);
|
|
8226
|
+
const __cwcThresholdTokens = localPressureGuardContextThreshold(settings, __cwcWindowTokens, params.config);
|
|
8227
|
+
const __cwcEstimatedTokens = estimateMessagesTokens(messages);
|
|
8228
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens && __hasCompactedContext && !__alreadyRotated) {
|
|
8217
8229
|
const __existingRotation = await rotateCompactedSessionLineage({ config: params.config, session: params.session, sessionManager: params.sessionManager, sessionFile: params.sessionFile, sessionKey: params.sessionKey, sessionId: params.sessionId, reason: "existing-compacted-lineage" });
|
|
8218
8230
|
if (__existingRotation.rotated) return { refreshed: true, rotated: true, reasons: ["existing-compacted-lineage"], transcriptBytes: __existingRotation.transcriptBytes, messageCount: __existingRotation.messageCount, heapUsedBytes, sessionId: __existingRotation.sessionId, sessionFile: __existingRotation.sessionFile, oldSessionId: __existingRotation.oldSessionId, oldSessionFile: __existingRotation.oldSessionFile };
|
|
8219
8231
|
}
|
|
8220
8232
|
const reasons = [];
|
|
8221
|
-
/*
|
|
8233
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single trigger — estimated active-context tokens vs the context-window threshold (family 74). Legacy byte/message/heap heuristics no longer gate; the family 22 append-only baseline below is computed and recorded for observability only. */
|
|
8222
8234
|
const __aopBaselineBytes = computeActivePressureBaselineBytes(params.sessionManager);
|
|
8223
8235
|
const __aopEffectiveBytes = effectiveTranscriptPressureBytes(transcriptBytes, __aopBaselineBytes);
|
|
8224
|
-
if (
|
|
8225
|
-
if (
|
|
8226
|
-
if (settings.heapUsedBytes > 0 && heapUsedBytes >= settings.heapUsedBytes) reasons.push("heapUsed=" + heapUsedBytes + "/" + settings.heapUsedBytes);
|
|
8227
|
-
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", transcriptBytes, messageCount, heapUsedBytes };
|
|
8236
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens) reasons.push("contextTokens=" + __cwcEstimatedTokens + "/" + __cwcThresholdTokens);
|
|
8237
|
+
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", contextTokens: __cwcEstimatedTokens, contextThreshold: __cwcThresholdTokens, baselineBytes: __aopBaselineBytes, effectiveTranscriptBytes: __aopEffectiveBytes, transcriptBytes, messageCount, heapUsedBytes };
|
|
8228
8238
|
let last = 0;
|
|
8229
8239
|
let lastFailed = false;
|
|
8230
8240
|
let lastBytes = 0;
|
|
@@ -16150,13 +16160,14 @@ async function maybeCompactActiveRunForPressure(params) {
|
|
|
16150
16160
|
} catch {}
|
|
16151
16161
|
const heapUsedBytes = typeof process?.memoryUsage === "function" ? process.memoryUsage().heapUsed : 0;
|
|
16152
16162
|
const reasons = [];
|
|
16153
|
-
/*
|
|
16163
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single trigger — estimated active-context tokens vs the context-window threshold (family 74). Legacy byte/message/heap heuristics no longer gate; the family 22 append-only baseline below is computed and recorded for observability only. */
|
|
16154
16164
|
const __aopBaselineBytes = computeActivePressureBaselineBytes(params.sessionManager);
|
|
16155
16165
|
const __aopEffectiveBytes = effectiveTranscriptPressureBytes(transcriptBytes, __aopBaselineBytes);
|
|
16156
|
-
|
|
16157
|
-
|
|
16158
|
-
|
|
16159
|
-
if (
|
|
16166
|
+
const __cwcWindowTokens = localPressureGuardContextWindowTokens(params.session?.model);
|
|
16167
|
+
const __cwcThresholdTokens = localPressureGuardContextThreshold(settings, __cwcWindowTokens, params.config);
|
|
16168
|
+
const __cwcEstimatedTokens = estimateMessagesTokens(messages);
|
|
16169
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens) reasons.push("contextTokens=" + __cwcEstimatedTokens + "/" + __cwcThresholdTokens);
|
|
16170
|
+
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", contextTokens: __cwcEstimatedTokens, contextThreshold: __cwcThresholdTokens, baselineBytes: __aopBaselineBytes, effectiveTranscriptBytes: __aopEffectiveBytes, transcriptBytes, messageCount, heapUsedBytes };
|
|
16160
16171
|
let last = 0;
|
|
16161
16172
|
let lastFailed = false;
|
|
16162
16173
|
let lastBytes = 0;
|
|
@@ -96130,9 +96130,7 @@ function buildEmbeddedExtensionFactories(params) {
|
|
|
96130
96130
|
|
|
96131
96131
|
//#region johnness local active-session pressure guard
|
|
96132
96132
|
const LOCAL_PRESSURE_GUARD_DEFAULTS = {
|
|
96133
|
-
|
|
96134
|
-
messageCount: 220,
|
|
96135
|
-
heapUsedBytes: 3221225472,
|
|
96133
|
+
contextRatio: 0.7,
|
|
96136
96134
|
minIntervalMs: 300000,
|
|
96137
96135
|
minMessagesAfterCompaction: 24
|
|
96138
96136
|
};
|
|
@@ -96143,14 +96141,24 @@ function localPressureGuardNumber(value, fallback) {
|
|
|
96143
96141
|
function localPressureGuardSettings(cfg) {
|
|
96144
96142
|
const raw = cfg?.agents?.defaults?.activeSessionPressure ?? cfg?.session?.activePressure ?? {};
|
|
96145
96143
|
if (raw?.enabled === false) return null;
|
|
96144
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: legacy transcriptBytes/messageCount/heapUsedBytes keys are accepted without error and ignored. Config surface: enabled, contextRatio, minIntervalMs, minMessagesAfterCompaction. */
|
|
96145
|
+
const contextRatio = localPressureGuardNumber(raw.contextRatio, LOCAL_PRESSURE_GUARD_DEFAULTS.contextRatio);
|
|
96146
96146
|
return {
|
|
96147
|
-
|
|
96148
|
-
messageCount: localPressureGuardNumber(raw.messageCount ?? raw.maxMessages, LOCAL_PRESSURE_GUARD_DEFAULTS.messageCount),
|
|
96149
|
-
heapUsedBytes: localPressureGuardNumber(raw.heapUsedBytes ?? raw.maxHeapUsedBytes, LOCAL_PRESSURE_GUARD_DEFAULTS.heapUsedBytes),
|
|
96147
|
+
contextRatio: contextRatio > 0 ? contextRatio : LOCAL_PRESSURE_GUARD_DEFAULTS.contextRatio,
|
|
96150
96148
|
minIntervalMs: localPressureGuardNumber(raw.minIntervalMs, LOCAL_PRESSURE_GUARD_DEFAULTS.minIntervalMs),
|
|
96151
96149
|
minMessagesAfterCompaction: localPressureGuardNumber(raw.minMessagesAfterCompaction, LOCAL_PRESSURE_GUARD_DEFAULTS.minMessagesAfterCompaction)
|
|
96152
96150
|
};
|
|
96153
96151
|
}
|
|
96152
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single pressure trigger — estimated active-context tokens vs the active model's declared context window; the window falls back to DEFAULT_CONTEXT_TOKENS when undeclared. See docs/PATCHES.md family 74. */
|
|
96153
|
+
function localPressureGuardContextWindowTokens(model) {
|
|
96154
|
+
const declared = typeof model?.contextWindow === "number" && Number.isFinite(model.contextWindow) ? Math.floor(model.contextWindow) : 0;
|
|
96155
|
+
return declared > 0 ? declared : DEFAULT_CONTEXT_TOKENS;
|
|
96156
|
+
}
|
|
96157
|
+
function localPressureGuardContextThreshold(settings, contextWindowTokens, cfg) {
|
|
96158
|
+
const reserveTokensFloor = localPressureGuardNumber(cfg?.agents?.defaults?.compaction?.reserveTokensFloor, 2e4);
|
|
96159
|
+
const floor = Math.max(reserveTokensFloor, 50000);
|
|
96160
|
+
return Math.max(Math.ceil(settings.contextRatio * contextWindowTokens), floor);
|
|
96161
|
+
}
|
|
96154
96162
|
/* JOHNNESS_PATCH_APPEND_ONLY_PRESSURE_BASELINE: derive a restart-safe byte baseline from the append-only JSONL so transcriptBytes pressure measures NEW growth since the last successful compaction rather than total (never-shrinking) file size. See docs/PATCHES.md family 22. Scans getEntries() newest->oldest for the newest SUCCESSFUL johnness.active-pressure-refresh marker (failed !== true) and returns its recorded post-compaction size (postCompactionBytes, else transcriptBytes). Returns 0 for legacy sessions with no such marker, so a first over-limit session still compacts once. */
|
|
96155
96163
|
function computeActivePressureBaselineBytes(sessionManager) {
|
|
96156
96164
|
try {
|
|
@@ -96308,12 +96316,12 @@ function compactionRotationNumber(value, fallback) {
|
|
|
96308
96316
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
96309
96317
|
}
|
|
96310
96318
|
function compactionRotationSettings(cfg) {
|
|
96311
|
-
const pressure = localPressureGuardSettings(cfg) ?? { transcriptBytes: 1048576 };
|
|
96312
96319
|
const raw = cfg?.agents?.defaults?.activeSessionPressure ?? cfg?.session?.activePressure ?? {};
|
|
96313
96320
|
if (raw?.rotateAfterCompaction === false) return null;
|
|
96314
|
-
|
|
96321
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: the legacy transcriptBytes threshold no longer exists; the rotation size budget keeps its historical 1 MiB-derived default so default rotation behavior is unchanged. */
|
|
96322
|
+
const threshold = 1048576;
|
|
96315
96323
|
const configuredMax = compactionRotationNumber(raw.rotationMaxBytes, 0);
|
|
96316
|
-
const maxBytes = configuredMax > 0 ? configuredMax :
|
|
96324
|
+
const maxBytes = configuredMax > 0 ? configuredMax : Math.max(131072, Math.min(524288, Math.floor(threshold * .45)));
|
|
96317
96325
|
return {
|
|
96318
96326
|
maxBytes,
|
|
96319
96327
|
maxMessages: Math.max(4, Math.floor(compactionRotationNumber(raw.rotationMaxMessages, 80))),
|
|
@@ -96449,18 +96457,20 @@ async function maybeRefreshActiveSessionForPressure(params) {
|
|
|
96449
96457
|
const heapUsedBytes = typeof process?.memoryUsage === "function" ? process.memoryUsage().heapUsed : 0;
|
|
96450
96458
|
const __hasCompactedContext = Array.isArray(params.session.messages) && params.session.messages.some((message) => message?.role === "compactionSummary");
|
|
96451
96459
|
const __alreadyRotated = params.sessionManager.getEntries?.().some((entry) => entry?.type === "custom" && entry?.customType === "johnness.compaction-session-rotation");
|
|
96452
|
-
|
|
96460
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: the existing-compacted-lineage rotation follows the same single context-token trigger; the byte gate is gone (family 74). */
|
|
96461
|
+
const __cwcWindowTokens = localPressureGuardContextWindowTokens(params.session?.model);
|
|
96462
|
+
const __cwcThresholdTokens = localPressureGuardContextThreshold(settings, __cwcWindowTokens, params.config);
|
|
96463
|
+
const __cwcEstimatedTokens = estimateMessagesTokens(messages);
|
|
96464
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens && __hasCompactedContext && !__alreadyRotated) {
|
|
96453
96465
|
const __existingRotation = await rotateCompactedSessionLineage({ config: params.config, session: params.session, sessionManager: params.sessionManager, sessionFile: params.sessionFile, sessionKey: params.sessionKey, sessionId: params.sessionId, reason: "existing-compacted-lineage" });
|
|
96454
96466
|
if (__existingRotation.rotated) return { refreshed: true, rotated: true, reasons: ["existing-compacted-lineage"], transcriptBytes: __existingRotation.transcriptBytes, messageCount: __existingRotation.messageCount, heapUsedBytes, sessionId: __existingRotation.sessionId, sessionFile: __existingRotation.sessionFile, oldSessionId: __existingRotation.oldSessionId, oldSessionFile: __existingRotation.oldSessionFile };
|
|
96455
96467
|
}
|
|
96456
96468
|
const reasons = [];
|
|
96457
|
-
/*
|
|
96469
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single trigger — estimated active-context tokens vs the context-window threshold (family 74). Legacy byte/message/heap heuristics no longer gate; the family 22 append-only baseline below is computed and recorded for observability only. */
|
|
96458
96470
|
const __aopBaselineBytes = computeActivePressureBaselineBytes(params.sessionManager);
|
|
96459
96471
|
const __aopEffectiveBytes = effectiveTranscriptPressureBytes(transcriptBytes, __aopBaselineBytes);
|
|
96460
|
-
if (
|
|
96461
|
-
if (
|
|
96462
|
-
if (settings.heapUsedBytes > 0 && heapUsedBytes >= settings.heapUsedBytes) reasons.push("heapUsed=" + heapUsedBytes + "/" + settings.heapUsedBytes);
|
|
96463
|
-
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", transcriptBytes, messageCount, heapUsedBytes };
|
|
96472
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens) reasons.push("contextTokens=" + __cwcEstimatedTokens + "/" + __cwcThresholdTokens);
|
|
96473
|
+
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", contextTokens: __cwcEstimatedTokens, contextThreshold: __cwcThresholdTokens, baselineBytes: __aopBaselineBytes, effectiveTranscriptBytes: __aopEffectiveBytes, transcriptBytes, messageCount, heapUsedBytes };
|
|
96464
96474
|
let last = 0;
|
|
96465
96475
|
let lastFailed = false;
|
|
96466
96476
|
let lastBytes = 0;
|
|
@@ -101878,13 +101888,14 @@ async function maybeCompactActiveRunForPressure(params) {
|
|
|
101878
101888
|
} catch {}
|
|
101879
101889
|
const heapUsedBytes = typeof process?.memoryUsage === "function" ? process.memoryUsage().heapUsed : 0;
|
|
101880
101890
|
const reasons = [];
|
|
101881
|
-
/*
|
|
101891
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single trigger — estimated active-context tokens vs the context-window threshold (family 74). Legacy byte/message/heap heuristics no longer gate; the family 22 append-only baseline below is computed and recorded for observability only. */
|
|
101882
101892
|
const __aopBaselineBytes = computeActivePressureBaselineBytes(params.sessionManager);
|
|
101883
101893
|
const __aopEffectiveBytes = effectiveTranscriptPressureBytes(transcriptBytes, __aopBaselineBytes);
|
|
101884
|
-
|
|
101885
|
-
|
|
101886
|
-
|
|
101887
|
-
if (
|
|
101894
|
+
const __cwcWindowTokens = localPressureGuardContextWindowTokens(params.session?.model);
|
|
101895
|
+
const __cwcThresholdTokens = localPressureGuardContextThreshold(settings, __cwcWindowTokens, params.config);
|
|
101896
|
+
const __cwcEstimatedTokens = estimateMessagesTokens(messages);
|
|
101897
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens) reasons.push("contextTokens=" + __cwcEstimatedTokens + "/" + __cwcThresholdTokens);
|
|
101898
|
+
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", contextTokens: __cwcEstimatedTokens, contextThreshold: __cwcThresholdTokens, baselineBytes: __aopBaselineBytes, effectiveTranscriptBytes: __aopEffectiveBytes, transcriptBytes, messageCount, heapUsedBytes };
|
|
101888
101899
|
let last = 0;
|
|
101889
101900
|
let lastFailed = false;
|
|
101890
101901
|
let lastBytes = 0;
|
|
@@ -96120,9 +96120,7 @@ function buildEmbeddedExtensionFactories(params) {
|
|
|
96120
96120
|
|
|
96121
96121
|
//#region johnness local active-session pressure guard
|
|
96122
96122
|
const LOCAL_PRESSURE_GUARD_DEFAULTS = {
|
|
96123
|
-
|
|
96124
|
-
messageCount: 220,
|
|
96125
|
-
heapUsedBytes: 3221225472,
|
|
96123
|
+
contextRatio: 0.7,
|
|
96126
96124
|
minIntervalMs: 300000,
|
|
96127
96125
|
minMessagesAfterCompaction: 24
|
|
96128
96126
|
};
|
|
@@ -96133,14 +96131,24 @@ function localPressureGuardNumber(value, fallback) {
|
|
|
96133
96131
|
function localPressureGuardSettings(cfg) {
|
|
96134
96132
|
const raw = cfg?.agents?.defaults?.activeSessionPressure ?? cfg?.session?.activePressure ?? {};
|
|
96135
96133
|
if (raw?.enabled === false) return null;
|
|
96134
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: legacy transcriptBytes/messageCount/heapUsedBytes keys are accepted without error and ignored. Config surface: enabled, contextRatio, minIntervalMs, minMessagesAfterCompaction. */
|
|
96135
|
+
const contextRatio = localPressureGuardNumber(raw.contextRatio, LOCAL_PRESSURE_GUARD_DEFAULTS.contextRatio);
|
|
96136
96136
|
return {
|
|
96137
|
-
|
|
96138
|
-
messageCount: localPressureGuardNumber(raw.messageCount ?? raw.maxMessages, LOCAL_PRESSURE_GUARD_DEFAULTS.messageCount),
|
|
96139
|
-
heapUsedBytes: localPressureGuardNumber(raw.heapUsedBytes ?? raw.maxHeapUsedBytes, LOCAL_PRESSURE_GUARD_DEFAULTS.heapUsedBytes),
|
|
96137
|
+
contextRatio: contextRatio > 0 ? contextRatio : LOCAL_PRESSURE_GUARD_DEFAULTS.contextRatio,
|
|
96140
96138
|
minIntervalMs: localPressureGuardNumber(raw.minIntervalMs, LOCAL_PRESSURE_GUARD_DEFAULTS.minIntervalMs),
|
|
96141
96139
|
minMessagesAfterCompaction: localPressureGuardNumber(raw.minMessagesAfterCompaction, LOCAL_PRESSURE_GUARD_DEFAULTS.minMessagesAfterCompaction)
|
|
96142
96140
|
};
|
|
96143
96141
|
}
|
|
96142
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single pressure trigger — estimated active-context tokens vs the active model's declared context window; the window falls back to DEFAULT_CONTEXT_TOKENS when undeclared. See docs/PATCHES.md family 74. */
|
|
96143
|
+
function localPressureGuardContextWindowTokens(model) {
|
|
96144
|
+
const declared = typeof model?.contextWindow === "number" && Number.isFinite(model.contextWindow) ? Math.floor(model.contextWindow) : 0;
|
|
96145
|
+
return declared > 0 ? declared : DEFAULT_CONTEXT_TOKENS;
|
|
96146
|
+
}
|
|
96147
|
+
function localPressureGuardContextThreshold(settings, contextWindowTokens, cfg) {
|
|
96148
|
+
const reserveTokensFloor = localPressureGuardNumber(cfg?.agents?.defaults?.compaction?.reserveTokensFloor, 2e4);
|
|
96149
|
+
const floor = Math.max(reserveTokensFloor, 50000);
|
|
96150
|
+
return Math.max(Math.ceil(settings.contextRatio * contextWindowTokens), floor);
|
|
96151
|
+
}
|
|
96144
96152
|
/* JOHNNESS_PATCH_APPEND_ONLY_PRESSURE_BASELINE: derive a restart-safe byte baseline from the append-only JSONL so transcriptBytes pressure measures NEW growth since the last successful compaction rather than total (never-shrinking) file size. See docs/PATCHES.md family 22. Scans getEntries() newest->oldest for the newest SUCCESSFUL johnness.active-pressure-refresh marker (failed !== true) and returns its recorded post-compaction size (postCompactionBytes, else transcriptBytes). Returns 0 for legacy sessions with no such marker, so a first over-limit session still compacts once. */
|
|
96145
96153
|
function computeActivePressureBaselineBytes(sessionManager) {
|
|
96146
96154
|
try {
|
|
@@ -96298,12 +96306,12 @@ function compactionRotationNumber(value, fallback) {
|
|
|
96298
96306
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
96299
96307
|
}
|
|
96300
96308
|
function compactionRotationSettings(cfg) {
|
|
96301
|
-
const pressure = localPressureGuardSettings(cfg) ?? { transcriptBytes: 1048576 };
|
|
96302
96309
|
const raw = cfg?.agents?.defaults?.activeSessionPressure ?? cfg?.session?.activePressure ?? {};
|
|
96303
96310
|
if (raw?.rotateAfterCompaction === false) return null;
|
|
96304
|
-
|
|
96311
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: the legacy transcriptBytes threshold no longer exists; the rotation size budget keeps its historical 1 MiB-derived default so default rotation behavior is unchanged. */
|
|
96312
|
+
const threshold = 1048576;
|
|
96305
96313
|
const configuredMax = compactionRotationNumber(raw.rotationMaxBytes, 0);
|
|
96306
|
-
const maxBytes = configuredMax > 0 ? configuredMax :
|
|
96314
|
+
const maxBytes = configuredMax > 0 ? configuredMax : Math.max(131072, Math.min(524288, Math.floor(threshold * .45)));
|
|
96307
96315
|
return {
|
|
96308
96316
|
maxBytes,
|
|
96309
96317
|
maxMessages: Math.max(4, Math.floor(compactionRotationNumber(raw.rotationMaxMessages, 80))),
|
|
@@ -96439,18 +96447,20 @@ async function maybeRefreshActiveSessionForPressure(params) {
|
|
|
96439
96447
|
const heapUsedBytes = typeof process?.memoryUsage === "function" ? process.memoryUsage().heapUsed : 0;
|
|
96440
96448
|
const __hasCompactedContext = Array.isArray(params.session.messages) && params.session.messages.some((message) => message?.role === "compactionSummary");
|
|
96441
96449
|
const __alreadyRotated = params.sessionManager.getEntries?.().some((entry) => entry?.type === "custom" && entry?.customType === "johnness.compaction-session-rotation");
|
|
96442
|
-
|
|
96450
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: the existing-compacted-lineage rotation follows the same single context-token trigger; the byte gate is gone (family 74). */
|
|
96451
|
+
const __cwcWindowTokens = localPressureGuardContextWindowTokens(params.session?.model);
|
|
96452
|
+
const __cwcThresholdTokens = localPressureGuardContextThreshold(settings, __cwcWindowTokens, params.config);
|
|
96453
|
+
const __cwcEstimatedTokens = estimateMessagesTokens(messages);
|
|
96454
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens && __hasCompactedContext && !__alreadyRotated) {
|
|
96443
96455
|
const __existingRotation = await rotateCompactedSessionLineage({ config: params.config, session: params.session, sessionManager: params.sessionManager, sessionFile: params.sessionFile, sessionKey: params.sessionKey, sessionId: params.sessionId, reason: "existing-compacted-lineage" });
|
|
96444
96456
|
if (__existingRotation.rotated) return { refreshed: true, rotated: true, reasons: ["existing-compacted-lineage"], transcriptBytes: __existingRotation.transcriptBytes, messageCount: __existingRotation.messageCount, heapUsedBytes, sessionId: __existingRotation.sessionId, sessionFile: __existingRotation.sessionFile, oldSessionId: __existingRotation.oldSessionId, oldSessionFile: __existingRotation.oldSessionFile };
|
|
96445
96457
|
}
|
|
96446
96458
|
const reasons = [];
|
|
96447
|
-
/*
|
|
96459
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single trigger — estimated active-context tokens vs the context-window threshold (family 74). Legacy byte/message/heap heuristics no longer gate; the family 22 append-only baseline below is computed and recorded for observability only. */
|
|
96448
96460
|
const __aopBaselineBytes = computeActivePressureBaselineBytes(params.sessionManager);
|
|
96449
96461
|
const __aopEffectiveBytes = effectiveTranscriptPressureBytes(transcriptBytes, __aopBaselineBytes);
|
|
96450
|
-
if (
|
|
96451
|
-
if (
|
|
96452
|
-
if (settings.heapUsedBytes > 0 && heapUsedBytes >= settings.heapUsedBytes) reasons.push("heapUsed=" + heapUsedBytes + "/" + settings.heapUsedBytes);
|
|
96453
|
-
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", transcriptBytes, messageCount, heapUsedBytes };
|
|
96462
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens) reasons.push("contextTokens=" + __cwcEstimatedTokens + "/" + __cwcThresholdTokens);
|
|
96463
|
+
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", contextTokens: __cwcEstimatedTokens, contextThreshold: __cwcThresholdTokens, baselineBytes: __aopBaselineBytes, effectiveTranscriptBytes: __aopEffectiveBytes, transcriptBytes, messageCount, heapUsedBytes };
|
|
96454
96464
|
let last = 0;
|
|
96455
96465
|
let lastFailed = false;
|
|
96456
96466
|
let lastBytes = 0;
|
|
@@ -101868,13 +101878,14 @@ async function maybeCompactActiveRunForPressure(params) {
|
|
|
101868
101878
|
} catch {}
|
|
101869
101879
|
const heapUsedBytes = typeof process?.memoryUsage === "function" ? process.memoryUsage().heapUsed : 0;
|
|
101870
101880
|
const reasons = [];
|
|
101871
|
-
/*
|
|
101881
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single trigger — estimated active-context tokens vs the context-window threshold (family 74). Legacy byte/message/heap heuristics no longer gate; the family 22 append-only baseline below is computed and recorded for observability only. */
|
|
101872
101882
|
const __aopBaselineBytes = computeActivePressureBaselineBytes(params.sessionManager);
|
|
101873
101883
|
const __aopEffectiveBytes = effectiveTranscriptPressureBytes(transcriptBytes, __aopBaselineBytes);
|
|
101874
|
-
|
|
101875
|
-
|
|
101876
|
-
|
|
101877
|
-
if (
|
|
101884
|
+
const __cwcWindowTokens = localPressureGuardContextWindowTokens(params.session?.model);
|
|
101885
|
+
const __cwcThresholdTokens = localPressureGuardContextThreshold(settings, __cwcWindowTokens, params.config);
|
|
101886
|
+
const __cwcEstimatedTokens = estimateMessagesTokens(messages);
|
|
101887
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens) reasons.push("contextTokens=" + __cwcEstimatedTokens + "/" + __cwcThresholdTokens);
|
|
101888
|
+
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", contextTokens: __cwcEstimatedTokens, contextThreshold: __cwcThresholdTokens, baselineBytes: __aopBaselineBytes, effectiveTranscriptBytes: __aopEffectiveBytes, transcriptBytes, messageCount, heapUsedBytes };
|
|
101878
101889
|
let last = 0;
|
|
101879
101890
|
let lastFailed = false;
|
|
101880
101891
|
let lastBytes = 0;
|
package/dist/reply-C5LKjXcC.js
CHANGED
|
@@ -74132,9 +74132,7 @@ function buildEmbeddedExtensionFactories(params) {
|
|
|
74132
74132
|
|
|
74133
74133
|
//#region johnness local active-session pressure guard
|
|
74134
74134
|
const LOCAL_PRESSURE_GUARD_DEFAULTS = {
|
|
74135
|
-
|
|
74136
|
-
messageCount: 220,
|
|
74137
|
-
heapUsedBytes: 3221225472,
|
|
74135
|
+
contextRatio: 0.7,
|
|
74138
74136
|
minIntervalMs: 300000,
|
|
74139
74137
|
minMessagesAfterCompaction: 24
|
|
74140
74138
|
};
|
|
@@ -74145,14 +74143,24 @@ function localPressureGuardNumber(value, fallback) {
|
|
|
74145
74143
|
function localPressureGuardSettings(cfg) {
|
|
74146
74144
|
const raw = cfg?.agents?.defaults?.activeSessionPressure ?? cfg?.session?.activePressure ?? {};
|
|
74147
74145
|
if (raw?.enabled === false) return null;
|
|
74146
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: legacy transcriptBytes/messageCount/heapUsedBytes keys are accepted without error and ignored. Config surface: enabled, contextRatio, minIntervalMs, minMessagesAfterCompaction. */
|
|
74147
|
+
const contextRatio = localPressureGuardNumber(raw.contextRatio, LOCAL_PRESSURE_GUARD_DEFAULTS.contextRatio);
|
|
74148
74148
|
return {
|
|
74149
|
-
|
|
74150
|
-
messageCount: localPressureGuardNumber(raw.messageCount ?? raw.maxMessages, LOCAL_PRESSURE_GUARD_DEFAULTS.messageCount),
|
|
74151
|
-
heapUsedBytes: localPressureGuardNumber(raw.heapUsedBytes ?? raw.maxHeapUsedBytes, LOCAL_PRESSURE_GUARD_DEFAULTS.heapUsedBytes),
|
|
74149
|
+
contextRatio: contextRatio > 0 ? contextRatio : LOCAL_PRESSURE_GUARD_DEFAULTS.contextRatio,
|
|
74152
74150
|
minIntervalMs: localPressureGuardNumber(raw.minIntervalMs, LOCAL_PRESSURE_GUARD_DEFAULTS.minIntervalMs),
|
|
74153
74151
|
minMessagesAfterCompaction: localPressureGuardNumber(raw.minMessagesAfterCompaction, LOCAL_PRESSURE_GUARD_DEFAULTS.minMessagesAfterCompaction)
|
|
74154
74152
|
};
|
|
74155
74153
|
}
|
|
74154
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single pressure trigger — estimated active-context tokens vs the active model's declared context window; the window falls back to DEFAULT_CONTEXT_TOKENS when undeclared. See docs/PATCHES.md family 74. */
|
|
74155
|
+
function localPressureGuardContextWindowTokens(model) {
|
|
74156
|
+
const declared = typeof model?.contextWindow === "number" && Number.isFinite(model.contextWindow) ? Math.floor(model.contextWindow) : 0;
|
|
74157
|
+
return declared > 0 ? declared : DEFAULT_CONTEXT_TOKENS;
|
|
74158
|
+
}
|
|
74159
|
+
function localPressureGuardContextThreshold(settings, contextWindowTokens, cfg) {
|
|
74160
|
+
const reserveTokensFloor = localPressureGuardNumber(cfg?.agents?.defaults?.compaction?.reserveTokensFloor, 2e4);
|
|
74161
|
+
const floor = Math.max(reserveTokensFloor, 50000);
|
|
74162
|
+
return Math.max(Math.ceil(settings.contextRatio * contextWindowTokens), floor);
|
|
74163
|
+
}
|
|
74156
74164
|
/* JOHNNESS_PATCH_APPEND_ONLY_PRESSURE_BASELINE: derive a restart-safe byte baseline from the append-only JSONL so transcriptBytes pressure measures NEW growth since the last successful compaction rather than total (never-shrinking) file size. See docs/PATCHES.md family 22. Scans getEntries() newest->oldest for the newest SUCCESSFUL johnness.active-pressure-refresh marker (failed !== true) and returns its recorded post-compaction size (postCompactionBytes, else transcriptBytes). Returns 0 for legacy sessions with no such marker, so a first over-limit session still compacts once. */
|
|
74157
74165
|
function computeActivePressureBaselineBytes(sessionManager) {
|
|
74158
74166
|
try {
|
|
@@ -74310,12 +74318,12 @@ function compactionRotationNumber(value, fallback) {
|
|
|
74310
74318
|
return Number.isFinite(parsed) && parsed >= 0 ? parsed : fallback;
|
|
74311
74319
|
}
|
|
74312
74320
|
function compactionRotationSettings(cfg) {
|
|
74313
|
-
const pressure = localPressureGuardSettings(cfg) ?? { transcriptBytes: 1048576 };
|
|
74314
74321
|
const raw = cfg?.agents?.defaults?.activeSessionPressure ?? cfg?.session?.activePressure ?? {};
|
|
74315
74322
|
if (raw?.rotateAfterCompaction === false) return null;
|
|
74316
|
-
|
|
74323
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: the legacy transcriptBytes threshold no longer exists; the rotation size budget keeps its historical 1 MiB-derived default so default rotation behavior is unchanged. */
|
|
74324
|
+
const threshold = 1048576;
|
|
74317
74325
|
const configuredMax = compactionRotationNumber(raw.rotationMaxBytes, 0);
|
|
74318
|
-
const maxBytes = configuredMax > 0 ? configuredMax :
|
|
74326
|
+
const maxBytes = configuredMax > 0 ? configuredMax : Math.max(131072, Math.min(524288, Math.floor(threshold * .45)));
|
|
74319
74327
|
return {
|
|
74320
74328
|
maxBytes,
|
|
74321
74329
|
maxMessages: Math.max(4, Math.floor(compactionRotationNumber(raw.rotationMaxMessages, 80))),
|
|
@@ -74451,18 +74459,20 @@ async function maybeRefreshActiveSessionForPressure(params) {
|
|
|
74451
74459
|
const heapUsedBytes = typeof process?.memoryUsage === "function" ? process.memoryUsage().heapUsed : 0;
|
|
74452
74460
|
const __hasCompactedContext = Array.isArray(params.session.messages) && params.session.messages.some((message) => message?.role === "compactionSummary");
|
|
74453
74461
|
const __alreadyRotated = params.sessionManager.getEntries?.().some((entry) => entry?.type === "custom" && entry?.customType === "johnness.compaction-session-rotation");
|
|
74454
|
-
|
|
74462
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: the existing-compacted-lineage rotation follows the same single context-token trigger; the byte gate is gone (family 74). */
|
|
74463
|
+
const __cwcWindowTokens = localPressureGuardContextWindowTokens(params.session?.model);
|
|
74464
|
+
const __cwcThresholdTokens = localPressureGuardContextThreshold(settings, __cwcWindowTokens, params.config);
|
|
74465
|
+
const __cwcEstimatedTokens = estimateMessagesTokens(messages);
|
|
74466
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens && __hasCompactedContext && !__alreadyRotated) {
|
|
74455
74467
|
const __existingRotation = await rotateCompactedSessionLineage({ config: params.config, session: params.session, sessionManager: params.sessionManager, sessionFile: params.sessionFile, sessionKey: params.sessionKey, sessionId: params.sessionId, reason: "existing-compacted-lineage" });
|
|
74456
74468
|
if (__existingRotation.rotated) return { refreshed: true, rotated: true, reasons: ["existing-compacted-lineage"], transcriptBytes: __existingRotation.transcriptBytes, messageCount: __existingRotation.messageCount, heapUsedBytes, sessionId: __existingRotation.sessionId, sessionFile: __existingRotation.sessionFile, oldSessionId: __existingRotation.oldSessionId, oldSessionFile: __existingRotation.oldSessionFile };
|
|
74457
74469
|
}
|
|
74458
74470
|
const reasons = [];
|
|
74459
|
-
/*
|
|
74471
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single trigger — estimated active-context tokens vs the context-window threshold (family 74). Legacy byte/message/heap heuristics no longer gate; the family 22 append-only baseline below is computed and recorded for observability only. */
|
|
74460
74472
|
const __aopBaselineBytes = computeActivePressureBaselineBytes(params.sessionManager);
|
|
74461
74473
|
const __aopEffectiveBytes = effectiveTranscriptPressureBytes(transcriptBytes, __aopBaselineBytes);
|
|
74462
|
-
if (
|
|
74463
|
-
if (
|
|
74464
|
-
if (settings.heapUsedBytes > 0 && heapUsedBytes >= settings.heapUsedBytes) reasons.push("heapUsed=" + heapUsedBytes + "/" + settings.heapUsedBytes);
|
|
74465
|
-
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", transcriptBytes, messageCount, heapUsedBytes };
|
|
74474
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens) reasons.push("contextTokens=" + __cwcEstimatedTokens + "/" + __cwcThresholdTokens);
|
|
74475
|
+
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", contextTokens: __cwcEstimatedTokens, contextThreshold: __cwcThresholdTokens, baselineBytes: __aopBaselineBytes, effectiveTranscriptBytes: __aopEffectiveBytes, transcriptBytes, messageCount, heapUsedBytes };
|
|
74466
74476
|
let last = 0;
|
|
74467
74477
|
let lastFailed = false;
|
|
74468
74478
|
let lastBytes = 0;
|
|
@@ -79883,13 +79893,14 @@ async function maybeCompactActiveRunForPressure(params) {
|
|
|
79883
79893
|
} catch {}
|
|
79884
79894
|
const heapUsedBytes = typeof process?.memoryUsage === "function" ? process.memoryUsage().heapUsed : 0;
|
|
79885
79895
|
const reasons = [];
|
|
79886
|
-
/*
|
|
79896
|
+
/* JOHNNESS_PATCH_CONTEXT_WINDOW_COMPACTION: single trigger — estimated active-context tokens vs the context-window threshold (family 74). Legacy byte/message/heap heuristics no longer gate; the family 22 append-only baseline below is computed and recorded for observability only. */
|
|
79887
79897
|
const __aopBaselineBytes = computeActivePressureBaselineBytes(params.sessionManager);
|
|
79888
79898
|
const __aopEffectiveBytes = effectiveTranscriptPressureBytes(transcriptBytes, __aopBaselineBytes);
|
|
79889
|
-
|
|
79890
|
-
|
|
79891
|
-
|
|
79892
|
-
if (
|
|
79899
|
+
const __cwcWindowTokens = localPressureGuardContextWindowTokens(params.session?.model);
|
|
79900
|
+
const __cwcThresholdTokens = localPressureGuardContextThreshold(settings, __cwcWindowTokens, params.config);
|
|
79901
|
+
const __cwcEstimatedTokens = estimateMessagesTokens(messages);
|
|
79902
|
+
if (__cwcEstimatedTokens >= __cwcThresholdTokens) reasons.push("contextTokens=" + __cwcEstimatedTokens + "/" + __cwcThresholdTokens);
|
|
79903
|
+
if (reasons.length === 0) return { refreshed: false, reason: "below threshold", contextTokens: __cwcEstimatedTokens, contextThreshold: __cwcThresholdTokens, baselineBytes: __aopBaselineBytes, effectiveTranscriptBytes: __aopEffectiveBytes, transcriptBytes, messageCount, heapUsedBytes };
|
|
79893
79904
|
let last = 0;
|
|
79894
79905
|
let lastFailed = false;
|
|
79895
79906
|
let lastBytes = 0;
|
package/docs/PATCHES.md
CHANGED
|
@@ -17,7 +17,7 @@ they predate ~2026-06-06).
|
|
|
17
17
|
|
|
18
18
|
## Index
|
|
19
19
|
|
|
20
|
-
Family 01 is retired. Families 02 through 41, 43 through
|
|
20
|
+
Family 01 is retired. Families 02 through 41, 43 through 74, including the 65.1 amendment, are live on `main`; the `latest` and `extended` release lines converged at 2026.9.24. Family 42 is omitted; native Codex OAuth ownership is Family 58.
|
|
21
21
|
|
|
22
22
|
1. **01, announce queue TTL, retired:** Removed the five-minute age filter that could discard delayed sub-agent completion announcements. [Details](#01--announce-ttl-retired-2026-07-30)
|
|
23
23
|
2. **02, failover rotation:** Returns model selection to the highest-priority profile after its cooldown ends. [Details](#02--failover-rotation-undocumented)
|
|
@@ -99,6 +99,7 @@ Family 01 is retired. Families 02 through 41, 43 through 72, including the 65.1
|
|
|
99
99
|
|
|
100
100
|
72. **72, bundled generic skills:** Eight workspace skills (code operations, research, todos, planning, logs, and more) ship as generic bundled skills that load by description match, with no owner names or personal paths. [Details](#family-72-bundled-generic-skills)
|
|
101
101
|
73. **73, prune bundled skills:** `content-story`, `dashboard` and `cold-outreach` are removed from the Family 72 bundled set on request after `2026.9.25`; the remaining eight ship unchanged. [Details](#family-73-prune-bundled-skills)
|
|
102
|
+
74. **74, context-window compaction:** The local active-session pressure guard becomes single-trigger and model-aware: estimated active-context tokens against 70% of the active model's declared context window, floored at `max(compaction.reserveTokensFloor, 50000)`; the 1 MB byte, 220-message and 3 GiB heap triggers are removed. [Details](#family-74-context-window-compaction)
|
|
102
103
|
|
|
103
104
|
---
|
|
104
105
|
|
|
@@ -729,6 +730,7 @@ already-compacting / compaction-disabled / cooldown are no-ops.
|
|
|
729
730
|
---
|
|
730
731
|
|
|
731
732
|
## 22 - append-only-pressure-baseline (2026-07-29)
|
|
733
|
+
**Superseded by Family 74:** the append-only baseline is still computed and recorded on the `active-pressure-refresh` marker (see below), but nothing gates on it any more; the pressure trigger is now estimated context tokens against the active model's declared context window.
|
|
732
734
|
**What:** The active-pressure `transcriptBytes` trigger now measures **NEW transcript
|
|
733
735
|
growth since the last successful compaction** instead of the total, never-shrinking
|
|
734
736
|
append-only file size. This removes the false-retrigger loop where a session that has
|
|
@@ -2669,3 +2671,17 @@ Three of the Family 72 bundled skills are removed from the bundled set on reques
|
|
|
2669
2671
|
The counters move with the set: the verifier emits one check per remaining skill through the same 72.1 loop (455 checks in total), `tests/bundled-skills.test.mjs` asserts exactly eight bundled skills, `scripts/check-packed-artifact.mjs` fails closed unless a tarball carries all eight with frontmatter, and `README.md` and the pinned copy in `patches/59-migrate-cli.patch` carry the new counts together so check 59c stays green. `RULES.md` section 5 drops the three rows.
|
|
2670
2672
|
|
|
2671
2673
|
Roll back with `npm i -g johns-harness@2026.9.25`.
|
|
2674
|
+
|
|
2675
|
+
## Family 74: context-window compaction
|
|
2676
|
+
|
|
2677
|
+
**Release:** `johns-harness@2026.9.27`. Published as `latest` and the `extended` dist-tag moves to it.
|
|
2678
|
+
|
|
2679
|
+
A live gateway session compacted at `messages=221/220` while its transcript held only 528 KB of a 1,048,576-byte budget. The guard was firing on a fixed message count, which is the wrong unit: 221 small messages can sit comfortably inside a large context window, and a few large tool outputs can overflow a small one. Family 74 makes the local active-session pressure guard single-trigger and model-aware.
|
|
2680
|
+
|
|
2681
|
+
The only trigger is estimated active-context tokens (`estimateMessagesTokens`, the estimator the compaction path already uses) against `max(ceil(contextRatio x activeModel.contextWindow), max(compaction.reserveTokensFloor, 50000))`, with `contextRatio` defaulting to 0.7. A model that declares no `contextWindow` falls back to the runtime default. Both the startup rotation gate and the in-loop refresh push only `contextTokens=<n>/<threshold>`.
|
|
2682
|
+
|
|
2683
|
+
The `transcriptBytes` (1 MB), `messageCount` (220) and `heapUsedBytes` (3 GiB) triggers are removed by design; the legacy config keys are accepted without error and ignored. The 5-minute cooldown, the 24-message post-compaction floor and the failed-attempt growth gate stay as anti-thrash throttles, and the emergency compaction path (Family 13) is untouched, so a genuine overflow is still caught. The Family 22 append-only baseline is still computed and recorded on the `active-pressure-refresh` marker for observability, but nothing gates on it. The config surface is `enabled`, `contextRatio`, `minIntervalMs`, `minMessagesAfterCompaction`.
|
|
2684
|
+
|
|
2685
|
+
Verifier checks 74.1 through 74.4 prove the marker, the absence of the byte/message/heap triggers, the threshold math and the config parsing in all four pressure bundles; `scripts/patch-context-window-compaction.py` applies the same change to any install root (both naming eras), is idempotent with `--check`, and fails closed on anchor drift. `patches/provider-catalog/changes.json` pins the four pressure bundles by hash, so `scripts/patch-provider-catalog.py` maps the Family 74 rewrite back to its pre-image in `family67_surface`, exactly as it already does for Family 68.
|
|
2686
|
+
|
|
2687
|
+
Roll back with `npm i -g johns-harness@2026.9.26`.
|