@nexus-cortex/core 4.96.1 → 4.98.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.
Files changed (38) hide show
  1. package/.env.defaults +10 -0
  2. package/dist/config/effectiveConfig.d.ts.map +1 -1
  3. package/dist/config/effectiveConfig.js +3 -0
  4. package/dist/config/effectiveConfig.js.map +1 -1
  5. package/dist/models/cards/mercury/index.d.ts +1 -0
  6. package/dist/models/cards/mercury/index.d.ts.map +1 -1
  7. package/dist/models/cards/mercury/index.js +4 -0
  8. package/dist/models/cards/mercury/index.js.map +1 -1
  9. package/dist/models/cards/mercury/mercury-2-5.d.ts +28 -0
  10. package/dist/models/cards/mercury/mercury-2-5.d.ts.map +1 -0
  11. package/dist/models/cards/mercury/mercury-2-5.js +37 -0
  12. package/dist/models/cards/mercury/mercury-2-5.js.map +1 -0
  13. package/dist/models/registry/ModularModelRegistry.d.ts.map +1 -1
  14. package/dist/models/registry/ModularModelRegistry.js +2 -1
  15. package/dist/models/registry/ModularModelRegistry.js.map +1 -1
  16. package/dist/orchestrator/APIClient.d.ts.map +1 -1
  17. package/dist/orchestrator/APIClient.js +17 -0
  18. package/dist/orchestrator/APIClient.js.map +1 -1
  19. package/dist/orchestrator/CortexOrchestrator.d.ts +16 -0
  20. package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
  21. package/dist/orchestrator/CortexOrchestrator.js +74 -5
  22. package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
  23. package/dist/orchestrator/dsmlRecovery.d.ts +40 -0
  24. package/dist/orchestrator/dsmlRecovery.d.ts.map +1 -0
  25. package/dist/orchestrator/dsmlRecovery.js +106 -0
  26. package/dist/orchestrator/dsmlRecovery.js.map +1 -0
  27. package/dist/orchestrator/sliceBlock.d.ts +50 -0
  28. package/dist/orchestrator/sliceBlock.d.ts.map +1 -0
  29. package/dist/orchestrator/sliceBlock.js +69 -0
  30. package/dist/orchestrator/sliceBlock.js.map +1 -0
  31. package/dist/tools/ToolProfile.d.ts +6 -0
  32. package/dist/tools/ToolProfile.d.ts.map +1 -1
  33. package/dist/tools/ToolProfile.js +14 -0
  34. package/dist/tools/ToolProfile.js.map +1 -1
  35. package/dist/training/DecisionStore.d.ts +1 -1
  36. package/dist/training/DecisionStore.d.ts.map +1 -1
  37. package/dist/training/DecisionStore.js.map +1 -1
  38. package/package.json +3 -3
@@ -35,7 +35,8 @@ import { CacheMetricsAccumulator } from '../session/CacheMetricsAccumulator.js';
35
35
  import { SubAgentProcessManager, createSubAgentProcessManager } from './SubAgentProcessManager.js';
36
36
  // Phase 1: Tool Architecture Refactor - Unified Tool Registry
37
37
  import { toolFactory } from '../tools/ToolFactory.js';
38
- import { resolveToolProfile, resolveToolAnchor, resolveFrameProfile, resolveLiftNudge, resolveLiftPlan, resolveEndTurnResolver, resolveHeadlessDropAskUser, resolveDeferredLoading, isNarrowProfile, isToolAllowedByProfile, applyToolProfile, webToolBlocked, resolveVisionHelperModel, resolveVisionHandoffMax, resolveSliceNudge } from '../tools/ToolProfile.js';
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
+ import { sliceReadFile, decideSliceBlock } from './sliceBlock.js';
39
40
  import { TurnEvidence, evaluateEndTurnGates, buildMissingEndTurnReminder } from './endTurnGates.js';
40
41
  import { resolveOuterToolDeadlineMs } from './outerToolTimeout.js';
41
42
  import { resolveTurnDeadlineMs, timeBudgetState, timeBudgetWarnNudge } from './timeBudget.js';
@@ -1518,6 +1519,7 @@ export class CortexOrchestrator {
1518
1519
  // Keep executing tools until model returns a text response
1519
1520
  let currentAssistantMessage = assistantMessage;
1520
1521
  let currentAssistantCanonicalMessage = assistantCanonicalMessage;
1522
+ this.recordDsmlRecovery(currentAssistantCanonicalMessage);
1521
1523
  let toolCallIteration = 0;
1522
1524
  // Loop control settings — single source of truth via getLoopControlConfig()
1523
1525
  const loopDefaults = this.getLoopControlConfig();
@@ -3635,6 +3637,7 @@ export class CortexOrchestrator {
3635
3637
  throw new Error('No response message returned from provider');
3636
3638
  }
3637
3639
  let currentAssistantCanonicalMessage = convertedResponse.messages[0];
3640
+ this.recordDsmlRecovery(currentAssistantCanonicalMessage);
3638
3641
  const assistantMessageId = currentAssistantCanonicalMessage.uuid;
3639
3642
  const assistantMessage = {
3640
3643
  uuid: assistantMessageId,
@@ -6077,6 +6080,12 @@ export class CortexOrchestrator {
6077
6080
  results.push(await this.processToolTraining(toolUse, loopBlocked));
6078
6081
  continue;
6079
6082
  }
6083
+ // CORTEX_SLICE_BLOCK: coercively block re-slicing a static file (force Read) — dark.
6084
+ const sliceBlocked = this.maybeBlockSliceRead(toolUse);
6085
+ if (sliceBlocked) {
6086
+ results.push(await this.processToolTraining(toolUse, sliceBlocked));
6087
+ continue;
6088
+ }
6080
6089
  // Context management tools (CORTEX.md generation + two-tier memory)
6081
6090
  const contextManagementToolNames = [
6082
6091
  'InitCortexContext',
@@ -6507,6 +6516,10 @@ export class CortexOrchestrator {
6507
6516
  const loopBlocked = await this.maybeBlockLoopingTool(toolUse);
6508
6517
  if (loopBlocked)
6509
6518
  return loopBlocked;
6519
+ // CORTEX_SLICE_BLOCK: coercively block re-slicing a static file (force Read) — dark.
6520
+ const sliceBlocked = this.maybeBlockSliceRead(toolUse);
6521
+ if (sliceBlocked)
6522
+ return sliceBlocked;
6510
6523
  // Context management tools
6511
6524
  const contextManagementToolNames = ['InitCortexContext'];
6512
6525
  const isContextManagementTool = contextManagementToolNames.includes(toolUse.name);
@@ -7251,6 +7264,8 @@ export class CortexOrchestrator {
7251
7264
  visionHandoffsThisTurn = 0;
7252
7265
  /** Per-session bash slice-read counts per file (CORTEX_SLICE_NUDGE). */
7253
7266
  sliceReads = new Map();
7267
+ /** Per-session coercive-block counts per file (CORTEX_SLICE_BLOCK — HB-SLICE-BLOCK). */
7268
+ sliceBlockCounts = new Map();
7254
7269
  /** Dependencies the shared EndTurn gates need from the orchestrator (endTurnGates.ts). */
7255
7270
  gateDeps() {
7256
7271
  return {
@@ -7278,11 +7293,9 @@ export class CortexOrchestrator {
7278
7293
  applySliceNudge(toolUse, result) {
7279
7294
  if (toolUse.name !== 'Bash' || result.is_error || !resolveSliceNudge(process.env))
7280
7295
  return;
7281
- const cmd = String(toolUse.input?.command ?? '');
7282
- const m = cmd.match(/(?:sed\s+-n\s+['"]?\d+\s*,\s*\d+\s*p['"]?|head\s+-n?\s*\d+|tail\s+-n?\s*\d+)\s+([^\s;|&>]+)/);
7283
- if (!m)
7296
+ const file = sliceReadFile(String(toolUse.input?.command ?? ''));
7297
+ if (!file)
7284
7298
  return;
7285
- const file = m[1];
7286
7299
  const n = (this.sliceReads.get(file) ?? 0) + 1;
7287
7300
  this.sliceReads.set(file, n);
7288
7301
  if (n !== 3)
@@ -7292,6 +7305,37 @@ export class CortexOrchestrator {
7292
7305
  }
7293
7306
  this.gateDeps().recordEvent('steering_injected', { kind: 'slice_read', file, count: n }, 'Bash');
7294
7307
  }
7308
+ /**
7309
+ * CORTEX_SLICE_BLOCK (HB-SLICE-BLOCK) — the coercive escalation of the ignored slice-nudge.
7310
+ * PRE-EXECUTION gate (sibling of maybeBlockLoopingTool): if the model is calling Bash to slice-read
7311
+ * a STATIC/source file it has already sliced >= CORTEX_SLICE_BLOCK_AT times, do NOT run the slice —
7312
+ * return an append-only redirect error steering it to Read (bounded to CORTEX_SLICE_BLOCK_MAX blocks
7313
+ * per file). Append-mostly logs are exempt (legit re-tailing). Dark by default. Evidence: full-sample
7314
+ * mining showed the soft nudge is ignored ~80% of re-tested cases (docs/HB-SLICE-BLOCK-SPEC.md).
7315
+ */
7316
+ maybeBlockSliceRead(toolUse) {
7317
+ if (toolUse.name !== 'Bash' || !resolveSliceBlock(process.env))
7318
+ return null;
7319
+ const file = sliceReadFile(String(toolUse.input?.command ?? ''));
7320
+ if (!file)
7321
+ return null;
7322
+ const priorSlices = this.sliceReads.get(file) ?? 0;
7323
+ const priorBlocks = this.sliceBlockCounts.get(file) ?? 0;
7324
+ const decision = decideSliceBlock(file, priorSlices, priorBlocks, resolveSliceBlockAt(process.env), resolveSliceBlockMax(process.env));
7325
+ if (decision.action !== 'block')
7326
+ return null;
7327
+ this.sliceBlockCounts.set(file, priorBlocks + 1);
7328
+ const store = this.getDecisionStore();
7329
+ if (store)
7330
+ void store.recordEvent({
7331
+ sessionId: this.currentSessionId ?? 'unknown',
7332
+ kind: 'slice_block', toolName: 'Bash',
7333
+ detail: { file, priorSlices, blockNumber: priorBlocks + 1 },
7334
+ }).catch(() => { });
7335
+ if (this.config.debug)
7336
+ console.log(`[SliceBlock] blocked slice-read of ${file} (${priorSlices} prior slices, block #${priorBlocks + 1})`);
7337
+ return { tool_use_id: toolUse.id, tool_name: toolUse.name, content: decision.message, is_error: true, metadata: { sliceBlock: true, file } };
7338
+ }
7295
7339
  async applyVisionHandoffs() {
7296
7340
  const queue = this.pendingVisionHandoffs;
7297
7341
  this.pendingVisionHandoffs = [];
@@ -7432,6 +7476,31 @@ export class CortexOrchestrator {
7432
7476
  }
7433
7477
  return this.decisionStore;
7434
7478
  }
7479
+ /** HB-DSML-PARSE observability (2026-09-09): if the DeepSeek DSML tool-call recovery fired on this
7480
+ * response (recovered tool_use ids are prefixed `dsml_`), record ONE countable `dsml_recovered`
7481
+ * decision event so the bench data shows how often the leak occurred + that the fix is live.
7482
+ * Observability only — never throws into the turn. */
7483
+ recordDsmlRecovery(msg) {
7484
+ try {
7485
+ const content = Array.isArray(msg?.content) ? msg.content : [];
7486
+ const recovered = content.filter((b) => b?.type === 'tool_use' && typeof b?.toolUse?.id === 'string' && b.toolUse.id.startsWith('dsml_'));
7487
+ if (recovered.length === 0)
7488
+ return;
7489
+ const store = this.getDecisionStore();
7490
+ if (store) {
7491
+ void store
7492
+ .recordEvent({
7493
+ sessionId: this.currentSessionId ?? 'unknown',
7494
+ kind: 'dsml_recovered',
7495
+ detail: { count: recovered.length, tools: recovered.map((b) => b.toolUse?.name) },
7496
+ })
7497
+ .catch(() => { });
7498
+ }
7499
+ if (this.config.debug)
7500
+ console.log(`[HB-DSML-PARSE] dsml_recovered event (count=${recovered.length})`);
7501
+ }
7502
+ catch { /* observability only */ }
7503
+ }
7435
7504
  isRecordingEnabled() {
7436
7505
  return process.env.CORTEX_RECORD_DECISIONS !== 'false';
7437
7506
  }