@nexus-cortex/core 4.124.44 → 4.124.46
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.defaults +144 -0
- package/dist/adapters/GatewayTranslationLayer.d.ts.map +1 -1
- package/dist/adapters/GatewayTranslationLayer.js +27 -1
- package/dist/adapters/GatewayTranslationLayer.js.map +1 -1
- package/dist/adapters/ServerSideToolDetection.d.ts.map +1 -1
- package/dist/adapters/ServerSideToolDetection.js +5 -1
- package/dist/adapters/ServerSideToolDetection.js.map +1 -1
- package/dist/config/effectiveConfig.d.ts.map +1 -1
- package/dist/config/effectiveConfig.js +16 -0
- package/dist/config/effectiveConfig.js.map +1 -1
- package/dist/orchestrator/APIClient.d.ts.map +1 -1
- package/dist/orchestrator/APIClient.js +120 -25
- package/dist/orchestrator/APIClient.js.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.d.ts +22 -0
- package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
- package/dist/orchestrator/CortexOrchestrator.js +210 -83
- package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
- package/dist/orchestrator/appendOnlyHistory.d.ts +39 -0
- package/dist/orchestrator/appendOnlyHistory.d.ts.map +1 -0
- package/dist/orchestrator/appendOnlyHistory.js +79 -0
- package/dist/orchestrator/appendOnlyHistory.js.map +1 -0
- package/dist/orchestrator/transportCacheFixes.d.ts +22 -0
- package/dist/orchestrator/transportCacheFixes.d.ts.map +1 -0
- package/dist/orchestrator/transportCacheFixes.js +114 -0
- package/dist/orchestrator/transportCacheFixes.js.map +1 -0
- package/dist/orchestrator/transportEffortFixes.d.ts +62 -0
- package/dist/orchestrator/transportEffortFixes.d.ts.map +1 -0
- package/dist/orchestrator/transportEffortFixes.js +114 -0
- package/dist/orchestrator/transportEffortFixes.js.map +1 -0
- package/dist/orchestrator/wallGuard.d.ts +3 -1
- package/dist/orchestrator/wallGuard.d.ts.map +1 -1
- package/dist/orchestrator/wallGuard.js +15 -2
- package/dist/orchestrator/wallGuard.js.map +1 -1
- package/dist/tools/ClientSideToolFilter.d.ts +9 -2
- package/dist/tools/ClientSideToolFilter.d.ts.map +1 -1
- package/dist/tools/ClientSideToolFilter.js +26 -3
- package/dist/tools/ClientSideToolFilter.js.map +1 -1
- package/dist/training/DecisionStore.d.ts +1 -1
- package/dist/training/DecisionStore.d.ts.map +1 -1
- package/dist/training/DecisionStore.js.map +1 -1
- package/package.json +3 -3
|
@@ -91,6 +91,8 @@ import { InitCortexContext, MemoryWrite, MemoryRecall } from '../tools/context-m
|
|
|
91
91
|
import { pruneAgedToolResults } from '../conversation/ToolResultPruner.js';
|
|
92
92
|
import { detectTailRepetition, tailLoopGuardEnabled } from './tailRepetitionDetector.js';
|
|
93
93
|
import { resolveEffortRamp, rampEffortFor } from './effortRamp.js';
|
|
94
|
+
import { firstRequestActionEffort } from './transportEffortFixes.js'; // CORTEX_ACTION_EFFORT_FIRST (dark)
|
|
95
|
+
import { resolveWallCacheFix, resolvePersistInjected, resolveAppendOnlyTools, resolveKeepMentorMessages, resolveResponsesSliceAll, chainedSliceStart, tailUnitAfterLastAssistant, isPreviousResponseUnavailable } from './appendOnlyHistory.js'; // R221-R228 append-only history (dark)
|
|
94
96
|
import { resolveWallDrop, resolveOutputCap, dropWalledTurn, resolveWallSummary, extractWalledReasoning, clipReasoning, formatWallSummary } from './wallGuard.js';
|
|
95
97
|
import { resolvePid1Guard, detectPid1Note } from './pid1Guard.js'; // R209
|
|
96
98
|
import { PlateauStopTracker, plateauBootInstruction, plateauStatusSegment } from './plateauStop.js'; // R210
|
|
@@ -382,6 +384,7 @@ export class CortexOrchestrator {
|
|
|
382
384
|
type: 'text',
|
|
383
385
|
text: `<system-reminder>\nFull session context follows (deferred until your first action; applies from here on).\n</system-reminder>\n${corpus}`
|
|
384
386
|
});
|
|
387
|
+
this.invalidateTailUnitConversions(); // R221 safety net (CORTEX_WALL_CACHE_FIX; off = no-op)
|
|
385
388
|
if (this.config.debug) {
|
|
386
389
|
console.log(`[Anchor] deferred static corpus delivered at lift (${corpus.length} chars)`);
|
|
387
390
|
}
|
|
@@ -424,6 +427,7 @@ export class CortexOrchestrator {
|
|
|
424
427
|
if (!r)
|
|
425
428
|
return;
|
|
426
429
|
lastMsg.message.content.push({ type: 'text', text: `<system-reminder>\n${r.note}\n</system-reminder>` });
|
|
430
|
+
this.invalidateTailUnitConversions(); // R221 safety net
|
|
427
431
|
const store = this.getDecisionStore();
|
|
428
432
|
if (store)
|
|
429
433
|
void store.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'pid1_guard', detail: { noted: true, pid1Cmd: r.info.pid1Cmd, children: r.info.children, chars: r.note.length } }).catch(() => { });
|
|
@@ -447,6 +451,7 @@ export class CortexOrchestrator {
|
|
|
447
451
|
return; // not the boundary yet — leave the one-shot open
|
|
448
452
|
this.plateauInstructionDelivered = true;
|
|
449
453
|
lastMsg.message.content.push({ type: 'text', text: `<system-reminder>\n${text}\n</system-reminder>` });
|
|
454
|
+
this.invalidateTailUnitConversions(); // R221 safety net
|
|
450
455
|
if (this.config.debug)
|
|
451
456
|
console.log('[PlateauStop] boot instruction delivered');
|
|
452
457
|
}
|
|
@@ -521,6 +526,7 @@ export class CortexOrchestrator {
|
|
|
521
526
|
text: `<system-reminder>\n${parts.join(' ')}\n</system-reminder>`
|
|
522
527
|
});
|
|
523
528
|
this.liftNudgeDelivered = true; // one-shot: consumed only on ACTUAL delivery
|
|
529
|
+
this.invalidateTailUnitConversions(); // R221 safety net
|
|
524
530
|
if (this.config.debug) {
|
|
525
531
|
console.log(`[Anchor] lift nudge delivered (${parts.join(' ').length} chars, ${hidden.length} hidden tools)`);
|
|
526
532
|
}
|
|
@@ -657,6 +663,7 @@ export class CortexOrchestrator {
|
|
|
657
663
|
`It is anchored to the REAL success criteria (what the task's own grader checks), NOT your own ` +
|
|
658
664
|
`tests. Your own tests are a means, never the finish line.\n\n${plan}\n</system-reminder>`,
|
|
659
665
|
});
|
|
666
|
+
this.invalidateTailUnitConversions(); // R221 safety net
|
|
660
667
|
if (store)
|
|
661
668
|
void store.recordEvent({
|
|
662
669
|
sessionId,
|
|
@@ -702,6 +709,7 @@ export class CortexOrchestrator {
|
|
|
702
709
|
return; // nothing authored (yet) — leave the one-shot open
|
|
703
710
|
this.reqLedgerDelivered = true;
|
|
704
711
|
lastMsg?.message?.content?.push?.({ type: 'text', text: `<system-reminder>\n${text}\n</system-reminder>` });
|
|
712
|
+
this.invalidateTailUnitConversions(); // R221 safety net
|
|
705
713
|
const store = this.getDecisionStore();
|
|
706
714
|
if (store)
|
|
707
715
|
void store.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'requirement_ledger_delivered', toolName: 'EndTurn', detail: { lines: (entries ?? []).length, chars: text.length } }).catch(() => { });
|
|
@@ -2105,6 +2113,7 @@ export class CortexOrchestrator {
|
|
|
2105
2113
|
}
|
|
2106
2114
|
};
|
|
2107
2115
|
messageHistoryForApi[messageHistoryForApi.length - 1] = userMessageForApi;
|
|
2116
|
+
this.rememberInjectedContent(userMessage.uuid, injectedContent); // R223 (CORTEX_PERSIST_INJECTED; off = no-op): later requests send the same bytes
|
|
2108
2117
|
// canonicalHistory will be re-computed after effectiveModel is determined
|
|
2109
2118
|
// (see input-slicing for cross-turn chain below).
|
|
2110
2119
|
// Debug logging for tools (already gathered above)
|
|
@@ -2172,7 +2181,7 @@ export class CortexOrchestrator {
|
|
|
2172
2181
|
const isPTCEnabled = this.config.enablePTC && effectiveModel.supportsPTC && effectiveModel.provider === 'anthropic';
|
|
2173
2182
|
// Deferred loading: filter tools for non-PTC paths (essential + recently-used only)
|
|
2174
2183
|
if (!isPTCEnabled && this.effectiveDeferredLoading && toolsToUse && toolsToUse.length > 0) {
|
|
2175
|
-
toolsToUse = this.toolFilter.getFilteredTools(toolsToUse);
|
|
2184
|
+
toolsToUse = this.toolFilter.getFilteredTools(toolsToUse, { appendOnly: resolveAppendOnlyTools() });
|
|
2176
2185
|
}
|
|
2177
2186
|
// First-turn anchoring narrows further while armed (no-op once lifted).
|
|
2178
2187
|
// Card-level home door: capture the active card's anchorProfile (env
|
|
@@ -2211,16 +2220,27 @@ export class CortexOrchestrator {
|
|
|
2211
2220
|
this.mentorshipMiddleware?.resetSequentialCalls(this.currentSessionId);
|
|
2212
2221
|
// §13-B2: force AskForAdvice this turn on high-confidence thrash (mentor-force armed).
|
|
2213
2222
|
const forcedMentorChoice = await this.resolveForcedMentorChoice(toolsToUse, 0); // initial request: 0 tool calls yet
|
|
2214
|
-
const
|
|
2223
|
+
const initialPrepOpts = {
|
|
2215
2224
|
temperature: options.parameters?.temperature,
|
|
2216
2225
|
maxTokens: options.parameters?.maxTokens,
|
|
2217
2226
|
topP: options.parameters?.topP,
|
|
2218
|
-
reasoningEffort: this.nextRampEffort(true) ?? options.parameters?.reasoningEffort, // HB-EFFORT-RAMP (dark) > request param
|
|
2227
|
+
reasoningEffort: this.nextRampEffort(true) ?? options.parameters?.reasoningEffort ?? firstRequestActionEffort(), // HB-EFFORT-RAMP (dark) > request param > CORTEX_ACTION_EFFORT on request 0 (CORTEX_ACTION_EFFORT_FIRST, dark)
|
|
2219
2228
|
stream: options.streaming,
|
|
2220
2229
|
staticSystemPrompt: this.currentStaticSystemPrompt, // R28
|
|
2221
2230
|
conversationId: this.currentConversationId, // R28b
|
|
2222
2231
|
toolChoice: forcedMentorChoice // §13-B2 forced mentor tool_choice
|
|
2223
|
-
}
|
|
2232
|
+
};
|
|
2233
|
+
const preparedRequest = this.gatewayTranslation.prepareRequest(canonicalHistory, toolsToUse, effectiveModel, initialPrepOpts);
|
|
2234
|
+
// R228 fallback (dark): the unchained full-history twin of preparedRequest, built only if the held response is gone.
|
|
2235
|
+
const rebuildInitialFull = () => {
|
|
2236
|
+
const r = this.gatewayTranslation.prepareRequest(this.convertToCanonicalMessages(messageHistoryForApi), toolsToUse, effectiveModel, initialPrepOpts);
|
|
2237
|
+
r.conversationId = this.currentSessionId;
|
|
2238
|
+
if (isPTCEnabled && toolsToUse && toolsToUse.length > 0) {
|
|
2239
|
+
r.tools = this.gatewayTranslation.prepareToolsWithPTC(toolsToUse, effectiveModel);
|
|
2240
|
+
r.parameters.enablePTC = true;
|
|
2241
|
+
}
|
|
2242
|
+
return r;
|
|
2243
|
+
};
|
|
2224
2244
|
// Stateful Responses API: chain from prior response when available
|
|
2225
2245
|
// (works across user turns — lastResponseId is preserved between messages).
|
|
2226
2246
|
// Only affects 'responses' api.pattern; other providers ignore this field.
|
|
@@ -2257,8 +2277,11 @@ export class CortexOrchestrator {
|
|
|
2257
2277
|
// Use effectiveModel (which may have modified endpoint/pattern for server-side tools)
|
|
2258
2278
|
// Wrap API call with retry middleware for automatic retry on transient errors
|
|
2259
2279
|
if (this.retryMiddleware) {
|
|
2260
|
-
|
|
2261
|
-
apiResponse =
|
|
2280
|
+
let retryResult;
|
|
2281
|
+
apiResponse = await this.sendWithChainFallback(preparedRequest, async (r) => {
|
|
2282
|
+
retryResult = await this.retryMiddleware.executeWithRetry(() => this.apiClient.sendRequest(r, effectiveModel), 'primary_api_call');
|
|
2283
|
+
return retryResult.result;
|
|
2284
|
+
}, rebuildInitialFull, 'primary_api_call'); // R228 fallback (dark; off = one send)
|
|
2262
2285
|
// Log retry information if retries occurred
|
|
2263
2286
|
if (this.config.debug && retryResult.attemptCount > 1) {
|
|
2264
2287
|
console.log(`[Orchestrator] API call succeeded after ${retryResult.attemptCount} attempts`);
|
|
@@ -2267,7 +2290,7 @@ export class CortexOrchestrator {
|
|
|
2267
2290
|
}
|
|
2268
2291
|
else {
|
|
2269
2292
|
// Fallback: direct call if middleware not available
|
|
2270
|
-
apiResponse = await this.apiClient.sendRequest(
|
|
2293
|
+
apiResponse = await this.sendWithChainFallback(preparedRequest, (r) => this.apiClient.sendRequest(r, effectiveModel), rebuildInitialFull, 'primary_api_call'); // R228 fallback (dark)
|
|
2271
2294
|
}
|
|
2272
2295
|
}
|
|
2273
2296
|
catch (error) {
|
|
@@ -2699,6 +2722,7 @@ export class CortexOrchestrator {
|
|
|
2699
2722
|
if (isEmpty) {
|
|
2700
2723
|
m.message = m.message || { role: 'assistant' };
|
|
2701
2724
|
m.message.content = [{ type: 'text', text: '(no output)' }];
|
|
2725
|
+
this.invalidateConversions([m]); // R221 safety net
|
|
2702
2726
|
if (this.config.debug) {
|
|
2703
2727
|
console.log(`[Orchestrator] R26: repaired empty assistant message at history[${i}] before retry`);
|
|
2704
2728
|
}
|
|
@@ -2740,7 +2764,7 @@ export class CortexOrchestrator {
|
|
|
2740
2764
|
await this.ensureHistoryFitsModel(effectiveModel);
|
|
2741
2765
|
const retryEffort = this.consumeReasoningBackoff() ?? options.parameters?.reasoningEffort; // R153 backoff > request param
|
|
2742
2766
|
const buildRetryRequest = () => {
|
|
2743
|
-
const retryCanonicalHistory = this.convertToCanonicalMessages(
|
|
2767
|
+
const retryCanonicalHistory = this.convertToCanonicalMessages(this.chainedHistoryForApi(effectiveModel)); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = full history)
|
|
2744
2768
|
const req = this.gatewayTranslation.prepareRequest(retryCanonicalHistory, toolsToUse, effectiveModel, {
|
|
2745
2769
|
temperature: options.parameters?.temperature,
|
|
2746
2770
|
maxTokens: options.parameters?.maxTokens,
|
|
@@ -2789,6 +2813,7 @@ export class CortexOrchestrator {
|
|
|
2789
2813
|
...(retryConverted.usage && { usage: retryConverted.usage }),
|
|
2790
2814
|
};
|
|
2791
2815
|
this.messageHistory.push(retryAssistantMessage);
|
|
2816
|
+
this.markChainedResponseCheckpoint(effectiveModel); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = no-op)
|
|
2792
2817
|
await this.historyStore.appendMessage(this.currentSessionId, retryAssistantMessage);
|
|
2793
2818
|
// Update current pointer so the loop re-evaluates with new content.
|
|
2794
2819
|
currentAssistantMessage = retryAssistantMessage;
|
|
@@ -2860,28 +2885,28 @@ export class CortexOrchestrator {
|
|
|
2860
2885
|
this.messageHistory.push(inactionUserMessage);
|
|
2861
2886
|
await this.historyStore.appendMessage(this.currentSessionId, inactionUserMessage);
|
|
2862
2887
|
await this.ensureHistoryFitsModel(effectiveModel);
|
|
2863
|
-
const
|
|
2864
|
-
const
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2888
|
+
const inactionEffort = this.consumeReasoningBackoff() ?? options.parameters?.reasoningEffort; // R153 backoff > request param (consumed once)
|
|
2889
|
+
const buildInactionRequest = () => {
|
|
2890
|
+
const inactionCanonicalHistory = this.convertToCanonicalMessages(this.chainedHistoryForApi(effectiveModel)); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = full history)
|
|
2891
|
+
const inactionRequest = this.gatewayTranslation.prepareRequest(inactionCanonicalHistory, toolsToUse, effectiveModel, {
|
|
2892
|
+
temperature: options.parameters?.temperature,
|
|
2893
|
+
maxTokens: options.parameters?.maxTokens,
|
|
2894
|
+
topP: options.parameters?.topP,
|
|
2895
|
+
reasoningEffort: inactionEffort,
|
|
2896
|
+
stream: options.streaming,
|
|
2897
|
+
staticSystemPrompt: this.currentStaticSystemPrompt, // R28
|
|
2898
|
+
conversationId: this.currentConversationId, // R28b
|
|
2899
|
+
});
|
|
2900
|
+
if (this.lastResponseId && effectiveModel.api.pattern === 'responses') {
|
|
2901
|
+
inactionRequest.previousResponseId = this.lastResponseId;
|
|
2902
|
+
}
|
|
2903
|
+
inactionRequest.conversationId = this.currentSessionId;
|
|
2904
|
+
return inactionRequest;
|
|
2905
|
+
};
|
|
2906
|
+
const sendInactionRequest = async (r) => this.retryMiddleware
|
|
2907
|
+
? (await this.retryMiddleware.executeWithRetry(() => this.apiClient.sendRequest(r, effectiveModel), 'inaction_nudge_retry')).result
|
|
2908
|
+
: this.apiClient.sendRequest(r, effectiveModel);
|
|
2909
|
+
const inactionApiResponse = await this.sendWithChainFallback(buildInactionRequest(), sendInactionRequest, buildInactionRequest, 'inaction_nudge_retry'); // R228 fallback (dark; off = one send)
|
|
2885
2910
|
const inactionConverted = this.gatewayTranslation.convertResponse(inactionApiResponse.data, effectiveModel, {
|
|
2886
2911
|
sessionId: this.currentSessionId,
|
|
2887
2912
|
conversationId: this.currentConversationId,
|
|
@@ -2914,6 +2939,7 @@ export class CortexOrchestrator {
|
|
|
2914
2939
|
...(inactionConverted.usage && { usage: inactionConverted.usage }),
|
|
2915
2940
|
};
|
|
2916
2941
|
this.messageHistory.push(inactionAssistantMessage);
|
|
2942
|
+
this.markChainedResponseCheckpoint(effectiveModel); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = no-op)
|
|
2917
2943
|
await this.historyStore.appendMessage(this.currentSessionId, inactionAssistantMessage);
|
|
2918
2944
|
currentAssistantMessage = inactionAssistantMessage;
|
|
2919
2945
|
currentAssistantCanonicalMessage = inactionAssistantCanonical;
|
|
@@ -3029,6 +3055,7 @@ export class CortexOrchestrator {
|
|
|
3029
3055
|
if (isEmpty) {
|
|
3030
3056
|
m.message = m.message || { role: 'assistant' };
|
|
3031
3057
|
m.message.content = [{ type: 'text', text: '(no output)' }];
|
|
3058
|
+
this.invalidateConversions([m]); // R221 safety net
|
|
3032
3059
|
}
|
|
3033
3060
|
break;
|
|
3034
3061
|
}
|
|
@@ -3075,28 +3102,28 @@ export class CortexOrchestrator {
|
|
|
3075
3102
|
this.messageHistory.push(endTurnReminder);
|
|
3076
3103
|
await this.historyStore.appendMessage(this.currentSessionId, endTurnReminder);
|
|
3077
3104
|
await this.ensureHistoryFitsModel(effectiveModel);
|
|
3078
|
-
const
|
|
3079
|
-
const
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3105
|
+
const gateEffort = this.consumeReasoningBackoff() ?? options.parameters?.reasoningEffort; // R153 backoff > request param (consumed once)
|
|
3106
|
+
const buildGateRequest = () => {
|
|
3107
|
+
const gateCanonicalHistory = this.convertToCanonicalMessages(this.chainedHistoryForApi(effectiveModel)); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = full history)
|
|
3108
|
+
const gateRequest = this.gatewayTranslation.prepareRequest(gateCanonicalHistory, toolsToUse, effectiveModel, {
|
|
3109
|
+
temperature: options.parameters?.temperature,
|
|
3110
|
+
maxTokens: options.parameters?.maxTokens,
|
|
3111
|
+
topP: options.parameters?.topP,
|
|
3112
|
+
reasoningEffort: gateEffort,
|
|
3113
|
+
stream: options.streaming,
|
|
3114
|
+
staticSystemPrompt: this.currentStaticSystemPrompt,
|
|
3115
|
+
conversationId: this.currentConversationId,
|
|
3116
|
+
});
|
|
3117
|
+
if (this.lastResponseId && effectiveModel.api.pattern === 'responses') {
|
|
3118
|
+
gateRequest.previousResponseId = this.lastResponseId;
|
|
3119
|
+
}
|
|
3120
|
+
gateRequest.conversationId = this.currentSessionId;
|
|
3121
|
+
return gateRequest;
|
|
3122
|
+
};
|
|
3123
|
+
const sendGate = async (r) => this.retryMiddleware
|
|
3124
|
+
? (await this.retryMiddleware.executeWithRetry(() => this.apiClient.sendRequest(r, effectiveModel), 'end_turn_gate')).result
|
|
3125
|
+
: this.apiClient.sendRequest(r, effectiveModel);
|
|
3126
|
+
const gateApiResponse = await this.sendWithChainFallback(buildGateRequest(), sendGate, buildGateRequest, 'end_turn_gate'); // R228 fallback (dark; off = one send)
|
|
3100
3127
|
const gateConverted = this.gatewayTranslation.convertResponse(gateApiResponse.data, effectiveModel, {
|
|
3101
3128
|
sessionId: this.currentSessionId,
|
|
3102
3129
|
conversationId: this.currentConversationId,
|
|
@@ -3129,6 +3156,7 @@ export class CortexOrchestrator {
|
|
|
3129
3156
|
...(gateConverted.usage && { usage: gateConverted.usage }),
|
|
3130
3157
|
};
|
|
3131
3158
|
this.messageHistory.push(gateAssistantMessage);
|
|
3159
|
+
this.markChainedResponseCheckpoint(effectiveModel); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = no-op)
|
|
3132
3160
|
await this.historyStore.appendMessage(this.currentSessionId, gateAssistantMessage);
|
|
3133
3161
|
currentAssistantMessage = gateAssistantMessage;
|
|
3134
3162
|
currentAssistantCanonicalMessage = gateAssistantCanonical;
|
|
@@ -3589,6 +3617,7 @@ export class CortexOrchestrator {
|
|
|
3589
3617
|
const block = lastMsg.message.content[0];
|
|
3590
3618
|
const existing = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
|
|
3591
3619
|
block.content = existing + '\n\n' + signals;
|
|
3620
|
+
this.invalidateTailUnitConversions(); // R221 safety net
|
|
3592
3621
|
// Observability (backlog item 3, micro-suite defect #4): this
|
|
3593
3622
|
// mutation happens AFTER the tool_result was persisted — the
|
|
3594
3623
|
// durable session lacks the steering the model saw. Bank a
|
|
@@ -3723,7 +3752,7 @@ export class CortexOrchestrator {
|
|
|
3723
3752
|
// are included in the continuation request's tools array
|
|
3724
3753
|
if (this.effectiveDeferredLoading && !isPTCEnabled) {
|
|
3725
3754
|
const beforeCount = toolsToUse.length;
|
|
3726
|
-
toolsToUse = this.toolFilter.getFilteredTools(allTools);
|
|
3755
|
+
toolsToUse = this.toolFilter.getFilteredTools(allTools, { appendOnly: resolveAppendOnlyTools() });
|
|
3727
3756
|
// StructuredOutput: the re-filter rebuilds from allTools (which never
|
|
3728
3757
|
// contained the request-scoped tool) — re-append so it stays present
|
|
3729
3758
|
// on every request of the turn.
|
|
@@ -4028,7 +4057,7 @@ export class CortexOrchestrator {
|
|
|
4028
4057
|
await this.ensureHistoryFitsModel(effectiveModel);
|
|
4029
4058
|
const synthEffort = this.consumeReasoningBackoff() ?? options.parameters?.reasoningEffort; // R153 backoff > request param
|
|
4030
4059
|
const buildSynthRequest = () => {
|
|
4031
|
-
const synthCanonicalHistory = this.convertToCanonicalMessages(
|
|
4060
|
+
const synthCanonicalHistory = this.convertToCanonicalMessages(this.chainedHistoryForApi(effectiveModel)); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = full history)
|
|
4032
4061
|
const req = this.gatewayTranslation.prepareRequest(synthCanonicalHistory,
|
|
4033
4062
|
// Tools suppressed — the model MUST produce text, not call more tools.
|
|
4034
4063
|
// NOTE (structured-output constraint, 2026-08-02): this is R29a's
|
|
@@ -4085,6 +4114,7 @@ export class CortexOrchestrator {
|
|
|
4085
4114
|
...(synthConverted.usage && { usage: synthConverted.usage }),
|
|
4086
4115
|
};
|
|
4087
4116
|
this.messageHistory.push(synthAssistantMessage);
|
|
4117
|
+
this.markChainedResponseCheckpoint(effectiveModel); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = no-op)
|
|
4088
4118
|
await this.historyStore.appendMessage(this.currentSessionId, synthAssistantMessage);
|
|
4089
4119
|
this.sessionTimeline.recordMessage(synthAssistantMessage.uuid, 'assistant');
|
|
4090
4120
|
if (synthConverted.usage) {
|
|
@@ -4487,6 +4517,7 @@ export class CortexOrchestrator {
|
|
|
4487
4517
|
}
|
|
4488
4518
|
};
|
|
4489
4519
|
messageHistoryForApi[messageHistoryForApi.length - 1] = userMessageForApi;
|
|
4520
|
+
this.rememberInjectedContent(userMessage.uuid, injectedContent); // R223 (CORTEX_PERSIST_INJECTED; off = no-op): later requests send the same bytes
|
|
4490
4521
|
// canonicalHistory computed after effectiveModel is determined (input-slicing below).
|
|
4491
4522
|
// Tools already gathered above for middleware injection
|
|
4492
4523
|
// Server-side tool detection
|
|
@@ -4514,7 +4545,7 @@ export class CortexOrchestrator {
|
|
|
4514
4545
|
const isPTCEnabled = this.config.enablePTC && effectiveModel.supportsPTC && effectiveModel.provider === 'anthropic';
|
|
4515
4546
|
// Deferred loading: filter tools for non-PTC paths (essential + recently-used only)
|
|
4516
4547
|
if (!isPTCEnabled && this.effectiveDeferredLoading && toolsToUse && toolsToUse.length > 0) {
|
|
4517
|
-
toolsToUse = this.toolFilter.getFilteredTools(toolsToUse);
|
|
4548
|
+
toolsToUse = this.toolFilter.getFilteredTools(toolsToUse, { appendOnly: resolveAppendOnlyTools() });
|
|
4518
4549
|
}
|
|
4519
4550
|
// First-turn anchoring narrows further while armed (no-op once lifted).
|
|
4520
4551
|
// Card-level home door: capture the active card's anchorProfile (env
|
|
@@ -4568,7 +4599,7 @@ export class CortexOrchestrator {
|
|
|
4568
4599
|
temperature: options.parameters?.temperature,
|
|
4569
4600
|
maxTokens: options.parameters?.maxTokens,
|
|
4570
4601
|
topP: options.parameters?.topP,
|
|
4571
|
-
reasoningEffort: this.nextRampEffort(true) ?? options.parameters?.reasoningEffort, // HB-EFFORT-RAMP (dark) > request param
|
|
4602
|
+
reasoningEffort: this.nextRampEffort(true) ?? options.parameters?.reasoningEffort ?? firstRequestActionEffort(), // HB-EFFORT-RAMP (dark) > request param > CORTEX_ACTION_EFFORT on request 0 (CORTEX_ACTION_EFFORT_FIRST, dark)
|
|
4572
4603
|
stream: true, // Enable streaming!
|
|
4573
4604
|
staticSystemPrompt: this.currentStaticSystemPrompt, // R28
|
|
4574
4605
|
conversationId: this.currentConversationId, // R28b
|
|
@@ -4909,6 +4940,7 @@ export class CortexOrchestrator {
|
|
|
4909
4940
|
if (isEmpty) {
|
|
4910
4941
|
m.message = m.message || { role: 'assistant' };
|
|
4911
4942
|
m.message.content = [{ type: 'text', text: '(no output)' }];
|
|
4943
|
+
this.invalidateConversions([m]); // R221 safety net
|
|
4912
4944
|
}
|
|
4913
4945
|
break;
|
|
4914
4946
|
}
|
|
@@ -4942,7 +4974,7 @@ export class CortexOrchestrator {
|
|
|
4942
4974
|
await this.ensureHistoryFitsModel(effectiveModel);
|
|
4943
4975
|
const retryEffort = this.consumeReasoningBackoff() ?? options.parameters?.reasoningEffort; // R153 backoff > request param
|
|
4944
4976
|
const buildRetryRequest = () => {
|
|
4945
|
-
const retryCanonicalHistory = this.convertToCanonicalMessages(
|
|
4977
|
+
const retryCanonicalHistory = this.convertToCanonicalMessages(this.chainedHistoryForApi(effectiveModel)); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = full history)
|
|
4946
4978
|
const req = this.gatewayTranslation.prepareRequest(retryCanonicalHistory, toolsToUse, effectiveModel, {
|
|
4947
4979
|
temperature: options.parameters?.temperature,
|
|
4948
4980
|
maxTokens: options.parameters?.maxTokens,
|
|
@@ -4991,6 +5023,7 @@ export class CortexOrchestrator {
|
|
|
4991
5023
|
...(retryConverted.usage && { usage: retryConverted.usage }),
|
|
4992
5024
|
};
|
|
4993
5025
|
this.messageHistory.push(retryAssistantMessage);
|
|
5026
|
+
this.markChainedResponseCheckpoint(effectiveModel); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = no-op)
|
|
4994
5027
|
await this.historyStore.appendMessage(this.currentSessionId, retryAssistantMessage);
|
|
4995
5028
|
currentAssistantCanonicalMessage = retryAssistantCanonical;
|
|
4996
5029
|
lastStopReason = retryConverted.stopReason; // R153
|
|
@@ -5068,28 +5101,28 @@ export class CortexOrchestrator {
|
|
|
5068
5101
|
await this.historyStore.appendMessage(this.currentSessionId, inactionUserMessage);
|
|
5069
5102
|
try {
|
|
5070
5103
|
await this.ensureHistoryFitsModel(effectiveModel);
|
|
5071
|
-
const
|
|
5072
|
-
const
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5104
|
+
const retryEffort = this.consumeReasoningBackoff() ?? options.parameters?.reasoningEffort; // R153 backoff > request param (consumed once)
|
|
5105
|
+
const buildRetryRequest = () => {
|
|
5106
|
+
const retryCanonicalHistory = this.convertToCanonicalMessages(this.chainedHistoryForApi(effectiveModel)); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = full history)
|
|
5107
|
+
const retryRequest = this.gatewayTranslation.prepareRequest(retryCanonicalHistory, toolsToUse, effectiveModel, {
|
|
5108
|
+
temperature: options.parameters?.temperature,
|
|
5109
|
+
maxTokens: options.parameters?.maxTokens,
|
|
5110
|
+
topP: options.parameters?.topP,
|
|
5111
|
+
reasoningEffort: retryEffort,
|
|
5112
|
+
stream: false,
|
|
5113
|
+
staticSystemPrompt: this.currentStaticSystemPrompt,
|
|
5114
|
+
conversationId: this.currentConversationId,
|
|
5115
|
+
});
|
|
5116
|
+
if (this.lastResponseId && effectiveModel.api.pattern === 'responses') {
|
|
5117
|
+
retryRequest.previousResponseId = this.lastResponseId;
|
|
5118
|
+
}
|
|
5119
|
+
retryRequest.conversationId = this.currentSessionId;
|
|
5120
|
+
return retryRequest;
|
|
5121
|
+
};
|
|
5122
|
+
const sendRetryRequest = async (r) => this.retryMiddleware
|
|
5123
|
+
? (await this.retryMiddleware.executeWithRetry(() => this.apiClient.sendRequest(r, effectiveModel), 'inaction_nudge_retry')).result
|
|
5124
|
+
: this.apiClient.sendRequest(r, effectiveModel);
|
|
5125
|
+
const retryApiResponse = await this.sendWithChainFallback(buildRetryRequest(), sendRetryRequest, buildRetryRequest, 'inaction_nudge_retry'); // R228 fallback (dark; off = one send)
|
|
5093
5126
|
const retryConverted = this.gatewayTranslation.convertResponse(retryApiResponse.data, effectiveModel, {
|
|
5094
5127
|
sessionId: this.currentSessionId,
|
|
5095
5128
|
conversationId: this.currentConversationId,
|
|
@@ -5122,6 +5155,7 @@ export class CortexOrchestrator {
|
|
|
5122
5155
|
...(retryConverted.usage && { usage: retryConverted.usage }),
|
|
5123
5156
|
};
|
|
5124
5157
|
this.messageHistory.push(retryAssistantMessage);
|
|
5158
|
+
this.markChainedResponseCheckpoint(effectiveModel); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = no-op)
|
|
5125
5159
|
await this.historyStore.appendMessage(this.currentSessionId, retryAssistantMessage);
|
|
5126
5160
|
currentAssistantCanonicalMessage = retryAssistantCanonical;
|
|
5127
5161
|
lastStopReason = retryConverted.stopReason; // R153
|
|
@@ -5428,6 +5462,7 @@ export class CortexOrchestrator {
|
|
|
5428
5462
|
const block = lastMsg.message.content[0];
|
|
5429
5463
|
const existing = typeof block.content === 'string' ? block.content : JSON.stringify(block.content);
|
|
5430
5464
|
block.content = existing + '\n\n' + signals;
|
|
5465
|
+
this.invalidateTailUnitConversions(); // R221 safety net
|
|
5431
5466
|
// Observability (backlog item 3): post-persist mutation — bank a
|
|
5432
5467
|
// steering_injected event (streaming parity).
|
|
5433
5468
|
const store = this.getDecisionStore();
|
|
@@ -5544,7 +5579,7 @@ export class CortexOrchestrator {
|
|
|
5544
5579
|
}
|
|
5545
5580
|
// Re-filter tools after SearchTools discovery (same as sendMessage path)
|
|
5546
5581
|
if (this.effectiveDeferredLoading && !isPTCEnabled) {
|
|
5547
|
-
toolsToUse = this.toolFilter.getFilteredTools(allTools);
|
|
5582
|
+
toolsToUse = this.toolFilter.getFilteredTools(allTools, { appendOnly: resolveAppendOnlyTools() });
|
|
5548
5583
|
// StructuredOutput: re-filter rebuilds from allTools — re-append the
|
|
5549
5584
|
// request-scoped tool (same as the sendMessage continuation path).
|
|
5550
5585
|
if (structuredOutputState) {
|
|
@@ -5935,7 +5970,7 @@ export class CortexOrchestrator {
|
|
|
5935
5970
|
await this.ensureHistoryFitsModel(effectiveModel);
|
|
5936
5971
|
const synthEffort = this.consumeReasoningBackoff() ?? options.parameters?.reasoningEffort; // R153 backoff > request param
|
|
5937
5972
|
const buildSynthRequest = () => {
|
|
5938
|
-
const synthCanonicalHistory = this.convertToCanonicalMessages(
|
|
5973
|
+
const synthCanonicalHistory = this.convertToCanonicalMessages(this.chainedHistoryForApi(effectiveModel)); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = full history)
|
|
5939
5974
|
const req = this.gatewayTranslation.prepareRequest(synthCanonicalHistory, [], // tools suppressed — must produce text
|
|
5940
5975
|
effectiveModel, {
|
|
5941
5976
|
temperature: options.parameters?.temperature,
|
|
@@ -5989,6 +6024,7 @@ export class CortexOrchestrator {
|
|
|
5989
6024
|
...(synthConverted.usage && { usage: synthConverted.usage }),
|
|
5990
6025
|
};
|
|
5991
6026
|
this.messageHistory.push(synthAssistantMessage);
|
|
6027
|
+
this.markChainedResponseCheckpoint(effectiveModel); // R228 (CORTEX_RESPONSES_SLICE_ALL; off = no-op)
|
|
5992
6028
|
await this.historyStore.appendMessage(this.currentSessionId, synthAssistantMessage);
|
|
5993
6029
|
this.sessionTimeline.recordMessage(synthAssistantMessage.uuid, 'assistant');
|
|
5994
6030
|
currentAssistantCanonicalMessage = synthCanonical;
|
|
@@ -6338,6 +6374,7 @@ export class CortexOrchestrator {
|
|
|
6338
6374
|
// cleared on session reset so stale entries (including synthetic-repair
|
|
6339
6375
|
// uuids from the previous session) can't leak into the new session.
|
|
6340
6376
|
this.canonicalConversionCache.clear();
|
|
6377
|
+
this.injectedApiContent.clear(); // R223
|
|
6341
6378
|
// Reset XAI Responses API chain for new session (was leaking across `--new`).
|
|
6342
6379
|
// Without this, a new session would reuse lastResponseId from the previous
|
|
6343
6380
|
// session, sending previous_response_id that the server doesn't recognize
|
|
@@ -6467,6 +6504,7 @@ export class CortexOrchestrator {
|
|
|
6467
6504
|
// Round 6: clear canonical-conversion cache on session resume too —
|
|
6468
6505
|
// entries from a previously running orchestrator instance are stale.
|
|
6469
6506
|
this.canonicalConversionCache.clear();
|
|
6507
|
+
this.injectedApiContent.clear(); // R223
|
|
6470
6508
|
// Reuse the persistedMetadata loaded above — avoid a second disk read.
|
|
6471
6509
|
const savedMetadata = persistedMetadata;
|
|
6472
6510
|
if (savedMetadata?.cacheMetrics) {
|
|
@@ -6937,6 +6975,7 @@ export class CortexOrchestrator {
|
|
|
6937
6975
|
plateau: plateauStatusSegment(this.plateauTracker), // R210: null when CORTEX_PLATEAU_STOP is off or no metric seen → line unchanged
|
|
6938
6976
|
});
|
|
6939
6977
|
if (appendStatusToNewestToolResult(this.messageHistory, line)) {
|
|
6978
|
+
this.invalidateTailUnitConversions(); // R221 safety net
|
|
6940
6979
|
this.turnStatusLines++;
|
|
6941
6980
|
if (this.config.debug)
|
|
6942
6981
|
console.log(`[TurnStatus] iteration ${iteration}: ${line}`);
|
|
@@ -9388,7 +9427,17 @@ export class CortexOrchestrator {
|
|
|
9388
9427
|
try {
|
|
9389
9428
|
if (!isReasoningExhaustion(cls) || !resolveWallDrop())
|
|
9390
9429
|
return { dropped: false };
|
|
9430
|
+
// R228 (CORTEX_RESPONSES_SLICE_ALL): on a chained Responses session the server already HOLDS the walled turn (previous_response_id
|
|
9431
|
+
// = its id) — a local drop cannot remove it, and the nudge on an already-held tool_result would never be sent (sliced away). Keep
|
|
9432
|
+
// the turn locally so the caller pushes the nudge as a new input item.
|
|
9433
|
+
const tail = this.messageHistory[this.messageHistory.length - 1];
|
|
9434
|
+
if (resolveResponsesSliceAll() && this.lastResponseId && tail?.model?.apiPattern === 'responses')
|
|
9435
|
+
return { dropped: false };
|
|
9391
9436
|
const r = dropWalledTurn(this.messageHistory, nudge);
|
|
9437
|
+
// R221 (CORTEX_WALL_CACHE_FIX): the carrier tool_result was converted (and cached by uuid) while the walled turn was the tail —
|
|
9438
|
+
// drop that stale copy so every later request carries the nudge (+ wall summary), not just the retry.
|
|
9439
|
+
if (r.dropped && r.carrierMessage)
|
|
9440
|
+
this.invalidateConversions([r.carrierMessage]);
|
|
9392
9441
|
const store = this.getDecisionStore();
|
|
9393
9442
|
if (r.dropped && store)
|
|
9394
9443
|
void store.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'wall_drop', detail: { iteration, droppedChars: r.droppedChars, carrier: r.carrier, streaming } }).catch(() => { });
|
|
@@ -9413,6 +9462,7 @@ export class CortexOrchestrator {
|
|
|
9413
9462
|
return;
|
|
9414
9463
|
if (!appendStatusToNewestToolResult(this.messageHistory, buildComputeNudgeLine(reasoningTokens)))
|
|
9415
9464
|
return;
|
|
9465
|
+
this.invalidateTailUnitConversions(); // R221 safety net
|
|
9416
9466
|
this.computeNudgeLastRound = round;
|
|
9417
9467
|
this.computeNudgeFired++;
|
|
9418
9468
|
const store = this.getDecisionStore();
|
|
@@ -9454,7 +9504,7 @@ export class CortexOrchestrator {
|
|
|
9454
9504
|
? (await this.retryMiddleware.executeWithRetry(() => this.apiClient.sendRequest(req, model), label)).result
|
|
9455
9505
|
: this.apiClient.sendRequest(req, model);
|
|
9456
9506
|
try {
|
|
9457
|
-
return await send(build())
|
|
9507
|
+
return await this.sendWithChainFallback(build(), send, build, label); // R228 fallback (dark; off = send(build()))
|
|
9458
9508
|
}
|
|
9459
9509
|
catch (err) {
|
|
9460
9510
|
if (!isImageRejectionError(err))
|
|
@@ -9463,6 +9513,7 @@ export class CortexOrchestrator {
|
|
|
9463
9513
|
const stripped = stripRejectedImages(this.messageHistory, reason);
|
|
9464
9514
|
if (stripped === 0)
|
|
9465
9515
|
throw err;
|
|
9516
|
+
this.invalidateConversions(this.messageHistory); // R221 safety net: stubbed image blocks live in already-converted messages
|
|
9466
9517
|
console.warn(`[Orchestrator] R154: provider rejected an image block on ${label} — stubbed ${stripped} image block(s) in history and retrying once.`);
|
|
9467
9518
|
const store = this.getDecisionStore();
|
|
9468
9519
|
if (store)
|
|
@@ -9970,6 +10021,11 @@ export class CortexOrchestrator {
|
|
|
9970
10021
|
* so this cleanup just removes them from the in-memory array.
|
|
9971
10022
|
*/
|
|
9972
10023
|
cleanupEphemeralMessages() {
|
|
10024
|
+
// R227 (CORTEX_KEEP_MENTOR_MESSAGES=on, dark): keep them — removing a mid-history message rewrites every later request's prefix and
|
|
10025
|
+
// shifts the Responses slice checkpoint (messageCountAtLastResponse counts them). Kept, the history stays append-only and the
|
|
10026
|
+
// checkpoint stays exact. Display already strips their system-reminder (sanitizeHistoryForDisplay); they were never persisted.
|
|
10027
|
+
if (resolveKeepMentorMessages())
|
|
10028
|
+
return;
|
|
9973
10029
|
const beforeCount = this.messageHistory.length;
|
|
9974
10030
|
this.messageHistory = this.messageHistory.filter((msg) => !msg.metadata?.ephemeral);
|
|
9975
10031
|
const removedCount = beforeCount - this.messageHistory.length;
|
|
@@ -10362,7 +10418,78 @@ export class CortexOrchestrator {
|
|
|
10362
10418
|
* Also validates and repairs the message history to handle crash recovery scenarios
|
|
10363
10419
|
* where tool_use blocks might be orphaned without matching tool_results.
|
|
10364
10420
|
*/
|
|
10365
|
-
|
|
10421
|
+
/** R223 (CORTEX_PERSIST_INJECTED, dark): uuid → the injected user content the first request of that turn sent. The message in
|
|
10422
|
+
* messageHistory keeps the RAW content (storage, display, title, judges and every text reader see the raw text); only the API
|
|
10423
|
+
* conversion swaps the injected content in, so every request of the session carries the same bytes for that message. */
|
|
10424
|
+
injectedApiContent = new Map();
|
|
10425
|
+
rememberInjectedContent(uuid, injected) {
|
|
10426
|
+
if (resolvePersistInjected())
|
|
10427
|
+
this.injectedApiContent.set(uuid, injected);
|
|
10428
|
+
}
|
|
10429
|
+
/** The record convertSingleMessage sees for the API (R223 swap; identity when off / not injected). */
|
|
10430
|
+
apiViewOf(msg) {
|
|
10431
|
+
if (this.injectedApiContent.size === 0 || !msg?.uuid)
|
|
10432
|
+
return msg;
|
|
10433
|
+
const injected = this.injectedApiContent.get(msg.uuid);
|
|
10434
|
+
if (injected === undefined)
|
|
10435
|
+
return msg;
|
|
10436
|
+
return { ...msg, message: { ...msg.message, content: injected } };
|
|
10437
|
+
}
|
|
10438
|
+
/** R221 general safety net (CORTEX_WALL_CACHE_FIX=on, dark; off = no-op): drop the cached canonical conversion of
|
|
10439
|
+
* messages mutated in place, so the next request converts them fresh instead of re-sending a stale copy. */
|
|
10440
|
+
invalidateConversions(msgs) {
|
|
10441
|
+
if (!resolveWallCacheFix())
|
|
10442
|
+
return;
|
|
10443
|
+
for (const m of msgs)
|
|
10444
|
+
if (m?.uuid)
|
|
10445
|
+
this.canonicalConversionCache.delete(m.uuid);
|
|
10446
|
+
}
|
|
10447
|
+
/** R221 safety net for the steering carriers (all of them write into the messages after the newest assistant turn). */
|
|
10448
|
+
invalidateTailUnitConversions() {
|
|
10449
|
+
if (!resolveWallCacheFix())
|
|
10450
|
+
return;
|
|
10451
|
+
this.invalidateConversions(tailUnitAfterLastAssistant(this.messageHistory));
|
|
10452
|
+
}
|
|
10453
|
+
/** R228 (CORTEX_RESPONSES_SLICE_ALL, dark): history for a request that chains previous_response_id — only the items added since the
|
|
10454
|
+
* held response. Off / not Responses / no chain / no checkpoint → the full history (the pre-existing behaviour). */
|
|
10455
|
+
chainedHistoryForApi(model) {
|
|
10456
|
+
const h = [...this.messageHistory];
|
|
10457
|
+
if (!resolveResponsesSliceAll() || !this.lastResponseId || model.api.pattern !== 'responses')
|
|
10458
|
+
return h;
|
|
10459
|
+
const from = chainedSliceStart(this.messageCountAtLastResponse, h.length);
|
|
10460
|
+
return from > 0 ? h.slice(from) : h;
|
|
10461
|
+
}
|
|
10462
|
+
/** R228 (CORTEX_RESPONSES_SLICE_ALL) fallback: when the held response is gone (store off / expired / error naming it), drop the chain
|
|
10463
|
+
* and resend ONCE with the FULL history and NO previous_response_id — never both. `rebuildFull` is called AFTER the chain reset, so
|
|
10464
|
+
* every builder that reads this.lastResponseId / chainedHistoryForApi produces the unchained full-history request. Off, unchained, or
|
|
10465
|
+
* any other error → rethrown untouched (byte-identical). */
|
|
10466
|
+
async sendWithChainFallback(req, send, rebuildFull, label) {
|
|
10467
|
+
try {
|
|
10468
|
+
return await send(req);
|
|
10469
|
+
}
|
|
10470
|
+
catch (err) {
|
|
10471
|
+
if (!req.previousResponseId || !resolveResponsesSliceAll() || !isPreviousResponseUnavailable(err))
|
|
10472
|
+
throw err;
|
|
10473
|
+
const lost = req.previousResponseId;
|
|
10474
|
+
this.lastResponseId = null;
|
|
10475
|
+
this.lastResponseIdProvider = null;
|
|
10476
|
+
this.messageCountAtLastResponse = 0;
|
|
10477
|
+
const full = rebuildFull();
|
|
10478
|
+
delete full.previousResponseId; // never both: full history XOR a chain id
|
|
10479
|
+
console.warn(`[Orchestrator] R228: previous response ${lost} unavailable on ${label} — chain dropped, resending the full history once.`);
|
|
10480
|
+
const store = this.getDecisionStore();
|
|
10481
|
+
if (store)
|
|
10482
|
+
void store.recordEvent({ sessionId: this.currentSessionId ?? 'unknown', kind: 'responses_chain_fallback', detail: { label, reason: String(err?.message ?? err).slice(0, 160) } }).catch(() => { });
|
|
10483
|
+
return await send(full);
|
|
10484
|
+
}
|
|
10485
|
+
}
|
|
10486
|
+
/** R228: a chained non-continuation response (gate / retries / synthesis) was pushed — the server now holds everything up to here. */
|
|
10487
|
+
markChainedResponseCheckpoint(model) {
|
|
10488
|
+
if (resolveResponsesSliceAll() && model.api.pattern === 'responses')
|
|
10489
|
+
this.messageCountAtLastResponse = this.messageHistory.length;
|
|
10490
|
+
}
|
|
10491
|
+
convertToCanonicalMessages(rawMessages) {
|
|
10492
|
+
const messages = this.injectedApiContent.size > 0 ? rawMessages.map((m) => this.apiViewOf(m)) : rawMessages;
|
|
10366
10493
|
const tailIdx = messages.length - 1;
|
|
10367
10494
|
const converted = messages.map((msg, i) => {
|
|
10368
10495
|
// Tail is recomputed every call (see cache doc-comment above).
|