@nexus-cortex/core 4.124.38 → 4.124.40

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.
@@ -20,11 +20,11 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
20
20
  import { execSync } from 'node:child_process';
21
21
  import { ENV_RECON_COMMAND, resolveLiftPlanConfig, parsePlannerResponse, bankPlanText } from '../training/liftPlanner.js';
22
22
  import { clipIn, FULL_CAPS, HINTS, resolveInventory, resolveInventoryPath } from '../training/steerInputs.js';
23
- import { resolveEndTurnResolverConfig, parseResolverVerdict, effectiveMaxRejects, budgetedVetoEscalation, decideVetoAction, shouldFinishConfirm, buildFinishConfirmMessage, buildMeetsConfirmMessage, gapHoldable, parseSpecChecks, groundSpecCheck, specFailFraction, applyVetoFloor, holdProgressed, planSimilarity, specCheckEvidence, specBlockForJudge, dropSpecEchoes, specBlockForWriter, vetoMessageLead } from '../training/endTurnResolver.js';
23
+ import { resolveEndTurnResolverConfig, parseResolverVerdict, effectiveMaxRejects, budgetedVetoEscalation, decideVetoAction, shouldFinishConfirm, buildFinishConfirmMessage, buildMeetsConfirmMessage, gapHoldable, parseSpecChecks, groundSpecCheck, specFailFraction, applyVetoFloor, holdProgressed, planSimilarity, specCheckEvidence, specBlockForJudge, dropSpecEchoes, specBlockForWriter, vetoMessageLead, RESOLVER_SCALE_CLAUSE } from '../training/endTurnResolver.js';
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';
@@ -91,6 +91,7 @@ import { pruneAgedToolResults } from '../conversation/ToolResultPruner.js';
91
91
  import { detectTailRepetition, tailLoopGuardEnabled } from './tailRepetitionDetector.js';
92
92
  import { resolveEffortRamp, rampEffortFor } from './effortRamp.js';
93
93
  import { resolveWallDrop, resolveOutputCap, dropWalledTurn, resolveWallSummary, extractWalledReasoning, clipReasoning, formatWallSummary } from './wallGuard.js';
94
+ import { resolvePid1Guard, detectPid1Note } from './pid1Guard.js'; // R209
94
95
  import { resolveComputeNudge, computeNudgeDecision, buildComputeNudgeLine, lastAssistantReasoningTokens } from './computeNudge.js';
95
96
  import { classifyEmptyResponse, emptyResponseNudge, nudgeForbidsTools, emptyResponseNudgeFor, isReasoningExhaustion, stepDownEffort, effortLadderFor, resolveExhaustLadderMode, resolveReasoningExhaustBackoff } from './emptyResponseClassifier.js';
96
97
  import { isImageRejectionError, stripRejectedImages } from './imageRejectionHeal.js'; // R154
@@ -214,6 +215,7 @@ export class CortexOrchestrator {
214
215
  * exactly once, at the anchor-lift boundary. One-shot per orchestrator. */
215
216
  deferredCorpusDelivered = false;
216
217
  liftNudgeDelivered = false; // A′ proposal-1: lift-boundary SearchTools/AskForAdvice nudge, one-shot
218
+ pid1NoteChecked = false; // R209 HB-CONTAINER-PID1: PID 1 inspected once, at the first tool_result boundary
217
219
  // CORTEX_LOOP_TOOL_BLOCK (hard loop intervention): when the ladder flags a
218
220
  // non-converging same-approach loop, disable the looping tool's EXECUTOR for
219
221
  // ONE turn (tools list unchanged → cache-safe); a call to it returns an
@@ -401,6 +403,29 @@ export class CortexOrchestrator {
401
403
  return tools; // interactive: keep it
402
404
  return tools.filter((t) => t.name !== 'AskUserQuestion');
403
405
  }
406
+ /** R209 HB-CONTAINER-PID1 (CORTEX_PID1_GUARD=on, dark): at the first tool_result boundary (the boot observation), when PID 1 is not
407
+ * the harness, append ONE note naming PID 1 and the services it supervises — killing them stops the container and ends the session.
408
+ * Independent of the tool anchor. One-shot; Linux-only; fail-safe (no note on any error). Event pid1_guard when the note is added. */
409
+ deliverPid1NoteAtBoot() {
410
+ if (this.pid1NoteChecked || !resolvePid1Guard())
411
+ return;
412
+ try {
413
+ const lastMsg = this.messageHistory[this.messageHistory.length - 1];
414
+ if (lastMsg?.message?.content?.[0]?.type !== 'tool_result')
415
+ return; // not the boundary yet — leave the one-shot open
416
+ this.pid1NoteChecked = true;
417
+ const r = detectPid1Note();
418
+ if (!r)
419
+ return;
420
+ lastMsg.message.content.push({ type: 'text', text: `<system-reminder>\n${r.note}\n</system-reminder>` });
421
+ const store = this.getDecisionStore();
422
+ if (store)
423
+ void store.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'pid1_guard', detail: { noted: true, pid1Cmd: r.info.pid1Cmd, children: r.info.children, chars: r.note.length } }).catch(() => { });
424
+ if (this.config.debug)
425
+ console.log(`[Pid1Guard] boot note delivered (PID 1 = ${r.info.pid1Cmd}, ${r.info.children.length} child(ren))`);
426
+ }
427
+ catch { /* fail-safe: no note */ }
428
+ }
404
429
  /** A′ proposal-1: at the anchor-lift boundary, when deferred loading is on and
405
430
  * CORTEX_LIFT_NUDGE is truthy, append a MINIMAL system-reminder pointing the model
406
431
  * at SearchTools (to reach the tools the deferred filter hides — names come from
@@ -618,6 +643,8 @@ export class CortexOrchestrator {
618
643
  }
619
644
  catch { /* fail-open */ }
620
645
  }
646
+ /** The session ledger snapshot (exact main usage + helper estimates + sub-agent breakdown) — read by the agent-mode child to report its spend. */
647
+ getSessionUsage() { return this.snapshotSessionUsage(); }
621
648
  /** R190: the session usage with the helper middleware's estimated calls merged in, plus a decision-store row so trajectories carry it. */
622
649
  snapshotSessionUsage() {
623
650
  const h = this.helperMiddleware?.getHelperUsageEstimate?.();
@@ -1288,6 +1315,9 @@ export class CortexOrchestrator {
1288
1315
  // what it judged, not just counts — so a k=5 run can score the resolver's JUDGMENT QUALITY
1289
1316
  // (was the GAP warranted? was the fix plan good? did it judge the right artifact?) and not
1290
1317
  // merely that it fired. Bounded caps keep the decisions row sane. See HARNESS_IMPROVEMENT_BACKLOG.
1318
+ // R208 HB-VERIFY-AT-SCALE (CORTEX_VERIFY_SCALE=on, dark): the judge persona carried the scale rubric item on this adjudication.
1319
+ if (store && cfg.verifyScale)
1320
+ void store.recordEvent({ sessionId, kind: 'verify_scale_item', toolName: 'EndTurn', detail: { surface: 'endturn-resolver', clauseChars: RESOLVER_SCALE_CLAUSE.length, roundsUsed, meets: verdict.meets, parsed: verdict.parsed, confidence: verdict.confidence } }).catch(() => { });
1291
1321
  if (store)
1292
1322
  void store.recordEvent({
1293
1323
  sessionId,
@@ -1307,6 +1337,7 @@ export class CortexOrchestrator {
1307
1337
  derivation: cfg.derivation, derivationAgreement: derivationInfo?.agreement ?? null, derivationHeld: !!derivationHold, // R176
1308
1338
  reqLedger: cfg.reqLedger, reqLines: reqCounts.lines, reqOpen: reqCounts.open, reqExercised: reqCounts.exercised, reqFailed: reqCounts.failed, reqUnverifiable: reqCounts.unverifiable, reqHeld: !!reqHold, reqHolds: this.reqLedgerHolds, reqGenLatencyMs: this.reqLedgerMeta.genLatencyMs, reqJev: cfg.reqLedgerJev, reqJevAsked: reqJev?.asked ?? 0, reqJevClosed: reqJev?.closed ?? [], reqJevLatencyMs: reqJev?.latencyMs ?? 0, // R187/R187b
1309
1339
  reqFailVeto: !!reqFailVeto, reqFailVetoes: this.reqLedgerFailVetoes, reqFailedNow, reqFailJev, // R192
1340
+ verifyScale: cfg.verifyScale, // R208
1310
1341
  reqBroken: [...this.reqLedgerBroken], reqLinesDetail: (this.reqLedger ?? []).map((e) => ({ id: e.id, kind: e.kind, status: e.status, check: !!e.check, runs: e.runs, last: (e.lastResult ?? '').split('\n').slice(0, 2).join(' / ').slice(0, 200) })), // R191: per-line outcomes so a false-failure read is possible from the decisions file
1311
1342
  latencyMs, rawLen: (text ?? '').length,
1312
1343
  deltaChars: workspaceDelta.length, checkRan: !!checkResult, checkPassed: checkResult ? /→ PASSED/.test(checkResult) : null,
@@ -3587,6 +3618,7 @@ export class CortexOrchestrator {
3587
3618
  // Send tool results back to model and get continuation response
3588
3619
  // Proactive context management - ensure history fits before continuation
3589
3620
  await this.ensureHistoryFitsModel(effectiveModel);
3621
+ this.deliverPid1NoteAtBoot(); // R209 HB-CONTAINER-PID1 (dark unless CORTEX_PID1_GUARD): PID 1 note on the boot observation
3590
3622
  // Anchor lift (BASH_PLUS_SPEC.md P0): the first tool call has executed —
3591
3623
  // this continuation is the first tool_result boundary, so the session's
3592
3624
  // full profile applies from here. Rebuild from allTools because the
@@ -5410,6 +5442,7 @@ export class CortexOrchestrator {
5410
5442
  // Send continuation request with tool results
5411
5443
  // Proactive context management - ensure history fits before streaming continuation
5412
5444
  await this.ensureHistoryFitsModel(effectiveModel);
5445
+ this.deliverPid1NoteAtBoot(); // R209 HB-CONTAINER-PID1 — streaming mirror
5413
5446
  // Anchor lift — streaming mirror of the sendMessage continuation path.
5414
5447
  if (!this.anchorLifted &&
5415
5448
  resolveToolAnchor(process.env, this.cardAnchorProfile) &&
@@ -7862,6 +7895,7 @@ export class CortexOrchestrator {
7862
7895
  envOverrides: { ...(timeoutSource === 'deadline' || timeoutSource === 'requested' ? { CORTEX_TURN_DEADLINE_MS: String(timeoutMs) } : {}), ...(envOverrides ?? {}) },
7863
7896
  toolUseId: toolUse.id,
7864
7897
  });
7898
+ this.sessionUsage = addSubagentUsage(this.sessionUsage, subAgentResult.usage); // 2026-10-01: sub-agent spend in the ledger
7865
7899
  // Clean up event listeners after completion
7866
7900
  progressListeners.cleanup();
7867
7901
  if (this.config.debug) {
@@ -8117,6 +8151,7 @@ export class CortexOrchestrator {
8117
8151
  envOverrides: { ...(timeoutSource === 'deadline' || timeoutSource === 'requested' ? { CORTEX_TURN_DEADLINE_MS: String(timeoutMs) } : {}), ...(envOverrides ?? {}) },
8118
8152
  toolUseId: toolUse.id,
8119
8153
  });
8154
+ this.sessionUsage = addSubagentUsage(this.sessionUsage, subAgentResult.usage); // 2026-10-01: sub-agent spend in the ledger
8120
8155
  progressListeners.cleanup();
8121
8156
  const formattedResult = this.formatSubAgentResultForLLM(subAgentResult);
8122
8157
  const rawContent = typeof formattedResult === 'string' ? formattedResult : JSON.stringify(formattedResult);