@nexus-cortex/core 4.81.0 → 4.83.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 +19 -0
- package/dist/adapters/GatewayTranslationLayer.d.ts.map +1 -1
- package/dist/adapters/GatewayTranslationLayer.js +15 -1
- package/dist/adapters/GatewayTranslationLayer.js.map +1 -1
- package/dist/config/SettingsLoader.d.ts +5 -2
- package/dist/config/SettingsLoader.d.ts.map +1 -1
- package/dist/config/SettingsLoader.js +32 -2
- package/dist/config/SettingsLoader.js.map +1 -1
- package/dist/config/SettingsSchema.js +12 -12
- package/dist/config/SettingsSchema.js.map +1 -1
- package/dist/interfaces/APITransport.d.ts +4 -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/APIClient.d.ts +9 -0
- package/dist/orchestrator/APIClient.d.ts.map +1 -1
- package/dist/orchestrator/APIClient.js +31 -0
- package/dist/orchestrator/APIClient.js.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.d.ts +27 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +145 -4
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/orchestrator/toolChoiceTranslation.d.ts +32 -0
- package/dist/orchestrator/toolChoiceTranslation.d.ts.map +1 -0
- package/dist/orchestrator/toolChoiceTranslation.js +74 -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 +30 -0
- package/dist/tools/registries/BaseToolRegistry.js.map +1 -1
- package/dist/training/DecisionStore.d.ts +14 -1
- package/dist/training/DecisionStore.d.ts.map +1 -1
- package/dist/training/DecisionStore.js +67 -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,8 @@ 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';
|
|
41
|
+
import { resolveThrashState, resolveThrashConfig } from '../training/thrashDetector.js';
|
|
40
42
|
import { classifyErrorFamily } from '../training/errorFamily.js';
|
|
41
43
|
import { classifyToolOutcome } from '../training/toolOutcome.js';
|
|
42
44
|
import { LoopLadder, formatLadderSignal } from '../training/loopLadder.js';
|
|
@@ -811,8 +813,15 @@ export class CortexOrchestrator {
|
|
|
811
813
|
if (structuredOutputState) {
|
|
812
814
|
toolsToUse = ensureStructuredOutputTool(toolsToUse, structuredOutputState);
|
|
813
815
|
}
|
|
816
|
+
// AskForAdvice (MENTORSHIP_ASK_FOR_ADVICE_SPEC §12): append the mentor tool AFTER
|
|
817
|
+
// the deferred filter + anchor (standard-tier tools are otherwise stripped), so a
|
|
818
|
+
// thrashing model can call it without a SearchTools round-trip. Session-stable (gated
|
|
819
|
+
// on mentorship-active, off by default), so the tool-prefix cache is not toggled mid-run.
|
|
820
|
+
toolsToUse = this.ensureAskForAdviceTool(toolsToUse);
|
|
814
821
|
// Reset sequential call counter at start of each user turn
|
|
815
822
|
this.mentorshipMiddleware?.resetSequentialCalls(this.currentSessionId);
|
|
823
|
+
// §13-B2: force AskForAdvice this turn on high-confidence thrash (mentor-force armed).
|
|
824
|
+
const forcedMentorChoice = await this.resolveForcedMentorChoice(toolsToUse);
|
|
816
825
|
const preparedRequest = this.gatewayTranslation.prepareRequest(canonicalHistory, toolsToUse, effectiveModel, {
|
|
817
826
|
temperature: options.parameters?.temperature,
|
|
818
827
|
maxTokens: options.parameters?.maxTokens,
|
|
@@ -820,7 +829,8 @@ export class CortexOrchestrator {
|
|
|
820
829
|
reasoningEffort: options.parameters?.reasoningEffort, // GPT-5.1 reasoning level
|
|
821
830
|
stream: options.streaming,
|
|
822
831
|
staticSystemPrompt: this.currentStaticSystemPrompt, // R28
|
|
823
|
-
conversationId: this.currentConversationId // R28b
|
|
832
|
+
conversationId: this.currentConversationId, // R28b
|
|
833
|
+
toolChoice: forcedMentorChoice // §13-B2 forced mentor tool_choice
|
|
824
834
|
});
|
|
825
835
|
// Stateful Responses API: chain from prior response when available
|
|
826
836
|
// (works across user turns — lastResponseId is preserved between messages).
|
|
@@ -3045,6 +3055,11 @@ export class CortexOrchestrator {
|
|
|
3045
3055
|
if (structuredOutputState) {
|
|
3046
3056
|
toolsToUse = ensureStructuredOutputTool(toolsToUse, structuredOutputState);
|
|
3047
3057
|
}
|
|
3058
|
+
// AskForAdvice (MENTORSHIP_ASK_FOR_ADVICE_SPEC §12): append the mentor tool AFTER
|
|
3059
|
+
// the deferred filter + anchor (standard-tier tools are otherwise stripped), so a
|
|
3060
|
+
// thrashing model can call it without a SearchTools round-trip. Session-stable (gated
|
|
3061
|
+
// on mentorship-active, off by default), so the tool-prefix cache is not toggled mid-run.
|
|
3062
|
+
toolsToUse = this.ensureAskForAdviceTool(toolsToUse);
|
|
3048
3063
|
// Reset sequential call counter at start of each user turn
|
|
3049
3064
|
this.mentorshipMiddleware?.resetSequentialCalls(this.currentSessionId);
|
|
3050
3065
|
// Input-slicing at initial (streaming) request: send only items since last checkpoint
|
|
@@ -3060,6 +3075,8 @@ export class CortexOrchestrator {
|
|
|
3060
3075
|
if (initialCanSliceInputStreaming && this.config.debug) {
|
|
3061
3076
|
console.log(`[Orchestrator Streaming] Input-sliced initial for cross-turn chain: sent ${initialHistoryForApiStreaming.length}/${messageHistoryForApi.length} messages`);
|
|
3062
3077
|
}
|
|
3078
|
+
// §13-B2: force AskForAdvice this turn on high-confidence thrash (mentor-force armed).
|
|
3079
|
+
const forcedMentorChoice = await this.resolveForcedMentorChoice(toolsToUse);
|
|
3063
3080
|
// Prepare request
|
|
3064
3081
|
const preparedRequest = this.gatewayTranslation.prepareRequest(canonicalHistory, toolsToUse, effectiveModel, {
|
|
3065
3082
|
temperature: options.parameters?.temperature,
|
|
@@ -3068,7 +3085,8 @@ export class CortexOrchestrator {
|
|
|
3068
3085
|
reasoningEffort: options.parameters?.reasoningEffort, // GPT-5.1 reasoning level
|
|
3069
3086
|
stream: true, // Enable streaming!
|
|
3070
3087
|
staticSystemPrompt: this.currentStaticSystemPrompt, // R28
|
|
3071
|
-
conversationId: this.currentConversationId // R28b
|
|
3088
|
+
conversationId: this.currentConversationId, // R28b
|
|
3089
|
+
toolChoice: forcedMentorChoice // §13-B2 forced mentor tool_choice
|
|
3072
3090
|
});
|
|
3073
3091
|
// Stateful Responses API: chain from prior response when available (cross-turn).
|
|
3074
3092
|
if (this.lastResponseId && effectiveModel.api.pattern === 'responses') {
|
|
@@ -5468,6 +5486,8 @@ export class CortexOrchestrator {
|
|
|
5468
5486
|
'MemoryRecall'
|
|
5469
5487
|
];
|
|
5470
5488
|
const isContextManagementTool = contextManagementToolNames.includes(toolUse.name);
|
|
5489
|
+
// AskForAdvice (MENTORSHIP_ASK_FOR_ADVICE_SPEC): orchestrator-dispatched mentor tool.
|
|
5490
|
+
const isMentorTool = toolUse.name === 'AskForAdvice';
|
|
5471
5491
|
// Phase 2.6: Check if this is an MCP management tool
|
|
5472
5492
|
const mcpManagementToolNames = [
|
|
5473
5493
|
'ListAvailableMcpServers',
|
|
@@ -5482,8 +5502,8 @@ export class CortexOrchestrator {
|
|
|
5482
5502
|
// Phase 2.5 Day 4: Check if this is an MCP tool
|
|
5483
5503
|
const mcpServerName = this.getMcpServerForTool(toolUse.name);
|
|
5484
5504
|
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)) {
|
|
5505
|
+
// Check if tool exists (context management, mentor, MCP management, MCP, or executor)
|
|
5506
|
+
if (!isContextManagementTool && !isMentorTool && !isMcpManagementTool && !isMcpTool && !this.executorRegistry.hasExecutor(toolUse.name)) {
|
|
5487
5507
|
const availableExecutors = this.executorRegistry.getExecutorNames();
|
|
5488
5508
|
const availableMcpTools = this.mcpManager ? this.mcpManager.getAllTools().map(t => t.name) : [];
|
|
5489
5509
|
const allAvailable = [...availableExecutors, ...availableMcpTools, ...contextManagementToolNames, ...mcpManagementToolNames];
|
|
@@ -5567,6 +5587,10 @@ export class CortexOrchestrator {
|
|
|
5567
5587
|
}
|
|
5568
5588
|
};
|
|
5569
5589
|
}
|
|
5590
|
+
// AskForAdvice — consult the stronger mentor for a hint (spec §4-§5)
|
|
5591
|
+
else if (isMentorTool) {
|
|
5592
|
+
result = await this.executeAskForAdvice(toolUse.input);
|
|
5593
|
+
}
|
|
5570
5594
|
// Phase 2.6: Execute MCP management tool
|
|
5571
5595
|
else if (isMcpManagementTool) {
|
|
5572
5596
|
if (this.config.debug) {
|
|
@@ -6699,6 +6723,123 @@ export class CortexOrchestrator {
|
|
|
6699
6723
|
* Returns the (possibly-augmented) result. Failures in the store path
|
|
6700
6724
|
* are swallowed so training never breaks tool execution.
|
|
6701
6725
|
*/
|
|
6726
|
+
/** Include AskForAdvice in the turn's tool set when mentorship is active (spec §12).
|
|
6727
|
+
* Appended post-filter so the deferred filter can't strip this standard-tier tool;
|
|
6728
|
+
* gated on reactiveMentorship.enabled (off by default) and idempotent. */
|
|
6729
|
+
ensureAskForAdviceTool(tools) {
|
|
6730
|
+
if (!this.config.reactiveMentorship?.enabled || !tools)
|
|
6731
|
+
return tools;
|
|
6732
|
+
if (tools.some((t) => t.name === 'AskForAdvice'))
|
|
6733
|
+
return tools;
|
|
6734
|
+
const def = toolFactory.getTool('AskForAdvice');
|
|
6735
|
+
return def ? [...tools, def] : tools;
|
|
6736
|
+
}
|
|
6737
|
+
/**
|
|
6738
|
+
* AskForAdvice v2 (§13-B2): decide whether to FORCE `AskForAdvice` for the NEXT
|
|
6739
|
+
* request (delivers the mentor hint through the heed-friendly tool-result channel,
|
|
6740
|
+
* routing around flash's weak voluntary heed — v1 measured 0/6). Gated on ALL of:
|
|
6741
|
+
* mentorship active, `CORTEX_MENTOR_FORCE=true` (default off), the tool is present
|
|
6742
|
+
* in this request's surface, the session is not yet rate-limited, and HIGH-confidence
|
|
6743
|
+
* thrash (the full `resolveThrashState` window — past the turn floor, a full window
|
|
6744
|
+
* of mostly-failures, currently failing). Returns the CANONICAL forced choice; the
|
|
6745
|
+
* gateway converts its name to the wire form. `tool_choice` is body-level → cache-safe.
|
|
6746
|
+
*/
|
|
6747
|
+
async resolveForcedMentorChoice(toolsToUse) {
|
|
6748
|
+
if (!this.config.reactiveMentorship?.enabled)
|
|
6749
|
+
return undefined;
|
|
6750
|
+
if (process.env.CORTEX_MENTOR_FORCE !== 'true')
|
|
6751
|
+
return undefined;
|
|
6752
|
+
if (!toolsToUse?.some((t) => t.name === 'AskForAdvice'))
|
|
6753
|
+
return undefined;
|
|
6754
|
+
const sessionId = this.currentSessionId ?? 'unknown';
|
|
6755
|
+
if ((this.mentorConsultCounts.get(sessionId) ?? 0) >= resolveMentorConfig().maxConsults)
|
|
6756
|
+
return undefined;
|
|
6757
|
+
const store = this.getDecisionStore();
|
|
6758
|
+
if (!store)
|
|
6759
|
+
return undefined;
|
|
6760
|
+
try {
|
|
6761
|
+
const outcomes = await store.recentOutcomes(resolveThrashConfig().window);
|
|
6762
|
+
return resolveThrashState(outcomes, this.turnNumber).thrashing
|
|
6763
|
+
? { type: 'tool', name: 'AskForAdvice' }
|
|
6764
|
+
: undefined;
|
|
6765
|
+
}
|
|
6766
|
+
catch {
|
|
6767
|
+
return undefined; // fail-open: never let the thrash read break a turn
|
|
6768
|
+
}
|
|
6769
|
+
}
|
|
6770
|
+
/** Honored AskForAdvice consults per session (rate-limit + rung state; persists across turns). */
|
|
6771
|
+
mentorConsultCounts = new Map();
|
|
6772
|
+
/**
|
|
6773
|
+
* AskForAdvice executor (MENTORSHIP_ASK_FOR_ADVICE_SPEC v1). Orchestrator-dispatched
|
|
6774
|
+
* because it needs helperMiddleware + the decision store + session state, which the
|
|
6775
|
+
* packages/executors executors structurally lack. Graduated ladder: premature bounce →
|
|
6776
|
+
* mentor DIRECTED REFRAME → structured interview → rate-limited. The stronger mentor
|
|
6777
|
+
* (reactiveMentorship.helperModelId, e.g. deepseek-v4-pro) returns a HINT, never the
|
|
6778
|
+
* solution. Banks a `mentor_consult` episode for the apprentice data lake. Fail-open —
|
|
6779
|
+
* a mentor error never breaks the turn.
|
|
6780
|
+
*/
|
|
6781
|
+
async executeAskForAdvice(input) {
|
|
6782
|
+
const sessionId = this.currentSessionId ?? 'unknown';
|
|
6783
|
+
const store = this.getDecisionStore();
|
|
6784
|
+
const failedRows = store ? await store.recentFailures(6) : [];
|
|
6785
|
+
const failed = failedRows.map((d) => ({
|
|
6786
|
+
call: d.inputSummary || d.toolName,
|
|
6787
|
+
error: d.errorSnippet || '',
|
|
6788
|
+
}));
|
|
6789
|
+
const honored = this.mentorConsultCounts.get(sessionId) ?? 0;
|
|
6790
|
+
// v1 gate: the model self-selected by CALLING the tool, so a light "real struggle
|
|
6791
|
+
// exists" check (>=2 recent failures) suffices. The full thrashDetector drives the
|
|
6792
|
+
// proactive invite/forced-choice path (v2), not this executor.
|
|
6793
|
+
const thrashing = failed.length >= 2;
|
|
6794
|
+
const rung = resolveConsultRung(honored, thrashing);
|
|
6795
|
+
if (rung === 'bounce') {
|
|
6796
|
+
return { success: true, llmContent: bounceMessage(failed.length), metadata: { source: 'mentor-consult', rung } };
|
|
6797
|
+
}
|
|
6798
|
+
if (rung === 'ratelimited') {
|
|
6799
|
+
return { success: true, llmContent: rateLimitedMessage(resolveMentorConfig().maxConsults), metadata: { source: 'mentor-consult', rung } };
|
|
6800
|
+
}
|
|
6801
|
+
let hint;
|
|
6802
|
+
try {
|
|
6803
|
+
hint = await this.helperMiddleware.generateMentorHint({
|
|
6804
|
+
rung,
|
|
6805
|
+
task: this.lastRealUserText(),
|
|
6806
|
+
failed,
|
|
6807
|
+
question: input?.question,
|
|
6808
|
+
helperModelId: this.config.reactiveMentorship?.helperModelId,
|
|
6809
|
+
});
|
|
6810
|
+
}
|
|
6811
|
+
catch (err) {
|
|
6812
|
+
return {
|
|
6813
|
+
success: true,
|
|
6814
|
+
llmContent: 'Advice is unavailable right now — keep working the problem: re-read the task and try a distinct approach.',
|
|
6815
|
+
metadata: { source: 'mentor-consult', rung, error: String(err).slice(0, 120) },
|
|
6816
|
+
};
|
|
6817
|
+
}
|
|
6818
|
+
this.mentorConsultCounts.set(sessionId, honored + 1);
|
|
6819
|
+
if (store) {
|
|
6820
|
+
// §13-B3: the FULL episode for the apprentice data pump (§10). Tagged
|
|
6821
|
+
// `mentor_episode` so the distiller/canon can filter; `turn` lets it JOIN to
|
|
6822
|
+
// this task's graded outcome (the reward label lives on the task row, known
|
|
6823
|
+
// only at grade time). Full hint (not truncated) + the question + the failed
|
|
6824
|
+
// trace = the training-ready thrash→ask→hint record. Best-effort, never throws.
|
|
6825
|
+
store.recordEvent({
|
|
6826
|
+
sessionId,
|
|
6827
|
+
kind: 'mentor_consult',
|
|
6828
|
+
toolName: 'AskForAdvice',
|
|
6829
|
+
detail: {
|
|
6830
|
+
tag: 'mentor_episode',
|
|
6831
|
+
rung,
|
|
6832
|
+
turn: this.turnNumber,
|
|
6833
|
+
helperModel: this.config.reactiveMentorship?.helperModelId ?? 'default',
|
|
6834
|
+
question: input?.question ?? null,
|
|
6835
|
+
hint,
|
|
6836
|
+
failedCount: failed.length,
|
|
6837
|
+
failedTrace: failed.slice(0, 6),
|
|
6838
|
+
},
|
|
6839
|
+
}).catch(() => { });
|
|
6840
|
+
}
|
|
6841
|
+
return { success: true, llmContent: hint, metadata: { source: 'mentor-consult', rung, helperModel: this.config.reactiveMentorship?.helperModelId } };
|
|
6842
|
+
}
|
|
6702
6843
|
async processToolTraining(toolUse, result) {
|
|
6703
6844
|
const store = this.getDecisionStore();
|
|
6704
6845
|
if (!store)
|