@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.
- package/dist/adapters/GatewayTranslationLayer.d.ts +11 -0
- package/dist/adapters/GatewayTranslationLayer.d.ts.map +1 -1
- package/dist/adapters/GatewayTranslationLayer.js.map +1 -1
- package/dist/interfaces/APITransport.d.ts +6 -0
- package/dist/interfaces/APITransport.d.ts.map +1 -1
- package/dist/middleware/HelperModelMiddleware.d.ts +17 -0
- package/dist/middleware/HelperModelMiddleware.d.ts.map +1 -1
- package/dist/middleware/HelperModelMiddleware.js +24 -0
- package/dist/middleware/HelperModelMiddleware.js.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.d.ts +16 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +95 -2
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/orchestrator/toolChoiceTranslation.d.ts +29 -0
- package/dist/orchestrator/toolChoiceTranslation.d.ts.map +1 -0
- package/dist/orchestrator/toolChoiceTranslation.js +63 -0
- package/dist/orchestrator/toolChoiceTranslation.js.map +1 -0
- package/dist/tools/registries/BaseToolRegistry.d.ts.map +1 -1
- package/dist/tools/registries/BaseToolRegistry.js +24 -0
- package/dist/tools/registries/BaseToolRegistry.js.map +1 -1
- package/dist/training/DecisionStore.d.ts +7 -1
- package/dist/training/DecisionStore.d.ts.map +1 -1
- package/dist/training/DecisionStore.js +33 -0
- package/dist/training/DecisionStore.js.map +1 -1
- package/dist/training/mentorConsult.d.ts +51 -0
- package/dist/training/mentorConsult.d.ts.map +1 -0
- package/dist/training/mentorConsult.js +73 -0
- package/dist/training/mentorConsult.js.map +1 -0
- package/dist/training/thrashDetector.d.ts +42 -0
- package/dist/training/thrashDetector.d.ts.map +1 -0
- package/dist/training/thrashDetector.js +45 -0
- package/dist/training/thrashDetector.js.map +1 -0
- 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)
|