@nexus-cortex/core 4.89.0 → 4.90.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/.env.example +73 -3
- package/dist/config/RuntimeConfigRegistry.d.ts.map +1 -1
- package/dist/config/RuntimeConfigRegistry.js +2 -0
- package/dist/config/RuntimeConfigRegistry.js.map +1 -1
- package/dist/config/SettingsLoader.d.ts.map +1 -1
- package/dist/config/SettingsLoader.js +2 -0
- package/dist/config/SettingsLoader.js.map +1 -1
- package/dist/config/SettingsSchema.d.ts +4 -0
- package/dist/config/SettingsSchema.d.ts.map +1 -1
- package/dist/config/SettingsSchema.js +19 -0
- package/dist/config/SettingsSchema.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +3 -1
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/middleware/HelperModelMiddleware.d.ts +13 -0
- package/dist/middleware/HelperModelMiddleware.d.ts.map +1 -1
- package/dist/middleware/HelperModelMiddleware.js +32 -0
- package/dist/middleware/HelperModelMiddleware.js.map +1 -1
- package/dist/middleware/helpers/HelperMiddlewareAdapter.interface.d.ts +6 -1
- package/dist/middleware/helpers/HelperMiddlewareAdapter.interface.d.ts.map +1 -1
- package/dist/middleware/helpers/HelperMiddlewareAdapter.interface.js.map +1 -1
- package/dist/middleware/helpers/adapters/ChatCompletionsAPIHelperAdapter.d.ts +9 -1
- package/dist/middleware/helpers/adapters/ChatCompletionsAPIHelperAdapter.d.ts.map +1 -1
- package/dist/middleware/helpers/adapters/ChatCompletionsAPIHelperAdapter.js +18 -4
- package/dist/middleware/helpers/adapters/ChatCompletionsAPIHelperAdapter.js.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.d.ts +5 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +64 -6
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/orchestrator/requirementsVerification.d.ts +11 -0
- package/dist/orchestrator/requirementsVerification.d.ts.map +1 -1
- package/dist/orchestrator/requirementsVerification.js +58 -1
- package/dist/orchestrator/requirementsVerification.js.map +1 -1
- package/dist/tools/ToolProfile.d.ts +7 -0
- package/dist/tools/ToolProfile.d.ts.map +1 -1
- package/dist/tools/ToolProfile.js +13 -0
- package/dist/tools/ToolProfile.js.map +1 -1
- package/dist/tools/registries/BaseToolRegistry.d.ts.map +1 -1
- package/dist/tools/registries/BaseToolRegistry.js +6 -2
- package/dist/tools/registries/BaseToolRegistry.js.map +1 -1
- package/package.json +3 -3
|
@@ -30,7 +30,7 @@ import { CacheMetricsAccumulator } from '../session/CacheMetricsAccumulator.js';
|
|
|
30
30
|
import { SubAgentProcessManager, createSubAgentProcessManager } from './SubAgentProcessManager.js';
|
|
31
31
|
// Phase 1: Tool Architecture Refactor - Unified Tool Registry
|
|
32
32
|
import { toolFactory } from '../tools/ToolFactory.js';
|
|
33
|
-
import { resolveToolProfile, resolveToolAnchor, resolveFrameProfile, resolveLiftNudge, resolveHeadlessDropAskUser, resolveDeferredLoading, isNarrowProfile, isToolAllowedByProfile, applyToolProfile, webToolBlocked } from '../tools/ToolProfile.js';
|
|
33
|
+
import { resolveToolProfile, resolveToolAnchor, resolveFrameProfile, resolveLiftNudge, resolveHeadlessDropAskUser, resolveDeferredLoading, isNarrowProfile, isToolAllowedByProfile, applyToolProfile, webToolBlocked, resolveVisionHelperModel } from '../tools/ToolProfile.js';
|
|
34
34
|
import { readStagedDoctrine, applyCuratedDoctrine, runOrientForStaging, withTimeout } from './doctrineCuration.js';
|
|
35
35
|
import { ExactRepeatTracker } from '../training/loopLadder.js';
|
|
36
36
|
import { slashCommandRegistry } from '../commands/SlashCommandRegistry.js';
|
|
@@ -44,7 +44,7 @@ import { classifyToolOutcome } from '../training/toolOutcome.js';
|
|
|
44
44
|
import { LoopLadder, formatLadderSignal } from '../training/loopLadder.js';
|
|
45
45
|
import { shouldNudgeInaction, formatInactionNudge } from './inactionGuard.js';
|
|
46
46
|
import { applyImageTtlForRequest } from './imageTtl.js';
|
|
47
|
-
import { verifyRequirements, resolveEndTurnRequirementsMode } from './requirementsVerification.js';
|
|
47
|
+
import { verifyRequirements, resolveEndTurnRequirementsMode, resolveEndTurnRequirementsStrict } from './requirementsVerification.js';
|
|
48
48
|
import { verifyIntegrity, resolveEndTurnIntegrityMode } from './integrityVerification.js';
|
|
49
49
|
import { detectSurrenderText, resolveSurrenderNudgeMode, SURRENDER_REMINDER } from './turnEndGuards.js';
|
|
50
50
|
import { ModelRouterMatrix } from '../training/ModelRouterMatrix.js';
|
|
@@ -478,7 +478,7 @@ export class CortexOrchestrator {
|
|
|
478
478
|
const catalogVision = this.getModel(this.currentModelId ?? '')?.vision === true;
|
|
479
479
|
return [...toolFactory.getAllTools(), ...extras]
|
|
480
480
|
.filter((t) => endTurnGateOn || t.name !== 'EndTurn')
|
|
481
|
-
.filter((t) => catalogVision || t.name !== 'ReadImage')
|
|
481
|
+
.filter((t) => catalogVision || !!resolveVisionHelperModel(process.env) || t.name !== 'ReadImage')
|
|
482
482
|
.filter((t) => (seen.has(t.name) ? false : (seen.add(t.name), true)))
|
|
483
483
|
.map((t) => ({
|
|
484
484
|
name: namingHandler.convertName(t.name, convention),
|
|
@@ -634,7 +634,7 @@ export class CortexOrchestrator {
|
|
|
634
634
|
const visionOn = model?.vision === true;
|
|
635
635
|
const factoryTools = this.applyBaseToolAllowlist(toolFactory.getAllTools()
|
|
636
636
|
.filter(t => endTurnGateOn || t.name !== 'EndTurn')
|
|
637
|
-
.filter(t => visionOn || t.name !== 'ReadImage'));
|
|
637
|
+
.filter(t => visionOn || !!resolveVisionHelperModel(process.env) || t.name !== 'ReadImage'));
|
|
638
638
|
// Tool-profile: MCP/management/context tools bypass ToolFactory, so the
|
|
639
639
|
// bash-only arm must suppress them here or the surface leaks (lean keeps
|
|
640
640
|
// them — they are part of the "guided" surface under test).
|
|
@@ -898,7 +898,7 @@ export class CortexOrchestrator {
|
|
|
898
898
|
// Thread the CARD's anchor to the executors (per-orchestrator config, by
|
|
899
899
|
// reference) so framing-aware executor behavior (ShellTool steering
|
|
900
900
|
// default) is model-card/registry-scoped, not process-global env.
|
|
901
|
-
this.executorRegistry.updateConfig({ activeAnchorProfile: this.cardAnchorProfile, allowCommandSubstitution: this.approvalMode.autoApproveActions });
|
|
901
|
+
this.executorRegistry.updateConfig({ activeAnchorProfile: this.cardAnchorProfile, allowCommandSubstitution: this.approvalMode.autoApproveActions, headless: this.approvalMode.autoApproveActions });
|
|
902
902
|
if (toolsToUse && toolsToUse.length > 0) {
|
|
903
903
|
toolsToUse = this.applyAnchorIfArmed(toolsToUse);
|
|
904
904
|
}
|
|
@@ -2095,6 +2095,8 @@ export class CortexOrchestrator {
|
|
|
2095
2095
|
verification: etUse?.input?.verification,
|
|
2096
2096
|
userTaskText: this.lastRealUserText(),
|
|
2097
2097
|
turnUsedMutatingTool,
|
|
2098
|
+
strict: resolveEndTurnRequirementsStrict(process.env),
|
|
2099
|
+
toolOutputs: thisTurnToolOutputs.join('\n'),
|
|
2098
2100
|
});
|
|
2099
2101
|
if (s4.ok) {
|
|
2100
2102
|
endTurnCalled = true;
|
|
@@ -2156,6 +2158,7 @@ export class CortexOrchestrator {
|
|
|
2156
2158
|
// Item 7: scrub ReadImage payloads from metadata BEFORE persist;
|
|
2157
2159
|
// the images inject as a user message after the results land.
|
|
2158
2160
|
const pendingImages = this.collectPendingImages(toolResults, effectiveModel.vision === true);
|
|
2161
|
+
await this.applyVisionHandoffs();
|
|
2159
2162
|
// Create tool_result messages and add to history
|
|
2160
2163
|
for (const toolResult of toolResults) {
|
|
2161
2164
|
const toolResultMessageId = uuidv4();
|
|
@@ -3196,7 +3199,7 @@ export class CortexOrchestrator {
|
|
|
3196
3199
|
// Thread the CARD's anchor to the executors (per-orchestrator config, by
|
|
3197
3200
|
// reference) so framing-aware executor behavior (ShellTool steering
|
|
3198
3201
|
// default) is model-card/registry-scoped, not process-global env.
|
|
3199
|
-
this.executorRegistry.updateConfig({ activeAnchorProfile: this.cardAnchorProfile, allowCommandSubstitution: this.approvalMode.autoApproveActions });
|
|
3202
|
+
this.executorRegistry.updateConfig({ activeAnchorProfile: this.cardAnchorProfile, allowCommandSubstitution: this.approvalMode.autoApproveActions, headless: this.approvalMode.autoApproveActions });
|
|
3200
3203
|
if (toolsToUse && toolsToUse.length > 0) {
|
|
3201
3204
|
toolsToUse = this.applyAnchorIfArmed(toolsToUse);
|
|
3202
3205
|
}
|
|
@@ -3808,6 +3811,7 @@ export class CortexOrchestrator {
|
|
|
3808
3811
|
}
|
|
3809
3812
|
// Item 7: scrub ReadImage payloads before persist (streaming parity).
|
|
3810
3813
|
const pendingImages = this.collectPendingImages(toolResults, effectiveModel.vision === true);
|
|
3814
|
+
await this.applyVisionHandoffs();
|
|
3811
3815
|
// Create tool_result messages and save to history
|
|
3812
3816
|
for (const toolResult of toolResults) {
|
|
3813
3817
|
// Emit tool result as streaming chunk for CLI display
|
|
@@ -6801,6 +6805,43 @@ export class CortexOrchestrator {
|
|
|
6801
6805
|
* hallucinated/PTC call that slipped the surface gate), the result is
|
|
6802
6806
|
* rewritten into an actionable error — a text-only model must never have
|
|
6803
6807
|
* an image dangled at it. */
|
|
6808
|
+
/** Vision hand-off queue (filled by collectPendingImages for text-only primaries). */
|
|
6809
|
+
pendingVisionHandoffs = [];
|
|
6810
|
+
/** Resolve queued ReadImage hand-offs through the helper middleware: the vision helper's TEXT
|
|
6811
|
+
* replaces the tool_result content. Failures degrade to the pre-hand-off guidance (bash OCR). */
|
|
6812
|
+
async applyVisionHandoffs() {
|
|
6813
|
+
const queue = this.pendingVisionHandoffs;
|
|
6814
|
+
this.pendingVisionHandoffs = [];
|
|
6815
|
+
for (const h of queue) {
|
|
6816
|
+
const modelId = resolveVisionHelperModel(process.env) || 'deepseek-v4-flash-vision-exp';
|
|
6817
|
+
try {
|
|
6818
|
+
const t0 = Date.now();
|
|
6819
|
+
const text = await this.helperMiddleware.describeImage({
|
|
6820
|
+
mediaType: h.payload.mediaType, base64: h.payload.base64, prompt: h.prompt, filePath: h.filePath, helperModelId: modelId,
|
|
6821
|
+
});
|
|
6822
|
+
h.tr.is_error = false;
|
|
6823
|
+
h.tr.content =
|
|
6824
|
+
`[ReadImage → vision helper ${modelId}${h.filePath ? ` on ${h.filePath}` : ''}]\n` +
|
|
6825
|
+
(text || '(the vision helper returned no description)') +
|
|
6826
|
+
`\n\n(Read by the vision helper on your behalf — the active model is text-only. Ask again with a more specific \`prompt\` if you need a different reading.)`;
|
|
6827
|
+
if (this.config.debug)
|
|
6828
|
+
console.log(`[VisionHandoff] ${modelId} described ${h.filePath || 'image'} in ${Date.now() - t0}ms (${(text || '').length} chars)`);
|
|
6829
|
+
const store = this.getDecisionStore();
|
|
6830
|
+
if (store) {
|
|
6831
|
+
void store.recordEvent({
|
|
6832
|
+
sessionId: this.currentSessionId ?? 'unknown', kind: 'steering_injected', toolName: 'ReadImage',
|
|
6833
|
+
detail: { kind: 'vision_handoff', helper: modelId, chars: (text || '').length, filePath: h.filePath },
|
|
6834
|
+
}).catch(() => { });
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
catch (err) {
|
|
6838
|
+
h.tr.is_error = true;
|
|
6839
|
+
h.tr.content =
|
|
6840
|
+
`ReadImage vision hand-off failed (${modelId}: ${err?.message || err}). ` +
|
|
6841
|
+
'Extract what you need through bash instead (e.g. tesseract OCR, ffprobe, PIL).';
|
|
6842
|
+
}
|
|
6843
|
+
}
|
|
6844
|
+
}
|
|
6804
6845
|
collectPendingImages(toolResults, modelVision) {
|
|
6805
6846
|
const out = [];
|
|
6806
6847
|
for (const tr of toolResults) {
|
|
@@ -6811,6 +6852,16 @@ export class CortexOrchestrator {
|
|
|
6811
6852
|
if (tr.is_error)
|
|
6812
6853
|
continue;
|
|
6813
6854
|
if (!modelVision) {
|
|
6855
|
+
// VISION HAND-OFF (2026-09-02): a text-only primary called ReadImage. If a vision helper
|
|
6856
|
+
// is configured, queue the payload for the helper middleware (applyVisionHandoffs runs
|
|
6857
|
+
// right after this at both call sites and REPLACES the tool_result with the helper's
|
|
6858
|
+
// text). The primary never receives an image payload — item 7's safety intent holds.
|
|
6859
|
+
if (resolveVisionHelperModel(process.env)) {
|
|
6860
|
+
this.pendingVisionHandoffs.push({ tr, payload, prompt: tr.metadata?.imagePrompt, filePath: tr.metadata?.imageFilePath });
|
|
6861
|
+
delete tr.metadata.imagePrompt;
|
|
6862
|
+
delete tr.metadata.imageFilePath;
|
|
6863
|
+
continue;
|
|
6864
|
+
}
|
|
6814
6865
|
tr.is_error = true;
|
|
6815
6866
|
tr.content =
|
|
6816
6867
|
'ReadImage requires a vision-capable model — the active model cannot see images. ' +
|
|
@@ -7055,6 +7106,13 @@ export class CortexOrchestrator {
|
|
|
7055
7106
|
const store = this.getDecisionStore();
|
|
7056
7107
|
if (!store)
|
|
7057
7108
|
return result;
|
|
7109
|
+
// TOOL_TIMEOUT_MODE engagement evidence: a promoted-to-background tool call.
|
|
7110
|
+
if (result.metadata?.promotedToBackground) {
|
|
7111
|
+
void store.recordEvent({
|
|
7112
|
+
sessionId: this.currentSessionId ?? 'unknown', kind: 'steering_injected', toolName: toolUse.name,
|
|
7113
|
+
detail: { kind: 'tool_promoted', bashId: result.metadata.promotedToBackground },
|
|
7114
|
+
}).catch(() => { });
|
|
7115
|
+
}
|
|
7058
7116
|
// Unified outcome layer (docs/UNIFIED_OUTCOME_LADDER.md): ONE failure
|
|
7059
7117
|
// semantics for recording + reminders. Critically, a bash command that
|
|
7060
7118
|
// ran and exited nonzero is a FAILURE here even though its tool result
|