@nexus-cortex/core 4.108.2 → 4.108.4
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/.env.defaults +22 -0
- package/dist/config/RuntimeConfigRegistry.d.ts.map +1 -1
- package/dist/config/RuntimeConfigRegistry.js +1 -0
- package/dist/config/RuntimeConfigRegistry.js.map +1 -1
- package/dist/config/SettingsLoader.d.ts.map +1 -1
- package/dist/config/SettingsLoader.js +1 -0
- package/dist/config/SettingsLoader.js.map +1 -1
- package/dist/config/SettingsSchema.d.ts +1 -0
- package/dist/config/SettingsSchema.d.ts.map +1 -1
- package/dist/config/SettingsSchema.js +9 -0
- package/dist/config/SettingsSchema.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +1 -0
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.d.ts +6 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +82 -16
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/orchestrator/compactionResume.d.ts +27 -1
- package/dist/orchestrator/compactionResume.d.ts.map +1 -1
- package/dist/orchestrator/compactionResume.js +74 -2
- package/dist/orchestrator/compactionResume.js.map +1 -1
- package/dist/orchestrator/compactionResumeTemplate.d.ts +9 -1
- package/dist/orchestrator/compactionResumeTemplate.d.ts.map +1 -1
- package/dist/orchestrator/compactionResumeTemplate.js +20 -2
- package/dist/orchestrator/compactionResumeTemplate.js.map +1 -1
- package/dist/system-messages/SystemReminderInjector.d.ts +3 -1
- package/dist/system-messages/SystemReminderInjector.d.ts.map +1 -1
- package/dist/system-messages/SystemReminderInjector.js +5 -2
- package/dist/system-messages/SystemReminderInjector.js.map +1 -1
- package/package.json +3 -3
|
@@ -16,7 +16,7 @@ import { sanitizeHistoryForDisplay } from './displayHistorySanitizer.js';
|
|
|
16
16
|
import { verifyCoordinates, deterministicCoordinateScore } from './coordinateVerification.js';
|
|
17
17
|
import { buildRouterSample, appendJsonlRotating } from './cortexTrainingRecord.js';
|
|
18
18
|
import { join as pathJoin } from 'path';
|
|
19
|
-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
19
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
20
20
|
import { execSync } from 'node:child_process';
|
|
21
21
|
import { ENV_RECON_COMMAND, resolveLiftPlanConfig } from '../training/liftPlanner.js';
|
|
22
22
|
import { resolveEndTurnResolverConfig, parseResolverVerdict } from '../training/endTurnResolver.js';
|
|
@@ -38,8 +38,8 @@ import { toolFactory } from '../tools/ToolFactory.js';
|
|
|
38
38
|
import { resolveToolProfile, resolveToolAnchor, resolveFrameProfile, resolveLiftNudge, resolveLiftPlan, resolveEndTurnResolver, resolveHeadlessDropAskUser, resolveDeferredLoading, isNarrowProfile, isToolAllowedByProfile, applyToolProfile, webToolBlocked, resolveVisionHelperModel, resolveVisionHandoffMax, resolveSliceNudge, resolveSliceBlock, resolveSliceBlockAt, resolveSliceBlockMax } from '../tools/ToolProfile.js';
|
|
39
39
|
import { sliceReadFile, decideSliceBlock } from './sliceBlock.js';
|
|
40
40
|
import { TurnEvidence, evaluateEndTurnGates, buildMissingEndTurnReminder } from './endTurnGates.js';
|
|
41
|
-
import { resolveCompactionResume,
|
|
42
|
-
import { renderResumeMemoryPrompt, buildRebuildInstructions, resolveCheckpointBand } from './compactionResumeTemplate.js';
|
|
41
|
+
import { resolveCompactionResume, pickDropped, buildCompactionResumeReminder, isCompactionResumeMessage, resolveTaskText, resumeMemoryTargetTokens, coversAll, buildRollingSeedMessage, memoryIndexLine, upsertMemoryIndex } from './compactionResume.js';
|
|
42
|
+
import { renderResumeMemoryPrompt, buildRebuildInstructions, resolveCheckpointBand, resolveRearmBand } from './compactionResumeTemplate.js';
|
|
43
43
|
import { collectWorkspaceDelta, detectCheckCommand, runCheck, resolveJudgeGroundingConfig } from '../training/judgeEvidence.js';
|
|
44
44
|
import { resolveMentorRoleConfig, describeMentorWire, describeMentorDelivery, mentorSurfaceTimeoutMs } from '../training/mentorRole.js';
|
|
45
45
|
import { resolveOuterToolDeadlineMs } from './outerToolTimeout.js';
|
|
@@ -115,6 +115,9 @@ export class CortexOrchestrator {
|
|
|
115
115
|
/** HB-COMPACTION-RESUME v2: pressure-rung checkpoint state (once per band; reused at compaction). */
|
|
116
116
|
lastCheckpointBand = 0;
|
|
117
117
|
lastResumeMemory = null;
|
|
118
|
+
pinnedTaskText = '';
|
|
119
|
+
/** 4.108.4: session start — the mtime floor for the non-git workspace delta at compaction. */
|
|
120
|
+
sessionStartMs = Date.now();
|
|
118
121
|
/** Pending TURN_SUMMARY_PREDICTION awaiting the user's ACTUAL next message —
|
|
119
122
|
* scored + recorded at the next sendMessage (graduation-signal capture,
|
|
120
123
|
* Decision Capture Layer §5). In-memory only; lost on restart by design. */
|
|
@@ -5689,12 +5692,40 @@ export class CortexOrchestrator {
|
|
|
5689
5692
|
/** HB-COMPACTION-RESUME: best-effort write of the resume memory to .cortex/memory/resume-<session>.md (synchronous fs). */
|
|
5690
5693
|
writeResumeMemoryFile(text, why) {
|
|
5691
5694
|
try {
|
|
5692
|
-
const
|
|
5695
|
+
const cortexDir = pathJoin(this.config.projectPath || process.cwd(), '.cortex');
|
|
5696
|
+
const dir = pathJoin(cortexDir, 'memory');
|
|
5693
5697
|
mkdirSync(dir, { recursive: true });
|
|
5694
|
-
|
|
5698
|
+
const name = `resume-${this.currentSessionId}`;
|
|
5699
|
+
writeFileSync(pathJoin(dir, `${name}.md`), `---\nname: ${name}\ndescription: resume memory — ${why}\ntype: project\n---\n${text}\n`);
|
|
5700
|
+
// 4.108.4: index it in .cortex/MEMORY.md (the harness's two-tier memory) so MemoryRecall and a resumed session can find it.
|
|
5701
|
+
const indexPath = pathJoin(cortexDir, 'MEMORY.md');
|
|
5702
|
+
let current = '';
|
|
5703
|
+
try {
|
|
5704
|
+
current = readFileSync(indexPath, 'utf8');
|
|
5705
|
+
}
|
|
5706
|
+
catch {
|
|
5707
|
+
current = '';
|
|
5708
|
+
}
|
|
5709
|
+
writeFileSync(indexPath, upsertMemoryIndex(current, name, memoryIndexLine(name, `resume memory (${why}) — load after a context compaction or session resume`)));
|
|
5695
5710
|
}
|
|
5696
5711
|
catch { /* best-effort */ }
|
|
5697
5712
|
}
|
|
5713
|
+
/** 4.108.4: the working tree as it is RIGHT NOW — git state when the workspace is a repo (forced past the per-turn lever), else
|
|
5714
|
+
* the mtime-based file delta since session start. Read from disk at compaction; capped so it cannot crowd the kept history. */
|
|
5715
|
+
buildCompactionWorkspaceState() {
|
|
5716
|
+
try {
|
|
5717
|
+
const root = process.env.PROJECT_ROOT || this.config.projectPath || this.config.workingDirectory || process.cwd();
|
|
5718
|
+
let state = this.systemReminderInjector.buildGitContextSection(root, { force: true }) ?? '';
|
|
5719
|
+
if (!state.trim()) {
|
|
5720
|
+
state = collectWorkspaceDelta(root, this.sessionStartMs, { ...resolveJudgeGroundingConfig(), delta: true, deltaMaxFiles: 0 });
|
|
5721
|
+
}
|
|
5722
|
+
const MAX = 2500;
|
|
5723
|
+
return state.length > MAX ? state.slice(0, MAX) + '\n[… workspace state truncated]' : state;
|
|
5724
|
+
}
|
|
5725
|
+
catch {
|
|
5726
|
+
return '';
|
|
5727
|
+
}
|
|
5728
|
+
}
|
|
5698
5729
|
async ensureHistoryFitsModel(model) {
|
|
5699
5730
|
// Capture the active model's context window for request-build-time
|
|
5700
5731
|
// pruning (pruneAgedForRequest) — set before any early return so the
|
|
@@ -5720,8 +5751,13 @@ export class CortexOrchestrator {
|
|
|
5720
5751
|
actualToolTokens: this.currentToolTokens,
|
|
5721
5752
|
actualSystemTokens: 0
|
|
5722
5753
|
};
|
|
5723
|
-
// Calculate compaction threshold using model's configuration (with accurate overrides)
|
|
5724
|
-
|
|
5754
|
+
// Calculate compaction threshold using model's configuration (with accurate overrides).
|
|
5755
|
+
// CORTEX_COMPACTION_THRESHOLD_TOKENS (4.108.3, test/ops override): a positive integer replaces the card-derived threshold so the
|
|
5756
|
+
// checkpoint rung + compaction can be exercised in a short live run (efficacy proof before any long-horizon bench).
|
|
5757
|
+
const thresholdOverride = Number(String(process.env.CORTEX_COMPACTION_THRESHOLD_TOKENS ?? '').trim() || 0);
|
|
5758
|
+
const threshold = thresholdOverride > 0
|
|
5759
|
+
? thresholdOverride
|
|
5760
|
+
: this.contextBudgetManager.getCompactionThreshold(model, budgetOverrides);
|
|
5725
5761
|
if (this.config.debug) {
|
|
5726
5762
|
console.log(`[Orchestrator Context] Current tokens: ${currentTokens}, Threshold: ${threshold} (tool reserve: ${this.currentToolTokens})`);
|
|
5727
5763
|
}
|
|
@@ -5734,10 +5770,12 @@ export class CortexOrchestrator {
|
|
|
5734
5770
|
if (band > this.lastCheckpointBand) {
|
|
5735
5771
|
this.lastCheckpointBand = band;
|
|
5736
5772
|
try {
|
|
5737
|
-
const
|
|
5773
|
+
const tgt = resumeMemoryTargetTokens(threshold);
|
|
5774
|
+
const r = await this.helperMiddleware.summarizeForResume(this.convertToCanonicalMessages([...this.messageHistory]), model, tgt, renderResumeMemoryPrompt('{{CONVERSATION}}', tgt));
|
|
5738
5775
|
const text = String(r?.summary ?? '');
|
|
5739
5776
|
if (text.trim()) {
|
|
5740
|
-
this.lastResumeMemory = { text, tokensAt: currentTokens, turn: this.turnNumber, helperModelId: r?.helperModelId, cost: Number(r?.cost ?? 0)
|
|
5777
|
+
this.lastResumeMemory = { text, tokensAt: currentTokens, turn: this.turnNumber, helperModelId: r?.helperModelId, cost: Number(r?.cost ?? 0),
|
|
5778
|
+
covered: new WeakSet(this.messageHistory) };
|
|
5741
5779
|
this.writeResumeMemoryFile(text, `checkpoint band ${band} (${currentTokens}/${threshold} tokens, turn ${this.turnNumber})`);
|
|
5742
5780
|
const store = this.getDecisionStore();
|
|
5743
5781
|
if (store)
|
|
@@ -5762,6 +5800,8 @@ export class CortexOrchestrator {
|
|
|
5762
5800
|
try {
|
|
5763
5801
|
// Calculate available budget for history (with accurate overrides)
|
|
5764
5802
|
const budget = this.contextBudgetManager.calculateBudget(model, budgetOverrides);
|
|
5803
|
+
if (thresholdOverride > 0)
|
|
5804
|
+
budget.availableForHistory = Math.floor(thresholdOverride * 0.5); // override: keep ~half the forced window
|
|
5765
5805
|
// Determine selection strategy based on model configuration
|
|
5766
5806
|
const strategy = model.compaction?.behavior?.compactOlder ? 'preserve-critical' : 'sliding-window';
|
|
5767
5807
|
// Select messages that fit within budget (standard path — no thinking stripping)
|
|
@@ -5780,13 +5820,16 @@ export class CortexOrchestrator {
|
|
|
5780
5820
|
// session JSONL (so a bench can count compactions), (5) .cortex/memory/resume-<session>.md is written.
|
|
5781
5821
|
const compactionResume = resolveCompactionResume();
|
|
5782
5822
|
const dropped = pickDropped(this.messageHistory, selectedMessages);
|
|
5783
|
-
const taskText =
|
|
5823
|
+
const taskText = resolveTaskText(this.messageHistory, this.pinnedTaskText);
|
|
5824
|
+
if (taskText)
|
|
5825
|
+
this.pinnedTaskText = taskText;
|
|
5784
5826
|
let resumeText = '';
|
|
5785
5827
|
let resumeHelper;
|
|
5786
5828
|
let resumeCost = 0;
|
|
5787
5829
|
let memorySource = 'none';
|
|
5788
|
-
//
|
|
5789
|
-
|
|
5830
|
+
// v3 (4.108.3): reuse the checkpoint only if it already covered every message being dropped. The v2 token-distance test went
|
|
5831
|
+
// negative after the first compaction and replayed one stale checkpoint forever (the hardened live proof: 27 compactions, 0 fresh memories).
|
|
5832
|
+
if (compactionResume && this.lastResumeMemory && coversAll(this.lastResumeMemory.covered, dropped)) {
|
|
5790
5833
|
resumeText = this.lastResumeMemory.text;
|
|
5791
5834
|
resumeHelper = this.lastResumeMemory.helperModelId;
|
|
5792
5835
|
resumeCost = 0;
|
|
@@ -5794,11 +5837,22 @@ export class CortexOrchestrator {
|
|
|
5794
5837
|
}
|
|
5795
5838
|
else if (compactionResume && dropped.length > 0 && this.config.useHelperModels && typeof this.helperMiddleware?.summarizeForResume === 'function') {
|
|
5796
5839
|
try {
|
|
5797
|
-
const
|
|
5840
|
+
const tgt = resumeMemoryTargetTokens(threshold);
|
|
5841
|
+
// v3: roll the prior memory forward — the helper summarizes [prior memory, ...newly dropped] into ONE memory.
|
|
5842
|
+
const prior = this.lastResumeMemory;
|
|
5843
|
+
const seed = prior && prior.text.trim() ? [buildRollingSeedMessage(prior.text)] : [];
|
|
5844
|
+
const r = await this.helperMiddleware.summarizeForResume(this.convertToCanonicalMessages([...seed, ...dropped]), model, tgt, renderResumeMemoryPrompt('{{CONVERSATION}}', tgt));
|
|
5798
5845
|
resumeText = String(r?.summary ?? '');
|
|
5799
5846
|
resumeHelper = r?.helperModelId;
|
|
5800
5847
|
resumeCost = Number(r?.cost ?? 0);
|
|
5801
|
-
memorySource = resumeText.trim() ? 'dropped' : 'none';
|
|
5848
|
+
memorySource = resumeText.trim() ? (seed.length ? 'rolled' : 'dropped') : 'none';
|
|
5849
|
+
if (resumeText.trim()) {
|
|
5850
|
+
const covered = prior?.covered ?? new WeakSet();
|
|
5851
|
+
for (const m of dropped)
|
|
5852
|
+
if (m && typeof m === 'object')
|
|
5853
|
+
covered.add(m);
|
|
5854
|
+
this.lastResumeMemory = { text: resumeText, tokensAt: currentTokens, turn: this.turnNumber, helperModelId: resumeHelper, cost: resumeCost, covered };
|
|
5855
|
+
}
|
|
5802
5856
|
}
|
|
5803
5857
|
catch (e) {
|
|
5804
5858
|
console.error('[Orchestrator Context] resume memory summary failed (degrading to task-only reminder):', e?.message ?? e);
|
|
@@ -5807,10 +5861,21 @@ export class CortexOrchestrator {
|
|
|
5807
5861
|
// Update message history with selected messages (dropping any OLDER compaction reminder — the new one supersedes it)
|
|
5808
5862
|
this.messageHistory = compactionResume ? selectedMessages.filter((m) => !isCompactionResumeMessage(m)) : selectedMessages;
|
|
5809
5863
|
if (compactionResume && dropped.length > 0) {
|
|
5864
|
+
// v3: re-arm the checkpoint rung relative to the post-compaction level so a fresh whole-conversation memory is written
|
|
5865
|
+
// again as the context climbs (v2 left lastCheckpointBand at its pre-compaction high-water mark → the rung never re-fired).
|
|
5866
|
+
this.lastCheckpointBand = resolveRearmBand(newTokenCount, threshold);
|
|
5867
|
+
const workspaceState = this.buildCompactionWorkspaceState();
|
|
5868
|
+
let sessionPath;
|
|
5869
|
+
try {
|
|
5870
|
+
sessionPath = this.currentSessionId ? this.historyStore.getSessionPath(this.currentSessionId) : undefined;
|
|
5871
|
+
}
|
|
5872
|
+
catch {
|
|
5873
|
+
sessionPath = undefined;
|
|
5874
|
+
}
|
|
5810
5875
|
const text = buildCompactionResumeReminder({
|
|
5811
5876
|
turn: this.turnNumber, droppedCount: dropped.length, keptCount: this.messageHistory.length,
|
|
5812
5877
|
tokensBefore: currentTokens, tokensAfter: newTokenCount, resumeText, taskText, helperModelId: resumeHelper,
|
|
5813
|
-
rebuild: buildRebuildInstructions(), memorySource,
|
|
5878
|
+
rebuild: buildRebuildInstructions({ sessionPath }), memorySource, workspaceState,
|
|
5814
5879
|
});
|
|
5815
5880
|
const reminder = {
|
|
5816
5881
|
uuid: uuidv4(),
|
|
@@ -5833,7 +5898,8 @@ export class CortexOrchestrator {
|
|
|
5833
5898
|
kind: 'compaction',
|
|
5834
5899
|
detail: { mode: 'proactive', turn: this.turnNumber, tokensBefore: currentTokens, tokensAfter: newTokenCount,
|
|
5835
5900
|
dropped: dropped.length, kept: selectedMessages.length, resumeChars: resumeText.length,
|
|
5836
|
-
helperModelId: resumeHelper ?? null, cost: resumeCost, taskPinned: taskText.length > 0, memorySource
|
|
5901
|
+
helperModelId: resumeHelper ?? null, cost: resumeCost, taskPinned: taskText.length > 0, memorySource,
|
|
5902
|
+
workspaceStateChars: workspaceState.length, sessionPath: sessionPath ?? null },
|
|
5837
5903
|
}).catch(() => { });
|
|
5838
5904
|
if (this.config.debug)
|
|
5839
5905
|
console.log(`[Orchestrator Context] resume reminder injected (${resumeText.length} chars memory, task pinned=${taskText.length > 0})`);
|