@nexus-cortex/core 4.108.9 → 4.108.11
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 +12 -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 +3 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +43 -14
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/orchestrator/outerToolTimeout.d.ts +11 -1
- package/dist/orchestrator/outerToolTimeout.d.ts.map +1 -1
- package/dist/orchestrator/outerToolTimeout.js +16 -2
- package/dist/orchestrator/outerToolTimeout.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/loopLadder.d.ts +37 -1
- package/dist/training/loopLadder.d.ts.map +1 -1
- package/dist/training/loopLadder.js +73 -2
- package/dist/training/loopLadder.js.map +1 -1
- package/package.json +3 -3
|
@@ -43,11 +43,11 @@ import { renderResumeMemoryPrompt, buildRebuildInstructions, resolveCheckpointBa
|
|
|
43
43
|
import { resolveCortexStateDir, cortexStatePath } from '../utils/stateDir.js';
|
|
44
44
|
import { collectWorkspaceDelta, detectCheckCommand, runCheck, resolveJudgeGroundingConfig } from '../training/judgeEvidence.js';
|
|
45
45
|
import { resolveMentorRoleConfig, describeMentorWire, describeMentorDelivery, mentorSurfaceTimeoutMs } from '../training/mentorRole.js';
|
|
46
|
-
import { resolveOuterToolDeadlineMs } from './outerToolTimeout.js';
|
|
46
|
+
import { resolveOuterToolDeadlineMs, resolveOuterToolTimeoutFloorMs } from './outerToolTimeout.js';
|
|
47
47
|
import { resolveSubAgentTimeoutMs } from './subAgentTimeout.js';
|
|
48
48
|
import { resolveTurnDeadlineMs, timeBudgetState, timeBudgetWarnNudge } from './timeBudget.js';
|
|
49
49
|
import { readStagedDoctrine, applyCuratedDoctrine, runOrientForStaging, withTimeout } from './doctrineCuration.js';
|
|
50
|
-
import { ExactRepeatTracker } from '../training/loopLadder.js';
|
|
50
|
+
import { ExactRepeatTracker, notePollResults } from '../training/loopLadder.js';
|
|
51
51
|
import { slashCommandRegistry } from '../commands/SlashCommandRegistry.js';
|
|
52
52
|
import { prefixMcpToolName, parseMcpToolName } from '../mcp/mcpToolNamespacing.js';
|
|
53
53
|
import { DecisionStore } from '../training/DecisionStore.js';
|
|
@@ -1582,6 +1582,10 @@ export class CortexOrchestrator {
|
|
|
1582
1582
|
let currentAssistantCanonicalMessage = assistantCanonicalMessage;
|
|
1583
1583
|
this.recordDsmlRecovery(currentAssistantCanonicalMessage);
|
|
1584
1584
|
let toolCallIteration = 0;
|
|
1585
|
+
// R137 HB-POLL-REPEAT-BREAKER: the exact-repeat breaker used to force-exit by overwriting
|
|
1586
|
+
// toolCallIteration = MAX_TOOL_ITERATIONS, which banked toolCallIterations=1000 (a metrics
|
|
1587
|
+
// artifact). An explicit flag ends the loop the same way and keeps the true count.
|
|
1588
|
+
let loopBreak = false;
|
|
1585
1589
|
// Loop control settings — single source of truth via getLoopControlConfig()
|
|
1586
1590
|
const loopDefaults = this.getLoopControlConfig();
|
|
1587
1591
|
// CORTEX_ACTION_EFFORT: static reasoning effort for the PRIMARY (action) model — fills the
|
|
@@ -1596,6 +1600,7 @@ export class CortexOrchestrator {
|
|
|
1596
1600
|
}
|
|
1597
1601
|
const MAX_TOOL_ITERATIONS = loopDefaults.maxToolIterations;
|
|
1598
1602
|
const TOOL_TIMEOUT_MS = loopDefaults.toolTimeoutMs;
|
|
1603
|
+
const OUTER_TOOL_TIMEOUT_FLOOR_MS = loopDefaults.outerToolTimeoutFloorMs;
|
|
1599
1604
|
const MAX_CONSECUTIVE_ERRORS = loopDefaults.maxConsecutiveErrors;
|
|
1600
1605
|
const MAX_LOOP_REPETITIONS = loopDefaults.maxLoopRepetitions;
|
|
1601
1606
|
const TOOL_BUDGET_SOFT = loopDefaults.toolBudgetSoft; // R29b brake
|
|
@@ -2312,8 +2317,9 @@ export class CortexOrchestrator {
|
|
|
2312
2317
|
if (matchCount >= MAX_LOOP_REPETITIONS) {
|
|
2313
2318
|
console.warn(`[Orchestrator Phase 2.5] Loop detected: Tool "${toolUse.name}" called ${matchCount} times with same input. Stopping to prevent infinite loop.`);
|
|
2314
2319
|
console.warn(`[Orchestrator Phase 2.5] Repeated input: ${inputHash.substring(0, 100)}...`);
|
|
2315
|
-
// Break out of the main while loop
|
|
2316
|
-
|
|
2320
|
+
// Break out of the main while loop (R137: flag, not a counter overwrite)
|
|
2321
|
+
loopBreak = true;
|
|
2322
|
+
this.recordLoopBreak(toolUse.name, matchCount, toolCallIteration);
|
|
2317
2323
|
break;
|
|
2318
2324
|
}
|
|
2319
2325
|
}
|
|
@@ -2321,7 +2327,7 @@ export class CortexOrchestrator {
|
|
|
2321
2327
|
// Without this, `break` above only exits the inner for, and the full tool
|
|
2322
2328
|
// batch still executes this iteration (defeats loop prevention).
|
|
2323
2329
|
// Orphaned tool_use blocks are handled by orphan-recovery at loop exit.
|
|
2324
|
-
if (toolCallIteration >= MAX_TOOL_ITERATIONS) {
|
|
2330
|
+
if (loopBreak || toolCallIteration >= MAX_TOOL_ITERATIONS) {
|
|
2325
2331
|
break;
|
|
2326
2332
|
}
|
|
2327
2333
|
// Phase 2.5 Day 3: Execute tools with timeout support
|
|
@@ -2333,7 +2339,7 @@ export class CortexOrchestrator {
|
|
|
2333
2339
|
const abortController = new AbortController();
|
|
2334
2340
|
// D-A (2026-09-04): outer cap must sit ABOVE the model's REQUESTED Bash timeout, not a static
|
|
2335
2341
|
// ~150s, or a legit `Bash({ timeout: 250000 })` is killed before ShellTool's own promote-at-deadline.
|
|
2336
|
-
const outerDeadlineMs = resolveOuterToolDeadlineMs(toolUseBlocks, TOOL_TIMEOUT_MS, OUTER_TIMEOUT_GRACE_MS, this.subAgentBlockTimeoutMs);
|
|
2342
|
+
const outerDeadlineMs = resolveOuterToolDeadlineMs(toolUseBlocks, TOOL_TIMEOUT_MS, OUTER_TIMEOUT_GRACE_MS, this.subAgentBlockTimeoutMs, OUTER_TOOL_TIMEOUT_FLOOR_MS);
|
|
2337
2343
|
const timeoutId = setTimeout(() => {
|
|
2338
2344
|
console.warn(`[Orchestrator Phase 2.5] Tool execution timeout after ${outerDeadlineMs}ms`);
|
|
2339
2345
|
abortController.abort();
|
|
@@ -2344,6 +2350,7 @@ export class CortexOrchestrator {
|
|
|
2344
2350
|
const toolResults = await this.handleToolCalls(toolUseBlocks, abortController.signal, structuredOutputState);
|
|
2345
2351
|
this.testPostExecThrow(); // test-only fault injection for the re-execution guard (inert in prod)
|
|
2346
2352
|
clearTimeout(timeoutId);
|
|
2353
|
+
notePollResults(exactRepeatTracker, toolUseBlocks, toolResults); // R137: poll repeats count only on identical STALLED output
|
|
2347
2354
|
// Unified Outcome Ladder: observe each result's TRUE outcome (exit
|
|
2348
2355
|
// codes, not wire is_error) and escalate on repeated failing
|
|
2349
2356
|
// approaches. The strongest signal this batch is injected at the
|
|
@@ -2978,8 +2985,11 @@ export class CortexOrchestrator {
|
|
|
2978
2985
|
break;
|
|
2979
2986
|
}
|
|
2980
2987
|
}
|
|
2981
|
-
// Warn if we hit max iterations
|
|
2982
|
-
if (
|
|
2988
|
+
// Warn if we hit max iterations (or the exact-repeat breaker ended the loop — R137)
|
|
2989
|
+
if (loopBreak) {
|
|
2990
|
+
console.warn(`[Orchestrator Phase 2.5] Exact-repeat breaker ended the tool loop at iteration ${toolCallIteration}. Stopping loop.`);
|
|
2991
|
+
}
|
|
2992
|
+
else if (toolCallIteration >= MAX_TOOL_ITERATIONS) {
|
|
2983
2993
|
console.warn(`[Orchestrator Phase 2.5] Max tool iterations (${MAX_TOOL_ITERATIONS}) reached. Stopping loop.`);
|
|
2984
2994
|
}
|
|
2985
2995
|
// R29a: post-loop synthesis net. The tool loop can exit with the final
|
|
@@ -3743,6 +3753,7 @@ export class CortexOrchestrator {
|
|
|
3743
3753
|
// Phase 2.8: Multi-turn tool execution loop (STREAMING VERSION)
|
|
3744
3754
|
// Matches sendMessage() pattern exactly (lines 800-1229), but with streaming
|
|
3745
3755
|
let toolCallIteration = 0;
|
|
3756
|
+
let loopBreak = false; // R137: explicit exact-repeat break flag (parity with sendMessage; keeps the true iteration count)
|
|
3746
3757
|
let totalToolErrors = 0;
|
|
3747
3758
|
let emptyResponseRetryUsed = false; // R32: parity with sendMessage R18b guard
|
|
3748
3759
|
let inactionNudgeUsed = false; // Inaction guard (backlog item 2) — streaming parity
|
|
@@ -3792,6 +3803,7 @@ export class CortexOrchestrator {
|
|
|
3792
3803
|
const MAX_CONSECUTIVE_ERRORS = loopDefaults.maxConsecutiveErrors;
|
|
3793
3804
|
const MAX_LOOP_REPETITIONS = loopDefaults.maxLoopRepetitions;
|
|
3794
3805
|
const TOOL_TIMEOUT_MS = loopDefaults.toolTimeoutMs;
|
|
3806
|
+
const OUTER_TOOL_TIMEOUT_FLOOR_MS = loopDefaults.outerToolTimeoutFloorMs;
|
|
3795
3807
|
const TOOL_BUDGET_SOFT = loopDefaults.toolBudgetSoft; // R29b brake
|
|
3796
3808
|
// R64: TOOL_BUDGET_SOFT <= 0 disables the budget-pressure system entirely
|
|
3797
3809
|
// (no reminders, no force-synthesis cap). Runaway protection then rests on
|
|
@@ -4125,7 +4137,8 @@ export class CortexOrchestrator {
|
|
|
4125
4137
|
if (this.config.debug) {
|
|
4126
4138
|
console.warn(`[Orchestrator Streaming] Loop detected: Tool "${toolUse.name}" called ${matchCount} times with same input. Stopping.`);
|
|
4127
4139
|
}
|
|
4128
|
-
|
|
4140
|
+
loopBreak = true; // Force exit (R137: flag, not a counter overwrite)
|
|
4141
|
+
this.recordLoopBreak(toolUse.name, matchCount, toolCallIteration);
|
|
4129
4142
|
break;
|
|
4130
4143
|
}
|
|
4131
4144
|
}
|
|
@@ -4133,14 +4146,14 @@ export class CortexOrchestrator {
|
|
|
4133
4146
|
// Without this, `break` above only exits the inner for, and the full tool
|
|
4134
4147
|
// batch still executes this iteration (defeats loop prevention).
|
|
4135
4148
|
// Orphaned tool_use blocks are handled by orphan-recovery at loop exit.
|
|
4136
|
-
if (toolCallIteration >= MAX_TOOL_ITERATIONS) {
|
|
4149
|
+
if (loopBreak || toolCallIteration >= MAX_TOOL_ITERATIONS) {
|
|
4137
4150
|
break;
|
|
4138
4151
|
}
|
|
4139
4152
|
// Execute tools with timeout (outer cap fires a grace period AFTER the tool's own deadline —
|
|
4140
4153
|
// see the non-stream site: ShellTool's promote-at-deadline must win the race; 4.90.1)
|
|
4141
4154
|
const abortController = new AbortController();
|
|
4142
4155
|
// D-A (2026-09-04): outer cap sits above the requested Bash timeout (see the non-stream site).
|
|
4143
|
-
const outerDeadlineMs = resolveOuterToolDeadlineMs(toolUseBlocks, TOOL_TIMEOUT_MS, OUTER_TIMEOUT_GRACE_MS, this.subAgentBlockTimeoutMs);
|
|
4156
|
+
const outerDeadlineMs = resolveOuterToolDeadlineMs(toolUseBlocks, TOOL_TIMEOUT_MS, OUTER_TIMEOUT_GRACE_MS, this.subAgentBlockTimeoutMs, OUTER_TOOL_TIMEOUT_FLOOR_MS);
|
|
4144
4157
|
const timeoutId = setTimeout(() => {
|
|
4145
4158
|
if (this.config.debug) {
|
|
4146
4159
|
console.warn(`[Orchestrator Streaming] Tool execution timeout after ${outerDeadlineMs}ms`);
|
|
@@ -4152,6 +4165,7 @@ export class CortexOrchestrator {
|
|
|
4152
4165
|
const toolResults = await this.handleToolCalls(toolUseBlocks, abortController.signal, structuredOutputState);
|
|
4153
4166
|
this.testPostExecThrow(); // test-only fault injection for the re-execution guard (inert in prod)
|
|
4154
4167
|
clearTimeout(timeoutId);
|
|
4168
|
+
notePollResults(streamRepeatTracker, toolUseBlocks, toolResults); // R137 (streaming parity)
|
|
4155
4169
|
// 4.91.0: EndTurn gates for STREAMING (were sendMessage-only) — same evidence + evaluation.
|
|
4156
4170
|
ev.noteToolResults(toolResults);
|
|
4157
4171
|
evaluateEndTurnGates(ev, toolResults, toolUseBlocks, this.gateDeps());
|
|
@@ -4791,10 +4805,12 @@ export class CortexOrchestrator {
|
|
|
4791
4805
|
}
|
|
4792
4806
|
}
|
|
4793
4807
|
}
|
|
4794
|
-
// Warn if hit max iterations
|
|
4795
|
-
if (toolCallIteration >= MAX_TOOL_ITERATIONS) {
|
|
4808
|
+
// Warn if hit max iterations (or the exact-repeat breaker ended the loop — R137)
|
|
4809
|
+
if (loopBreak || toolCallIteration >= MAX_TOOL_ITERATIONS) {
|
|
4796
4810
|
if (this.config.debug) {
|
|
4797
|
-
console.warn(
|
|
4811
|
+
console.warn(loopBreak
|
|
4812
|
+
? `[Orchestrator Streaming] Exact-repeat breaker ended the tool loop at iteration ${toolCallIteration}. Stopping loop.`
|
|
4813
|
+
: `[Orchestrator Streaming] Max tool iterations (${MAX_TOOL_ITERATIONS}) reached. Stopping loop.`);
|
|
4798
4814
|
}
|
|
4799
4815
|
}
|
|
4800
4816
|
// R29a (streaming parity): post-loop synthesis net. R32 added the R18b
|
|
@@ -5138,6 +5154,8 @@ export class CortexOrchestrator {
|
|
|
5138
5154
|
// coercion silently replaced an explicit 0 with 15.
|
|
5139
5155
|
toolBudgetSoft: Number.isFinite(softRaw) && softRaw >= 0 ? softRaw : 400,
|
|
5140
5156
|
toolTimeoutMs: this.config.loopControl?.toolTimeoutMs ?? 120000,
|
|
5157
|
+
// CORTEX_OUTER_TOOL_TIMEOUT_MS: floor for the outer per-batch abort (0 = no floor, byte-identical).
|
|
5158
|
+
outerToolTimeoutFloorMs: resolveOuterToolTimeoutFloorMs(),
|
|
5141
5159
|
maxLoopRepetitions: this.config.loopControl?.maxLoopRepetitions ?? 5,
|
|
5142
5160
|
// #2 wall-clock deadline: opt-in (0 = disabled), env CORTEX_TURN_DEADLINE_MS is the fallback.
|
|
5143
5161
|
turnDeadlineMs: resolveTurnDeadlineMs(this.config.loopControl?.turnDeadlineMs),
|
|
@@ -6262,6 +6280,17 @@ export class CortexOrchestrator {
|
|
|
6262
6280
|
* @param signal AbortSignal for cancellation
|
|
6263
6281
|
* @returns Array of tool results
|
|
6264
6282
|
*/
|
|
6283
|
+
/** R137 HB-POLL-REPEAT-BREAKER: bank the exact-repeat break as a decisions event (mechanism-engagement evidence). */
|
|
6284
|
+
recordLoopBreak(tool, matchCount, iteration) {
|
|
6285
|
+
const store = this.getDecisionStore();
|
|
6286
|
+
if (store)
|
|
6287
|
+
void store.recordEvent({
|
|
6288
|
+
sessionId: this.currentSessionId ?? 'unknown',
|
|
6289
|
+
kind: 'loop_break',
|
|
6290
|
+
toolName: tool,
|
|
6291
|
+
detail: { tool, matchCount, iteration },
|
|
6292
|
+
}).catch(() => { });
|
|
6293
|
+
}
|
|
6265
6294
|
async handleToolCalls(toolUseBlocks, signal, structuredOutputState) {
|
|
6266
6295
|
// StructuredOutput (grok-build port): intercept BEFORE any dispatch — the
|
|
6267
6296
|
// synthetic tool is request-scoped (never in a registry) and must NEVER
|