@nexus-cortex/core 4.81.0 → 4.82.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 (33) hide show
  1. package/dist/adapters/GatewayTranslationLayer.d.ts +11 -0
  2. package/dist/adapters/GatewayTranslationLayer.d.ts.map +1 -1
  3. package/dist/adapters/GatewayTranslationLayer.js.map +1 -1
  4. package/dist/interfaces/APITransport.d.ts +6 -0
  5. package/dist/interfaces/APITransport.d.ts.map +1 -1
  6. package/dist/middleware/HelperModelMiddleware.d.ts +17 -0
  7. package/dist/middleware/HelperModelMiddleware.d.ts.map +1 -1
  8. package/dist/middleware/HelperModelMiddleware.js +24 -0
  9. package/dist/middleware/HelperModelMiddleware.js.map +1 -1
  10. package/dist/orchestrator/CortexOrchestrator.d.ts +16 -0
  11. package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
  12. package/dist/orchestrator/CortexOrchestrator.js +95 -2
  13. package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
  14. package/dist/orchestrator/toolChoiceTranslation.d.ts +29 -0
  15. package/dist/orchestrator/toolChoiceTranslation.d.ts.map +1 -0
  16. package/dist/orchestrator/toolChoiceTranslation.js +63 -0
  17. package/dist/orchestrator/toolChoiceTranslation.js.map +1 -0
  18. package/dist/tools/registries/BaseToolRegistry.d.ts.map +1 -1
  19. package/dist/tools/registries/BaseToolRegistry.js +24 -0
  20. package/dist/tools/registries/BaseToolRegistry.js.map +1 -1
  21. package/dist/training/DecisionStore.d.ts +7 -1
  22. package/dist/training/DecisionStore.d.ts.map +1 -1
  23. package/dist/training/DecisionStore.js +33 -0
  24. package/dist/training/DecisionStore.js.map +1 -1
  25. package/dist/training/mentorConsult.d.ts +51 -0
  26. package/dist/training/mentorConsult.d.ts.map +1 -0
  27. package/dist/training/mentorConsult.js +73 -0
  28. package/dist/training/mentorConsult.js.map +1 -0
  29. package/dist/training/thrashDetector.d.ts +42 -0
  30. package/dist/training/thrashDetector.d.ts.map +1 -0
  31. package/dist/training/thrashDetector.js +45 -0
  32. package/dist/training/thrashDetector.js.map +1 -0
  33. package/package.json +3 -3
@@ -37,6 +37,7 @@ import { slashCommandRegistry } from '../commands/SlashCommandRegistry.js';
37
37
  import { prefixMcpToolName, parseMcpToolName } from '../mcp/mcpToolNamespacing.js';
38
38
  import { DecisionStore } from '../training/DecisionStore.js';
39
39
  import { formatPriorReminder, formatFamilyReminder, formatApproachReminder } from '../training/DecisionPriorInjector.js';
40
+ import { resolveConsultRung, resolveMentorConfig, bounceMessage, rateLimitedMessage, } from '../training/mentorConsult.js';
40
41
  import { classifyErrorFamily } from '../training/errorFamily.js';
41
42
  import { classifyToolOutcome } from '../training/toolOutcome.js';
42
43
  import { LoopLadder, formatLadderSignal } from '../training/loopLadder.js';
@@ -811,6 +812,11 @@ export class CortexOrchestrator {
811
812
  if (structuredOutputState) {
812
813
  toolsToUse = ensureStructuredOutputTool(toolsToUse, structuredOutputState);
813
814
  }
815
+ // AskForAdvice (MENTORSHIP_ASK_FOR_ADVICE_SPEC §12): append the mentor tool AFTER
816
+ // the deferred filter + anchor (standard-tier tools are otherwise stripped), so a
817
+ // thrashing model can call it without a SearchTools round-trip. Session-stable (gated
818
+ // on mentorship-active, off by default), so the tool-prefix cache is not toggled mid-run.
819
+ toolsToUse = this.ensureAskForAdviceTool(toolsToUse);
814
820
  // Reset sequential call counter at start of each user turn
815
821
  this.mentorshipMiddleware?.resetSequentialCalls(this.currentSessionId);
816
822
  const preparedRequest = this.gatewayTranslation.prepareRequest(canonicalHistory, toolsToUse, effectiveModel, {
@@ -3045,6 +3051,11 @@ export class CortexOrchestrator {
3045
3051
  if (structuredOutputState) {
3046
3052
  toolsToUse = ensureStructuredOutputTool(toolsToUse, structuredOutputState);
3047
3053
  }
3054
+ // AskForAdvice (MENTORSHIP_ASK_FOR_ADVICE_SPEC §12): append the mentor tool AFTER
3055
+ // the deferred filter + anchor (standard-tier tools are otherwise stripped), so a
3056
+ // thrashing model can call it without a SearchTools round-trip. Session-stable (gated
3057
+ // on mentorship-active, off by default), so the tool-prefix cache is not toggled mid-run.
3058
+ toolsToUse = this.ensureAskForAdviceTool(toolsToUse);
3048
3059
  // Reset sequential call counter at start of each user turn
3049
3060
  this.mentorshipMiddleware?.resetSequentialCalls(this.currentSessionId);
3050
3061
  // Input-slicing at initial (streaming) request: send only items since last checkpoint
@@ -5468,6 +5479,8 @@ export class CortexOrchestrator {
5468
5479
  'MemoryRecall'
5469
5480
  ];
5470
5481
  const isContextManagementTool = contextManagementToolNames.includes(toolUse.name);
5482
+ // AskForAdvice (MENTORSHIP_ASK_FOR_ADVICE_SPEC): orchestrator-dispatched mentor tool.
5483
+ const isMentorTool = toolUse.name === 'AskForAdvice';
5471
5484
  // Phase 2.6: Check if this is an MCP management tool
5472
5485
  const mcpManagementToolNames = [
5473
5486
  'ListAvailableMcpServers',
@@ -5482,8 +5495,8 @@ export class CortexOrchestrator {
5482
5495
  // Phase 2.5 Day 4: Check if this is an MCP tool
5483
5496
  const mcpServerName = this.getMcpServerForTool(toolUse.name);
5484
5497
  const isMcpTool = mcpServerName !== undefined;
5485
- // Check if tool exists (context management, MCP management, MCP, or executor)
5486
- if (!isContextManagementTool && !isMcpManagementTool && !isMcpTool && !this.executorRegistry.hasExecutor(toolUse.name)) {
5498
+ // Check if tool exists (context management, mentor, MCP management, MCP, or executor)
5499
+ if (!isContextManagementTool && !isMentorTool && !isMcpManagementTool && !isMcpTool && !this.executorRegistry.hasExecutor(toolUse.name)) {
5487
5500
  const availableExecutors = this.executorRegistry.getExecutorNames();
5488
5501
  const availableMcpTools = this.mcpManager ? this.mcpManager.getAllTools().map(t => t.name) : [];
5489
5502
  const allAvailable = [...availableExecutors, ...availableMcpTools, ...contextManagementToolNames, ...mcpManagementToolNames];
@@ -5567,6 +5580,10 @@ export class CortexOrchestrator {
5567
5580
  }
5568
5581
  };
5569
5582
  }
5583
+ // AskForAdvice — consult the stronger mentor for a hint (spec §4-§5)
5584
+ else if (isMentorTool) {
5585
+ result = await this.executeAskForAdvice(toolUse.input);
5586
+ }
5570
5587
  // Phase 2.6: Execute MCP management tool
5571
5588
  else if (isMcpManagementTool) {
5572
5589
  if (this.config.debug) {
@@ -6699,6 +6716,82 @@ export class CortexOrchestrator {
6699
6716
  * Returns the (possibly-augmented) result. Failures in the store path
6700
6717
  * are swallowed so training never breaks tool execution.
6701
6718
  */
6719
+ /** Include AskForAdvice in the turn's tool set when mentorship is active (spec §12).
6720
+ * Appended post-filter so the deferred filter can't strip this standard-tier tool;
6721
+ * gated on reactiveMentorship.enabled (off by default) and idempotent. */
6722
+ ensureAskForAdviceTool(tools) {
6723
+ if (!this.config.reactiveMentorship?.enabled || !tools)
6724
+ return tools;
6725
+ if (tools.some((t) => t.name === 'AskForAdvice'))
6726
+ return tools;
6727
+ const def = toolFactory.getTool('AskForAdvice');
6728
+ return def ? [...tools, def] : tools;
6729
+ }
6730
+ /** Honored AskForAdvice consults per session (rate-limit + rung state; persists across turns). */
6731
+ mentorConsultCounts = new Map();
6732
+ /**
6733
+ * AskForAdvice executor (MENTORSHIP_ASK_FOR_ADVICE_SPEC v1). Orchestrator-dispatched
6734
+ * because it needs helperMiddleware + the decision store + session state, which the
6735
+ * packages/executors executors structurally lack. Graduated ladder: premature bounce →
6736
+ * mentor DIRECTED REFRAME → structured interview → rate-limited. The stronger mentor
6737
+ * (reactiveMentorship.helperModelId, e.g. deepseek-v4-pro) returns a HINT, never the
6738
+ * solution. Banks a `mentor_consult` episode for the apprentice data lake. Fail-open —
6739
+ * a mentor error never breaks the turn.
6740
+ */
6741
+ async executeAskForAdvice(input) {
6742
+ const sessionId = this.currentSessionId ?? 'unknown';
6743
+ const store = this.getDecisionStore();
6744
+ const failedRows = store ? await store.recentFailures(6) : [];
6745
+ const failed = failedRows.map((d) => ({
6746
+ call: d.inputSummary || d.toolName,
6747
+ error: d.errorSnippet || '',
6748
+ }));
6749
+ const honored = this.mentorConsultCounts.get(sessionId) ?? 0;
6750
+ // v1 gate: the model self-selected by CALLING the tool, so a light "real struggle
6751
+ // exists" check (>=2 recent failures) suffices. The full thrashDetector drives the
6752
+ // proactive invite/forced-choice path (v2), not this executor.
6753
+ const thrashing = failed.length >= 2;
6754
+ const rung = resolveConsultRung(honored, thrashing);
6755
+ if (rung === 'bounce') {
6756
+ return { success: true, llmContent: bounceMessage(failed.length), metadata: { source: 'mentor-consult', rung } };
6757
+ }
6758
+ if (rung === 'ratelimited') {
6759
+ return { success: true, llmContent: rateLimitedMessage(resolveMentorConfig().maxConsults), metadata: { source: 'mentor-consult', rung } };
6760
+ }
6761
+ let hint;
6762
+ try {
6763
+ hint = await this.helperMiddleware.generateMentorHint({
6764
+ rung,
6765
+ task: this.lastRealUserText(),
6766
+ failed,
6767
+ question: input?.question,
6768
+ helperModelId: this.config.reactiveMentorship?.helperModelId,
6769
+ });
6770
+ }
6771
+ catch (err) {
6772
+ return {
6773
+ success: true,
6774
+ llmContent: 'Advice is unavailable right now — keep working the problem: re-read the task and try a distinct approach.',
6775
+ metadata: { source: 'mentor-consult', rung, error: String(err).slice(0, 120) },
6776
+ };
6777
+ }
6778
+ this.mentorConsultCounts.set(sessionId, honored + 1);
6779
+ if (store) {
6780
+ // Reward-labeled episode for the apprentice pipeline (data pump). Best-effort.
6781
+ store.recordEvent({
6782
+ sessionId,
6783
+ kind: 'mentor_consult',
6784
+ toolName: 'AskForAdvice',
6785
+ detail: {
6786
+ rung,
6787
+ helperModel: this.config.reactiveMentorship?.helperModelId ?? 'default',
6788
+ hint: hint.slice(0, 400),
6789
+ failedCount: failed.length,
6790
+ },
6791
+ }).catch(() => { });
6792
+ }
6793
+ return { success: true, llmContent: hint, metadata: { source: 'mentor-consult', rung, helperModel: this.config.reactiveMentorship?.helperModelId } };
6794
+ }
6702
6795
  async processToolTraining(toolUse, result) {
6703
6796
  const store = this.getDecisionStore();
6704
6797
  if (!store)