@nexus-cortex/core 4.93.0 → 4.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{.env.example → .env.defaults} +93 -25
- package/dist/config/MentorshipConfigService.d.ts +0 -1
- package/dist/config/MentorshipConfigService.d.ts.map +1 -1
- package/dist/config/MentorshipConfigService.js +10 -5
- package/dist/config/MentorshipConfigService.js.map +1 -1
- package/dist/config/SettingsLoader.d.ts +92 -11
- package/dist/config/SettingsLoader.d.ts.map +1 -1
- package/dist/config/SettingsLoader.js +331 -131
- package/dist/config/SettingsLoader.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts +1 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +6 -1
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/middleware/HelperModelMiddleware.d.ts +16 -0
- package/dist/middleware/HelperModelMiddleware.d.ts.map +1 -1
- package/dist/middleware/HelperModelMiddleware.js +32 -5
- package/dist/middleware/HelperModelMiddleware.js.map +1 -1
- package/dist/models/cards/deepseek/deepseek-v4-flash.d.ts.map +1 -1
- package/dist/models/cards/deepseek/deepseek-v4-flash.js +4 -2
- package/dist/models/cards/deepseek/deepseek-v4-flash.js.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.d.ts +14 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +131 -6
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/orchestrator/OrchestratorFactory.js +1 -1
- package/dist/orchestrator/OrchestratorFactory.js.map +1 -1
- package/dist/orchestrator/displayHistorySanitizer.d.ts +29 -0
- package/dist/orchestrator/displayHistorySanitizer.d.ts.map +1 -0
- package/dist/orchestrator/displayHistorySanitizer.js +62 -0
- package/dist/orchestrator/displayHistorySanitizer.js.map +1 -0
- package/dist/tools/context-management/InitCortexContext.js +1 -1
- package/dist/tools/context-management/InitCortexContext.js.map +1 -1
- 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/deadlineExitMentor.d.ts +67 -0
- package/dist/training/deadlineExitMentor.d.ts.map +1 -0
- package/dist/training/deadlineExitMentor.js +99 -0
- package/dist/training/deadlineExitMentor.js.map +1 -0
- package/dist/training/endTurnResolver.d.ts +14 -3
- package/dist/training/endTurnResolver.d.ts.map +1 -1
- package/dist/training/endTurnResolver.js +27 -10
- package/dist/training/endTurnResolver.js.map +1 -1
- package/package.json +5 -5
|
@@ -12,6 +12,7 @@ import { ToolNamingHandler } from '../adapters/ToolNamingHandler.js';
|
|
|
12
12
|
// Phase 2.4: Server-Side Tools Support
|
|
13
13
|
import { shouldUseServerSideTools, isServerSideToolsEnabled, modelSupportsServerSideTools } from '../adapters/ServerSideToolDetection.js';
|
|
14
14
|
import { shouldAutoInjectMcp } from './mcpAutoInjectPolicy.js';
|
|
15
|
+
import { sanitizeHistoryForDisplay } from './displayHistorySanitizer.js';
|
|
15
16
|
import { verifyCoordinates, deterministicCoordinateScore } from './coordinateVerification.js';
|
|
16
17
|
import { buildRouterSample, appendJsonlRotating } from './cortexTrainingRecord.js';
|
|
17
18
|
import { join as pathJoin } from 'path';
|
|
@@ -19,6 +20,7 @@ import { existsSync } from 'fs';
|
|
|
19
20
|
import { execSync } from 'node:child_process';
|
|
20
21
|
import { ENV_RECON_COMMAND, resolveLiftPlanConfig } from '../training/liftPlanner.js';
|
|
21
22
|
import { resolveEndTurnResolverConfig, parseResolverVerdict } from '../training/endTurnResolver.js';
|
|
23
|
+
import { resolveDeadlineExitConfig, deadlineExitCallBudget, parseDeadlineExitVerdict } from '../training/deadlineExitMentor.js';
|
|
22
24
|
import { isTaskShaped } from './requirementsVerification.js';
|
|
23
25
|
import { extractServerSideMetadata, XAIServerSideTools, OpenAIServerSideTools, toCanonicalTool } from '../tools/ServerSideTools.js';
|
|
24
26
|
// Phase 2.2.1: Timeline and History Storage
|
|
@@ -529,14 +531,22 @@ export class CortexOrchestrator {
|
|
|
529
531
|
kind: 'endturn_resolver',
|
|
530
532
|
toolName: 'EndTurn',
|
|
531
533
|
detail: {
|
|
532
|
-
meets: verdict.meets,
|
|
534
|
+
meets: verdict.meets, retire: verdict.retire, abstained: verdict.retire && cfg.abstain,
|
|
535
|
+
planChars: verdict.plan.length, rejects: this.endTurnResolverRejects, parsed: verdict.parsed,
|
|
533
536
|
latencyMs, rawLen: (text ?? '').length,
|
|
534
537
|
planText: verdict.plan.slice(0, 4000),
|
|
535
538
|
workProductSample: workProduct.slice(0, 1500),
|
|
536
539
|
attestation: attestation.slice(0, 800),
|
|
537
540
|
},
|
|
538
541
|
}).catch(() => { });
|
|
539
|
-
if (
|
|
542
|
+
if (verdict.retire && cfg.abstain) {
|
|
543
|
+
// ABSTENTION — the finish is structurally unclosable; accept it and STOP the reject
|
|
544
|
+
// loop (no veto, no reject increment) instead of burning more pro@max cycles on a task
|
|
545
|
+
// the junior can't fix. The finish stands (ev.endTurnCalled stays true).
|
|
546
|
+
if (this.config.debug)
|
|
547
|
+
console.warn(`[EndTurnResolver] RETIRE — abstained (unclosable): ${verdict.plan.slice(0, 160)}`);
|
|
548
|
+
}
|
|
549
|
+
else if (!verdict.meets && verdict.plan) {
|
|
540
550
|
this.endTurnResolverRejects += 1;
|
|
541
551
|
ev.endTurnCalled = false; // VETO the finish
|
|
542
552
|
et.is_error = true;
|
|
@@ -556,6 +566,78 @@ export class CortexOrchestrator {
|
|
|
556
566
|
// fail-open: leave the finish accepted
|
|
557
567
|
}
|
|
558
568
|
}
|
|
569
|
+
/**
|
|
570
|
+
* deadlineExitCheckpoint — the mentor-as-deadline-checkpoint at the WARN rung (~0.9 of the
|
|
571
|
+
* per-turn deadline, where residual still exists). Returns null when disabled/not-applicable
|
|
572
|
+
* (caller uses its normal warn nudge). Otherwise a bounded, residual-scaled mentor call decides:
|
|
573
|
+
* shouldBreak=true → FINISH or RETIRE: end the loop now (post-loop synthesis; resolver bypassed
|
|
574
|
+
* via abnormal-exit) — a clean finish or a clean retirement instead of
|
|
575
|
+
* grinding the residual.
|
|
576
|
+
* shouldBreak=false → CONTINUE (signal='' → normal nudge) or ACTION (signal=the one directed step).
|
|
577
|
+
* Dark by default (CORTEX_DEADLINE_EXIT_MENTOR); fail-safe to null on any error (never truncate
|
|
578
|
+
* a turn on a broken checkpoint call).
|
|
579
|
+
*/
|
|
580
|
+
async deadlineExitCheckpoint(task, workProduct, remainingMs) {
|
|
581
|
+
const cfg = resolveDeadlineExitConfig();
|
|
582
|
+
if (!cfg.enabled)
|
|
583
|
+
return null;
|
|
584
|
+
if (!this.helperMiddleware?.evaluateDeadlineExit)
|
|
585
|
+
return null;
|
|
586
|
+
if (!isTaskShaped(task))
|
|
587
|
+
return null;
|
|
588
|
+
const { timeoutMs, outputBudgetTokens } = deadlineExitCallBudget(cfg, remainingMs);
|
|
589
|
+
const store = this.getDecisionStore();
|
|
590
|
+
const sessionId = this.currentSessionId ?? 'unknown';
|
|
591
|
+
try {
|
|
592
|
+
const t0 = Date.now();
|
|
593
|
+
const text = await withTimeout(this.helperMiddleware.evaluateDeadlineExit({
|
|
594
|
+
task,
|
|
595
|
+
envReport: this.gatherEnvReport(),
|
|
596
|
+
workProduct,
|
|
597
|
+
remainingBudget: `~${Math.max(0, Math.round(remainingMs / 1000))}s of budget left`,
|
|
598
|
+
outputBudgetTokens,
|
|
599
|
+
effort: cfg.effort,
|
|
600
|
+
helperModelId: this.config.reactiveMentorship?.helperModelId,
|
|
601
|
+
}), timeoutMs);
|
|
602
|
+
const v = parseDeadlineExitVerdict(text ?? '');
|
|
603
|
+
if (store)
|
|
604
|
+
void store.recordEvent({
|
|
605
|
+
sessionId,
|
|
606
|
+
kind: 'deadline_exit_mentor',
|
|
607
|
+
detail: {
|
|
608
|
+
decision: v.decision, parsed: v.parsed, remainingMs, latencyMs: Date.now() - t0,
|
|
609
|
+
detailText: v.detail.slice(0, 2000), workProductSample: workProduct.slice(0, 1200),
|
|
610
|
+
},
|
|
611
|
+
}).catch(() => { });
|
|
612
|
+
switch (v.decision) {
|
|
613
|
+
case 'finish':
|
|
614
|
+
if (this.config.debug)
|
|
615
|
+
console.warn(`[DeadlineExit] FINISH — mentor confirms criteria met; ending turn`);
|
|
616
|
+
return { shouldBreak: true, signal: '' };
|
|
617
|
+
case 'retire':
|
|
618
|
+
if (this.config.debug)
|
|
619
|
+
console.warn(`[DeadlineExit] RETIRE — unclosable in residual (${v.detail.slice(0, 120)}); ending turn`);
|
|
620
|
+
return { shouldBreak: true, signal: '' };
|
|
621
|
+
case 'action':
|
|
622
|
+
return { shouldBreak: false, signal: `Time is short — a reviewer says ONE action closes the gap:\n${v.detail}\nDo exactly that, verify it against the task's real criteria, then finish.` };
|
|
623
|
+
default:
|
|
624
|
+
return { shouldBreak: false, signal: '' }; // CONTINUE → caller uses the normal warn nudge
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
catch (e) {
|
|
628
|
+
if (store)
|
|
629
|
+
void store.recordEvent({ sessionId, kind: 'deadline_exit_mentor', detail: { error: String(e?.message ?? e).slice(0, 120) } }).catch(() => { });
|
|
630
|
+
return null; // fail-safe: fall back to the normal warn nudge
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
/** Build the bounded work-product snapshot for the deadline checkpoint (latest answer + recent tool outputs). */
|
|
634
|
+
buildDeadlineWorkProduct(toolResults) {
|
|
635
|
+
const outs = toolResults
|
|
636
|
+
.slice(-6)
|
|
637
|
+
.map((r) => `[${r.tool_name}${r.is_error ? ' ERR' : ''}] ${(typeof r.content === 'string' ? r.content : JSON.stringify(r.content ?? '')).slice(0, 500)}`)
|
|
638
|
+
.join('\n');
|
|
639
|
+
return `${this.lastAssistantText()}\n\n--- recent tool outputs ---\n${outs}`.slice(0, 8000);
|
|
640
|
+
}
|
|
559
641
|
/** Narrow `tools` to the anchor profile while the anchor is armed; no-op
|
|
560
642
|
* once lifted or when CORTEX_TOOL_ANCHOR is unset. Applied AFTER the
|
|
561
643
|
* deferred filter at both request-assembly sites. */
|
|
@@ -1386,6 +1468,16 @@ export class CortexOrchestrator {
|
|
|
1386
1468
|
let toolCallIteration = 0;
|
|
1387
1469
|
// Loop control settings — single source of truth via getLoopControlConfig()
|
|
1388
1470
|
const loopDefaults = this.getLoopControlConfig();
|
|
1471
|
+
// CORTEX_ACTION_EFFORT: static reasoning effort for the PRIMARY (action) model — fills the
|
|
1472
|
+
// request param when unset (`??=`), so it overrides the model card's default but NOT an
|
|
1473
|
+
// explicit request param or the dynamic effort-pulse (both still win). Mentor calls
|
|
1474
|
+
// (lift-plan / endturn-resolver / deadline-exit) use their own *_EFFORT and are unaffected.
|
|
1475
|
+
// Enables the pro-track "wide effort delta" A/B (pro@low action + pro@max mentors).
|
|
1476
|
+
const __actionEffort = (process.env.CORTEX_ACTION_EFFORT || '').trim();
|
|
1477
|
+
if (__actionEffort) {
|
|
1478
|
+
options.parameters = options.parameters || {};
|
|
1479
|
+
options.parameters.reasoningEffort ??= __actionEffort;
|
|
1480
|
+
}
|
|
1389
1481
|
const MAX_TOOL_ITERATIONS = loopDefaults.maxToolIterations;
|
|
1390
1482
|
const TOOL_TIMEOUT_MS = loopDefaults.toolTimeoutMs;
|
|
1391
1483
|
const MAX_CONSECUTIVE_ERRORS = loopDefaults.maxConsecutiveErrors;
|
|
@@ -2359,10 +2451,20 @@ export class CortexOrchestrator {
|
|
|
2359
2451
|
const budgetSignal = computeToolBudgetSignal(effectiveToolBudgetCount, TOOL_BUDGET_SOFT, progressStalled);
|
|
2360
2452
|
const diversityWarning = this.getDiversityWarning(toolCallCounts);
|
|
2361
2453
|
// #2: one-shot wall-clock warning at 90% of the deadline — tell the model to converge + EndTurn.
|
|
2454
|
+
// DARK deadline-exit-mentor (CORTEX_DEADLINE_EXIT_MENTOR): at the warn rung, a bounded mentor
|
|
2455
|
+
// may decide FINISH/RETIRE (end now, cleanly) or ACTION (one directed step) instead of the dumb
|
|
2456
|
+
// "wrap up" nudge; null/CONTINUE falls back to the normal nudge. Hard-floor break below stays.
|
|
2362
2457
|
let timeSignal = null;
|
|
2363
2458
|
if (!timeWarnFired && timeBudgetState(Date.now() - loopStartMs, TURN_DEADLINE_MS) === 'warn') {
|
|
2364
|
-
timeSignal = timeBudgetWarnNudge(Date.now() - loopStartMs, TURN_DEADLINE_MS);
|
|
2365
2459
|
timeWarnFired = true;
|
|
2460
|
+
const de = await this.deadlineExitCheckpoint(this.lastRealUserText(), this.buildDeadlineWorkProduct(toolResults), TURN_DEADLINE_MS - (Date.now() - loopStartMs));
|
|
2461
|
+
if (de?.shouldBreak) {
|
|
2462
|
+
const dstore = this.getDecisionStore();
|
|
2463
|
+
if (dstore)
|
|
2464
|
+
void dstore.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'deadline_exit_break', detail: { iteration: toolCallIteration } }).catch(() => { });
|
|
2465
|
+
break; // mentor-directed clean exit → post-loop synthesis (resolver bypassed via abnormal-exit)
|
|
2466
|
+
}
|
|
2467
|
+
timeSignal = de?.signal || timeBudgetWarnNudge(Date.now() - loopStartMs, TURN_DEADLINE_MS);
|
|
2366
2468
|
}
|
|
2367
2469
|
if (budgetSignal || diversityWarning || ladderSignal || timeSignal) {
|
|
2368
2470
|
const signals = [budgetSignal, diversityWarning, ladderSignal, timeSignal].filter(Boolean).join('\n');
|
|
@@ -3529,6 +3631,16 @@ export class CortexOrchestrator {
|
|
|
3529
3631
|
let hasToolUse = initialToolUseBlocks.length > 0;
|
|
3530
3632
|
// Loop control settings — single source of truth via getLoopControlConfig()
|
|
3531
3633
|
const loopDefaults = this.getLoopControlConfig();
|
|
3634
|
+
// CORTEX_ACTION_EFFORT: static reasoning effort for the PRIMARY (action) model — fills the
|
|
3635
|
+
// request param when unset (`??=`), so it overrides the model card's default but NOT an
|
|
3636
|
+
// explicit request param or the dynamic effort-pulse (both still win). Mentor calls
|
|
3637
|
+
// (lift-plan / endturn-resolver / deadline-exit) use their own *_EFFORT and are unaffected.
|
|
3638
|
+
// Enables the pro-track "wide effort delta" A/B (pro@low action + pro@max mentors).
|
|
3639
|
+
const __actionEffort = (process.env.CORTEX_ACTION_EFFORT || '').trim();
|
|
3640
|
+
if (__actionEffort) {
|
|
3641
|
+
options.parameters = options.parameters || {};
|
|
3642
|
+
options.parameters.reasoningEffort ??= __actionEffort;
|
|
3643
|
+
}
|
|
3532
3644
|
const MAX_TOOL_ITERATIONS = loopDefaults.maxToolIterations;
|
|
3533
3645
|
const MAX_CONSECUTIVE_ERRORS = loopDefaults.maxConsecutiveErrors;
|
|
3534
3646
|
const MAX_LOOP_REPETITIONS = loopDefaults.maxLoopRepetitions;
|
|
@@ -4064,11 +4176,19 @@ export class CortexOrchestrator {
|
|
|
4064
4176
|
const progressStalled = isToolProgressStalled(allToolCalls);
|
|
4065
4177
|
const budgetSignal = computeToolBudgetSignal(effectiveToolBudgetCount, TOOL_BUDGET_SOFT, progressStalled);
|
|
4066
4178
|
const diversityWarning = this.getDiversityWarning(toolCallCounts);
|
|
4067
|
-
// #2: one-shot wall-clock warning at 90% of the deadline (streaming parity).
|
|
4179
|
+
// #2: one-shot wall-clock warning at 90% of the deadline (streaming parity). DARK
|
|
4180
|
+
// deadline-exit-mentor may FINISH/RETIRE (end cleanly) or ACTION (one step) here.
|
|
4068
4181
|
let timeSignal = null;
|
|
4069
4182
|
if (!timeWarnFired && timeBudgetState(Date.now() - loopStartMs, TURN_DEADLINE_MS) === 'warn') {
|
|
4070
|
-
timeSignal = timeBudgetWarnNudge(Date.now() - loopStartMs, TURN_DEADLINE_MS);
|
|
4071
4183
|
timeWarnFired = true;
|
|
4184
|
+
const de = await this.deadlineExitCheckpoint(this.lastRealUserText(), this.buildDeadlineWorkProduct(toolResults), TURN_DEADLINE_MS - (Date.now() - loopStartMs));
|
|
4185
|
+
if (de?.shouldBreak) {
|
|
4186
|
+
const dstore = this.getDecisionStore();
|
|
4187
|
+
if (dstore)
|
|
4188
|
+
void dstore.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'deadline_exit_break', detail: { iteration: toolCallIteration } }).catch(() => { });
|
|
4189
|
+
break; // mentor-directed clean exit → post-loop synthesis (resolver bypassed via abnormal-exit)
|
|
4190
|
+
}
|
|
4191
|
+
timeSignal = de?.signal || timeBudgetWarnNudge(Date.now() - loopStartMs, TURN_DEADLINE_MS);
|
|
4072
4192
|
}
|
|
4073
4193
|
if (budgetSignal || diversityWarning || ladderSignal || timeSignal) {
|
|
4074
4194
|
const signals = [budgetSignal, diversityWarning, ladderSignal, timeSignal].filter(Boolean).join('\n');
|
|
@@ -4954,7 +5074,12 @@ export class CortexOrchestrator {
|
|
|
4954
5074
|
});
|
|
4955
5075
|
});
|
|
4956
5076
|
}
|
|
4957
|
-
|
|
5077
|
+
// Strip model-only <system-reminder> scaffolding (lift-nudge / deferred
|
|
5078
|
+
// corpus / lift-plan append these onto history messages) — this accessor
|
|
5079
|
+
// feeds the TUI history view + session export, never the model request, so
|
|
5080
|
+
// the reminders must not surface to a human. Returns sanitized copies; the
|
|
5081
|
+
// model-facing messageHistory objects are untouched. See displayHistorySanitizer.
|
|
5082
|
+
return sanitizeHistoryForDisplay([...this.messageHistory]);
|
|
4958
5083
|
}
|
|
4959
5084
|
/**
|
|
4960
5085
|
* Resume an existing session by loading its full history
|