@nexus-cortex/core 4.124.37 → 4.124.39
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 +32 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +3 -0
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/middleware/HelperModelMiddleware.d.ts +9 -0
- package/dist/middleware/HelperModelMiddleware.d.ts.map +1 -1
- package/dist/middleware/HelperModelMiddleware.js +18 -0
- package/dist/middleware/HelperModelMiddleware.js.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.d.ts +10 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +81 -11
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/orchestrator/SubAgentTypes.d.ts +2 -0
- package/dist/orchestrator/SubAgentTypes.d.ts.map +1 -1
- package/dist/orchestrator/wallGuard.d.ts +31 -0
- package/dist/orchestrator/wallGuard.d.ts.map +1 -0
- package/dist/orchestrator/wallGuard.js +82 -0
- package/dist/orchestrator/wallGuard.js.map +1 -0
- package/dist/training/DecisionStore.d.ts +1 -1
- package/dist/training/DecisionStore.d.ts.map +1 -1
- package/dist/training/DecisionStore.js.map +1 -1
- package/dist/training/usageAccounting.d.ts +17 -0
- package/dist/training/usageAccounting.d.ts.map +1 -1
- package/dist/training/usageAccounting.js +21 -2
- package/dist/training/usageAccounting.js.map +1 -1
- package/package.json +3 -3
|
@@ -24,7 +24,7 @@ import { resolveEndTurnResolverConfig, parseResolverVerdict, effectiveMaxRejects
|
|
|
24
24
|
import { jevAvailable, jevNoul, buildGapHoldState, GAP_HOLD_QUESTIONS } from '../training/jevGate.js'; // R173b
|
|
25
25
|
import { resolveFrameConfig, FRAME_CONTRACT, FRAME_TOOL_NAME } from '../frames/frameConfig.js'; // R179
|
|
26
26
|
import { FrameRunner } from '../frames/frameRunner.js'; // R179
|
|
27
|
-
import { emptySessionUsage, addMainUsage } from '../training/usageAccounting.js'; // R190
|
|
27
|
+
import { emptySessionUsage, addMainUsage, addSubagentUsage } from '../training/usageAccounting.js'; // R190
|
|
28
28
|
import { parseRequirementLedger, initLedger, updateLedger, ledgerCounts, ledgerHoldable, formatLedgerForWriter, formatLedgerForJudge, formatLedgerHoldMessage, buildLedgerJevState, buildLedgerJevQuestions, applyLedgerJevAnswers, looksLikeBrokenCheck, ledgerFailVetoable, buildLedgerFailJevState, buildLedgerFailJevQuestions, applyLedgerFailJevAnswers, formatLedgerFailVetoMessage } from '../training/requirementLedger.js'; // R187 / R191 / R192
|
|
29
29
|
import { isValueShapedTask, parseDerivationReply, methodsDiffer, parseValueLines, extractNumbers, reconcile, buildDerivationHoldMessage, isDerivationCommandAllowed, checkRunPassed, checkRunBody } from '../training/independentDerivation.js'; // R176
|
|
30
30
|
import { resolveDeadlineExitConfig, deadlineExitCallBudget, parseDeadlineExitVerdict } from '../training/deadlineExitMentor.js';
|
|
@@ -90,6 +90,7 @@ import { InitCortexContext, MemoryWrite, MemoryRecall } from '../tools/context-m
|
|
|
90
90
|
import { pruneAgedToolResults } from '../conversation/ToolResultPruner.js';
|
|
91
91
|
import { detectTailRepetition, tailLoopGuardEnabled } from './tailRepetitionDetector.js';
|
|
92
92
|
import { resolveEffortRamp, rampEffortFor } from './effortRamp.js';
|
|
93
|
+
import { resolveWallDrop, resolveOutputCap, dropWalledTurn, resolveWallSummary, extractWalledReasoning, clipReasoning, formatWallSummary } from './wallGuard.js';
|
|
93
94
|
import { resolveComputeNudge, computeNudgeDecision, buildComputeNudgeLine, lastAssistantReasoningTokens } from './computeNudge.js';
|
|
94
95
|
import { classifyEmptyResponse, emptyResponseNudge, nudgeForbidsTools, emptyResponseNudgeFor, isReasoningExhaustion, stepDownEffort, effortLadderFor, resolveExhaustLadderMode, resolveReasoningExhaustBackoff } from './emptyResponseClassifier.js';
|
|
95
96
|
import { isImageRejectionError, stripRejectedImages } from './imageRejectionHeal.js'; // R154
|
|
@@ -617,6 +618,8 @@ export class CortexOrchestrator {
|
|
|
617
618
|
}
|
|
618
619
|
catch { /* fail-open */ }
|
|
619
620
|
}
|
|
621
|
+
/** The session ledger snapshot (exact main usage + helper estimates + sub-agent breakdown) — read by the agent-mode child to report its spend. */
|
|
622
|
+
getSessionUsage() { return this.snapshotSessionUsage(); }
|
|
620
623
|
/** R190: the session usage with the helper middleware's estimated calls merged in, plus a decision-store row so trajectories carry it. */
|
|
621
624
|
snapshotSessionUsage() {
|
|
622
625
|
const h = this.helperMiddleware?.getHelperUsageEstimate?.();
|
|
@@ -1707,6 +1710,7 @@ export class CortexOrchestrator {
|
|
|
1707
1710
|
if (!this.sessionTimeline) {
|
|
1708
1711
|
throw new Error('Session not initialized. Call createSession() first.');
|
|
1709
1712
|
}
|
|
1713
|
+
this.applyOutputCap(options); // HB-OUTPUT-CAP (dark)
|
|
1710
1714
|
// Item 10: full-mass pre-assembly boundary — doctrine curation completes
|
|
1711
1715
|
// BEFORE the turn-0 prompt is built (under defer this no-ops here and the
|
|
1712
1716
|
// lift boundary awaits instead; one-shot flag makes both calls safe).
|
|
@@ -2572,6 +2576,10 @@ export class CortexOrchestrator {
|
|
|
2572
2576
|
console.warn(`[Orchestrator] Empty response detected (${emptyClass.kind}, hadReasoning=${emptyClass.hadReasoning}, iteration=${toolCallIteration}). ` +
|
|
2573
2577
|
`Retrying once with explicit completion prompt.`);
|
|
2574
2578
|
const exhaustionLevel = this.armReasoningBackoffIfExhausted(emptyClass, options.parameters?.reasoningEffort ?? effectiveModel?.reasoning?.effort, toolCallIteration, currentAssistantMessage?.usage?.outputTokens, effectiveModel.provider);
|
|
2579
|
+
// HB-WALL-DROP (CORTEX_WALL_DROP, dark): drop the walled turn + carry the nudge on the newest tool_result (cache-preserving retry).
|
|
2580
|
+
const wallSummary = await this.summarizeWall(emptyClass, toolCallIteration, false); // HB-WALL-SUMMARY (dark); '' when off/failed
|
|
2581
|
+
const wallNudge = `<system-reminder>${emptyResponseNudgeFor(emptyClass, exhaustionLevel, effectiveModel?.limits?.outputTokens)}${nudgeForbidsTools(emptyClass.kind) ? ' Do not call any more tools.' : ''}${wallSummary}</system-reminder>`;
|
|
2582
|
+
const wallDrop = this.applyWallDrop(emptyClass, wallNudge, toolCallIteration, false);
|
|
2575
2583
|
// R26 (2026-05-15, surfaced by A/B benchmark): the empty assistant
|
|
2576
2584
|
// turn is already in messageHistory. The retry below rebuilds the
|
|
2577
2585
|
// full history and re-sends it. Anthropic's Messages API tolerates
|
|
@@ -2580,8 +2588,8 @@ export class CortexOrchestrator {
|
|
|
2580
2588
|
// the entire retry. R18b was validated on Claude, so this was
|
|
2581
2589
|
// invisible until a grok run emitted an empty turn. Repair the
|
|
2582
2590
|
// empty assistant message in-place with a minimal placeholder so
|
|
2583
|
-
// every provider's message-content contract is satisfied.
|
|
2584
|
-
for (let i = this.messageHistory.length - 1; i >= 0; i--) {
|
|
2591
|
+
// every provider's message-content contract is satisfied. (Skipped when HB-WALL-DROP removed the turn.)
|
|
2592
|
+
for (let i = wallDrop.dropped ? -1 : this.messageHistory.length - 1; i >= 0; i--) {
|
|
2585
2593
|
const m = this.messageHistory[i];
|
|
2586
2594
|
const isAssistant = m?.type === 'assistant' || m?.message?.role === 'assistant';
|
|
2587
2595
|
if (!isAssistant)
|
|
@@ -2610,7 +2618,7 @@ export class CortexOrchestrator {
|
|
|
2610
2618
|
role: 'user',
|
|
2611
2619
|
content: [{
|
|
2612
2620
|
type: 'text',
|
|
2613
|
-
text:
|
|
2621
|
+
text: wallNudge,
|
|
2614
2622
|
}],
|
|
2615
2623
|
},
|
|
2616
2624
|
timeline: {
|
|
@@ -2624,8 +2632,10 @@ export class CortexOrchestrator {
|
|
|
2624
2632
|
apiPattern: effectiveModel.api.pattern,
|
|
2625
2633
|
},
|
|
2626
2634
|
};
|
|
2627
|
-
|
|
2628
|
-
|
|
2635
|
+
if (wallDrop.carrier !== 'tool_result') { // HB-WALL-DROP carried the nudge on the newest tool_result already
|
|
2636
|
+
this.messageHistory.push(followupUserMessage);
|
|
2637
|
+
await this.historyStore.appendMessage(this.currentSessionId, followupUserMessage);
|
|
2638
|
+
}
|
|
2629
2639
|
// Build a continuation request and re-call. Mirrors the
|
|
2630
2640
|
// tool-result continuation path (lines ~1395-1466) but without
|
|
2631
2641
|
// tool_result blocks.
|
|
@@ -4130,6 +4140,7 @@ export class CortexOrchestrator {
|
|
|
4130
4140
|
if (!this.currentSessionId || !this.sessionTimeline) {
|
|
4131
4141
|
throw new Error('Session not initialized. Call createSession() first.');
|
|
4132
4142
|
}
|
|
4143
|
+
this.applyOutputCap(options); // HB-OUTPUT-CAP (dark)
|
|
4133
4144
|
// Graduation-signal capture (Decision Capture Layer §5) — same as sendMessage:
|
|
4134
4145
|
// score the previous turn's prediction against THIS user message + record.
|
|
4135
4146
|
if (this.pendingTurnPrediction && this.pendingTurnPrediction.sessionId === this.currentSessionId) {
|
|
@@ -4778,8 +4789,12 @@ export class CortexOrchestrator {
|
|
|
4778
4789
|
console.warn(`[Orchestrator Streaming] R32/R18b: Empty response (${emptyClass.kind}, iteration=${toolCallIteration}). ` +
|
|
4779
4790
|
`Retrying with tools preserved.`);
|
|
4780
4791
|
const exhaustionLevel = this.armReasoningBackoffIfExhausted(emptyClass, options.parameters?.reasoningEffort ?? effectiveModel?.reasoning?.effort, toolCallIteration, this.messageHistory[this.messageHistory.length - 1]?.usage?.outputTokens, effectiveModel.provider);
|
|
4781
|
-
//
|
|
4782
|
-
|
|
4792
|
+
// HB-WALL-DROP (streaming parity).
|
|
4793
|
+
const wallSummary = await this.summarizeWall(emptyClass, toolCallIteration, true);
|
|
4794
|
+
const wallNudge = `<system-reminder>${emptyResponseNudgeFor(emptyClass, exhaustionLevel, effectiveModel?.limits?.outputTokens)}${nudgeForbidsTools(emptyClass.kind) ? ' Do not call any more tools.' : ''}${wallSummary}</system-reminder>`;
|
|
4795
|
+
const wallDrop = this.applyWallDrop(emptyClass, wallNudge, toolCallIteration, true);
|
|
4796
|
+
// R26 repair: ensure the empty assistant turn has content (xAI hard-400s on empty). Skipped when HB-WALL-DROP removed it.
|
|
4797
|
+
for (let i = wallDrop.dropped ? -1 : this.messageHistory.length - 1; i >= 0; i--) {
|
|
4783
4798
|
const m = this.messageHistory[i];
|
|
4784
4799
|
const isAssistant = m?.type === 'assistant' || m?.message?.role === 'assistant';
|
|
4785
4800
|
if (!isAssistant)
|
|
@@ -4802,7 +4817,7 @@ export class CortexOrchestrator {
|
|
|
4802
4817
|
role: 'user',
|
|
4803
4818
|
content: [{
|
|
4804
4819
|
type: 'text',
|
|
4805
|
-
text:
|
|
4820
|
+
text: wallNudge,
|
|
4806
4821
|
}],
|
|
4807
4822
|
},
|
|
4808
4823
|
timeline: {
|
|
@@ -4816,8 +4831,10 @@ export class CortexOrchestrator {
|
|
|
4816
4831
|
apiPattern: effectiveModel.api.pattern,
|
|
4817
4832
|
},
|
|
4818
4833
|
};
|
|
4819
|
-
|
|
4820
|
-
|
|
4834
|
+
if (wallDrop.carrier !== 'tool_result') {
|
|
4835
|
+
this.messageHistory.push(followupUserMessage);
|
|
4836
|
+
await this.historyStore.appendMessage(this.currentSessionId, followupUserMessage);
|
|
4837
|
+
}
|
|
4821
4838
|
try {
|
|
4822
4839
|
await this.ensureHistoryFitsModel(effectiveModel);
|
|
4823
4840
|
const retryEffort = this.consumeReasoningBackoff() ?? options.parameters?.reasoningEffort; // R153 backoff > request param
|
|
@@ -7847,6 +7864,7 @@ export class CortexOrchestrator {
|
|
|
7847
7864
|
envOverrides: { ...(timeoutSource === 'deadline' || timeoutSource === 'requested' ? { CORTEX_TURN_DEADLINE_MS: String(timeoutMs) } : {}), ...(envOverrides ?? {}) },
|
|
7848
7865
|
toolUseId: toolUse.id,
|
|
7849
7866
|
});
|
|
7867
|
+
this.sessionUsage = addSubagentUsage(this.sessionUsage, subAgentResult.usage); // 2026-10-01: sub-agent spend in the ledger
|
|
7850
7868
|
// Clean up event listeners after completion
|
|
7851
7869
|
progressListeners.cleanup();
|
|
7852
7870
|
if (this.config.debug) {
|
|
@@ -8102,6 +8120,7 @@ export class CortexOrchestrator {
|
|
|
8102
8120
|
envOverrides: { ...(timeoutSource === 'deadline' || timeoutSource === 'requested' ? { CORTEX_TURN_DEADLINE_MS: String(timeoutMs) } : {}), ...(envOverrides ?? {}) },
|
|
8103
8121
|
toolUseId: toolUse.id,
|
|
8104
8122
|
});
|
|
8123
|
+
this.sessionUsage = addSubagentUsage(this.sessionUsage, subAgentResult.usage); // 2026-10-01: sub-agent spend in the ledger
|
|
8105
8124
|
progressListeners.cleanup();
|
|
8106
8125
|
const formattedResult = this.formatSubAgentResultForLLM(subAgentResult);
|
|
8107
8126
|
const rawContent = typeof formattedResult === 'string' ? formattedResult : JSON.stringify(formattedResult);
|
|
@@ -9219,6 +9238,57 @@ export class CortexOrchestrator {
|
|
|
9219
9238
|
return undefined;
|
|
9220
9239
|
}
|
|
9221
9240
|
}
|
|
9241
|
+
/** HB-WALL-SUMMARY (CORTEX_WALL_SUMMARY=on, dark): one helper call condensing the walled turn's reasoning; returns the attributed block for
|
|
9242
|
+
* the nudge, or '' (off / not a reasoning wall / no reasoning / timeout / error). Must run BEFORE HB-WALL-DROP removes the turn. */
|
|
9243
|
+
async summarizeWall(cls, iteration, streaming) {
|
|
9244
|
+
const cfg = resolveWallSummary();
|
|
9245
|
+
if (!cfg.enabled || !isReasoningExhaustion(cls) || !this.helperMiddleware?.summarizeWalledThinking)
|
|
9246
|
+
return '';
|
|
9247
|
+
const t0 = Date.now();
|
|
9248
|
+
let block = '';
|
|
9249
|
+
let inputChars = 0;
|
|
9250
|
+
let ok = false;
|
|
9251
|
+
try {
|
|
9252
|
+
const reasoning = extractWalledReasoning(this.messageHistory);
|
|
9253
|
+
inputChars = reasoning.length;
|
|
9254
|
+
if (reasoning.trim()) {
|
|
9255
|
+
const reply = await withTimeout(this.helperMiddleware.summarizeWalledThinking({ reasoning: clipReasoning(reasoning, cfg.headChars, cfg.tailChars), helperModelId: this.config.reactiveMentorship?.helperModelId }), cfg.timeoutMs);
|
|
9256
|
+
block = formatWallSummary(typeof reply === 'string' ? reply : '');
|
|
9257
|
+
ok = !!block;
|
|
9258
|
+
}
|
|
9259
|
+
}
|
|
9260
|
+
catch {
|
|
9261
|
+
block = '';
|
|
9262
|
+
}
|
|
9263
|
+
const store = this.getDecisionStore();
|
|
9264
|
+
if (store)
|
|
9265
|
+
void store.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'wall_summary', detail: { iteration, inputChars, summaryChars: block.length, ok, ms: Date.now() - t0, streaming } }).catch(() => { });
|
|
9266
|
+
return block;
|
|
9267
|
+
}
|
|
9268
|
+
/** HB-OUTPUT-CAP (CORTEX_OUTPUT_CAP_TOKENS, dark): fills the action model's maxTokens when the request did not set one. */
|
|
9269
|
+
applyOutputCap(options) {
|
|
9270
|
+
const cap = resolveOutputCap();
|
|
9271
|
+
if (!cap)
|
|
9272
|
+
return;
|
|
9273
|
+
options.parameters = options.parameters || {};
|
|
9274
|
+
options.parameters.maxTokens ??= cap;
|
|
9275
|
+
}
|
|
9276
|
+
/** HB-WALL-DROP (CORTEX_WALL_DROP=on, dark): on a reasoning-exhaustion wall, drop the walled turn from the in-memory history and carry
|
|
9277
|
+
* the nudge on the newest tool_result; one wall_drop event per drop. Fail-open (no drop). */
|
|
9278
|
+
applyWallDrop(cls, nudge, iteration, streaming) {
|
|
9279
|
+
try {
|
|
9280
|
+
if (!isReasoningExhaustion(cls) || !resolveWallDrop())
|
|
9281
|
+
return { dropped: false };
|
|
9282
|
+
const r = dropWalledTurn(this.messageHistory, nudge);
|
|
9283
|
+
const store = this.getDecisionStore();
|
|
9284
|
+
if (r.dropped && store)
|
|
9285
|
+
void store.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'wall_drop', detail: { iteration, droppedChars: r.droppedChars, carrier: r.carrier, streaming } }).catch(() => { });
|
|
9286
|
+
return r;
|
|
9287
|
+
}
|
|
9288
|
+
catch {
|
|
9289
|
+
return { dropped: false };
|
|
9290
|
+
}
|
|
9291
|
+
}
|
|
9222
9292
|
/**
|
|
9223
9293
|
* HB-COMPUTE-NUDGE (CORTEX_COMPUTE_NUDGE=on, dark): when the response that issued this round reasoned past the threshold,
|
|
9224
9294
|
* append one 'compute/test instead of deliberating' line to the tail of the newest tool_result (the HB-TURN-STATUS carrier —
|