@nexus-cortex/core 4.124.43 → 4.124.45

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 (72) hide show
  1. package/.env.defaults +184 -0
  2. package/dist/adapters/GatewayTranslationLayer.d.ts.map +1 -1
  3. package/dist/adapters/GatewayTranslationLayer.js +14 -1
  4. package/dist/adapters/GatewayTranslationLayer.js.map +1 -1
  5. package/dist/adapters/ServerSideToolDetection.d.ts.map +1 -1
  6. package/dist/adapters/ServerSideToolDetection.js +5 -1
  7. package/dist/adapters/ServerSideToolDetection.js.map +1 -1
  8. package/dist/config/SettingsLoader.d.ts +3 -1
  9. package/dist/config/SettingsLoader.d.ts.map +1 -1
  10. package/dist/config/SettingsLoader.js +18 -4
  11. package/dist/config/SettingsLoader.js.map +1 -1
  12. package/dist/config/SettingsSchema.d.ts +1 -0
  13. package/dist/config/SettingsSchema.d.ts.map +1 -1
  14. package/dist/config/SettingsSchema.js +9 -0
  15. package/dist/config/SettingsSchema.js.map +1 -1
  16. package/dist/config/effectiveConfig.d.ts +1 -1
  17. package/dist/config/effectiveConfig.d.ts.map +1 -1
  18. package/dist/config/effectiveConfig.js +21 -1
  19. package/dist/config/effectiveConfig.js.map +1 -1
  20. package/dist/config/interactiveProfile.d.ts +86 -0
  21. package/dist/config/interactiveProfile.d.ts.map +1 -0
  22. package/dist/config/interactiveProfile.js +114 -0
  23. package/dist/config/interactiveProfile.js.map +1 -0
  24. package/dist/middleware/HelperModelMiddleware.d.ts +10 -0
  25. package/dist/middleware/HelperModelMiddleware.d.ts.map +1 -1
  26. package/dist/middleware/HelperModelMiddleware.js +48 -5
  27. package/dist/middleware/HelperModelMiddleware.js.map +1 -1
  28. package/dist/middleware/SystemMessageMiddleware.d.ts.map +1 -1
  29. package/dist/middleware/SystemMessageMiddleware.js +4 -2
  30. package/dist/middleware/SystemMessageMiddleware.js.map +1 -1
  31. package/dist/middleware/helpers/helperProviderMatch.d.ts +40 -0
  32. package/dist/middleware/helpers/helperProviderMatch.d.ts.map +1 -0
  33. package/dist/middleware/helpers/helperProviderMatch.js +50 -0
  34. package/dist/middleware/helpers/helperProviderMatch.js.map +1 -0
  35. package/dist/orchestrator/APIClient.d.ts.map +1 -1
  36. package/dist/orchestrator/APIClient.js +92 -13
  37. package/dist/orchestrator/APIClient.js.map +1 -1
  38. package/dist/orchestrator/CortexOrchestrator.d.ts +22 -0
  39. package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
  40. package/dist/orchestrator/CortexOrchestrator.js +211 -82
  41. package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
  42. package/dist/orchestrator/OrchestratorFactory.d.ts.map +1 -1
  43. package/dist/orchestrator/OrchestratorFactory.js +10 -0
  44. package/dist/orchestrator/OrchestratorFactory.js.map +1 -1
  45. package/dist/orchestrator/appendOnlyHistory.d.ts +39 -0
  46. package/dist/orchestrator/appendOnlyHistory.d.ts.map +1 -0
  47. package/dist/orchestrator/appendOnlyHistory.js +75 -0
  48. package/dist/orchestrator/appendOnlyHistory.js.map +1 -0
  49. package/dist/orchestrator/transportCacheFixes.d.ts +22 -0
  50. package/dist/orchestrator/transportCacheFixes.d.ts.map +1 -0
  51. package/dist/orchestrator/transportCacheFixes.js +114 -0
  52. package/dist/orchestrator/transportCacheFixes.js.map +1 -0
  53. package/dist/orchestrator/transportFixes.d.ts +55 -0
  54. package/dist/orchestrator/transportFixes.d.ts.map +1 -0
  55. package/dist/orchestrator/transportFixes.js +182 -0
  56. package/dist/orchestrator/transportFixes.js.map +1 -0
  57. package/dist/orchestrator/wallGuard.d.ts +3 -1
  58. package/dist/orchestrator/wallGuard.d.ts.map +1 -1
  59. package/dist/orchestrator/wallGuard.js +15 -2
  60. package/dist/orchestrator/wallGuard.js.map +1 -1
  61. package/dist/system-messages/promptPresets.d.ts +29 -1
  62. package/dist/system-messages/promptPresets.d.ts.map +1 -1
  63. package/dist/system-messages/promptPresets.js +44 -2
  64. package/dist/system-messages/promptPresets.js.map +1 -1
  65. package/dist/tools/ClientSideToolFilter.d.ts +9 -2
  66. package/dist/tools/ClientSideToolFilter.d.ts.map +1 -1
  67. package/dist/tools/ClientSideToolFilter.js +26 -3
  68. package/dist/tools/ClientSideToolFilter.js.map +1 -1
  69. package/dist/training/DecisionStore.d.ts +1 -1
  70. package/dist/training/DecisionStore.d.ts.map +1 -1
  71. package/dist/training/DecisionStore.js.map +1 -1
  72. package/package.json +3 -3
@@ -19,6 +19,8 @@ import { GoogleGenAI } from '@google/genai';
19
19
  import { v4 as uuidv4 } from 'uuid';
20
20
  import { assertCompletionBody } from './completionBodyGuard.js';
21
21
  import { parseHFCompletion, normalizeToolCallArguments } from '../models/hfSpace/normalize.js';
22
+ import { isResponsesInlineRemindersEnabled, inlineRemindersForResponses, isResponsesStopReasonEnabled, isAnthropicHistoryCacheEnabled, applyAnthropicHistoryCache, countAnthropicBreakpoints, } from './transportFixes.js';
23
+ import { isGeminiSystemFixEnabled, isOpenAICacheKeyEnabled, isStreamUsageEnabled, applyAnthropicCacheLevers, streamFinalUsage, } from './transportCacheFixes.js';
22
24
  import { anthropicCredentialService, CredentialError } from '../config/AnthropicCredentialService.js';
23
25
  /**
24
26
  * Anthropic families on the adaptive-thinking-only request surface — sending
@@ -353,6 +355,15 @@ export class APIClient {
353
355
  }
354
356
  this.applyToolChoice(anthropicRequest, request, 'messages'); // §13-B1 forced tool_choice
355
357
  }
358
+ // R218 (DARK, CORTEX_ANTHROPIC_HISTORY_CACHE=on): rolling message-level breakpoints so the conversation
359
+ // history is cached, within the 4-breakpoint cap (system + last tool counted). Anthropic only.
360
+ if (enableCaching && isAnthropicHistoryCacheEnabled()) {
361
+ anthropicRequest.messages = applyAnthropicHistoryCache(anthropicRequest.messages, countAnthropicBreakpoints({ system: anthropicRequest.system, tools: anthropicRequest.tools })).messages;
362
+ }
363
+ // R225 (DARK): CORTEX_ANTHROPIC_AUTO_CACHE top-level automatic cache_control (free slot only) +
364
+ // CORTEX_ANTHROPIC_CACHE_TTL=1h on every marker. Anthropic only; no-op with both flags off.
365
+ if (enableCaching)
366
+ applyAnthropicCacheLevers(anthropicRequest);
356
367
  // Phase 2.8: Enable extended thinking for Claude 4+ models with reasoning support
357
368
  // Requires beta header: anthropic-beta: interleaved-thinking-2025-05-14
358
369
  // Skip if disableThinking option is set (used for continuation requests)
@@ -778,6 +789,16 @@ export class APIClient {
778
789
  chatRequest.tools = request.tools;
779
790
  this.applyToolChoice(chatRequest, request, 'chat/completions'); // §13-B1 forced tool_choice
780
791
  }
792
+ // R225 (DARK, CORTEX_OPENAI_CACHE_KEY): OpenAI routes same-key requests to the same prompt cache.
793
+ // OpenAI provider only (other chat/completions providers may reject the unknown field).
794
+ if (isOpenAICacheKeyEnabled() && modelConfig.provider === 'openai' && request.conversationId) {
795
+ chatRequest.prompt_cache_key = request.conversationId;
796
+ }
797
+ // R224a (DARK, CORTEX_STREAM_USAGE): ask for the final usage chunk on streaming requests (otherwise the
798
+ // reassembled message reports zeros). Body-level, after the prefix — cache-neutral.
799
+ if (opts.stream && isStreamUsageEnabled()) {
800
+ chatRequest.stream_options = { include_usage: true };
801
+ }
781
802
  this.logChatCompletionsPayload(chatRequest, request.modelId, opts.stream);
782
803
  return { client, chatRequest };
783
804
  }
@@ -982,7 +1003,12 @@ export class APIClient {
982
1003
  //
983
1004
  // Extract <system-reminder> content from user messages into `instructions` parameter.
984
1005
  // This lets the Responses API cache system context separately from conversation content.
985
- const { instructions, cleanedItems: inputItems } = this.extractSystemRemindersForResponsesAPI(request.messages);
1006
+ // R215 (DARK, CORTEX_RESPONSES_INLINE_REMINDERS=on): keep reminders IN PLACE as user input_text items
1007
+ // (xAI never receives `instructions`; OpenAI lost their position after the tool output). R63 system
1008
+ // delivery below is unchanged — `instructions` then carries only the static system prompt.
1009
+ const { instructions, cleanedItems: inputItems } = isResponsesInlineRemindersEnabled()
1010
+ ? { instructions: undefined, cleanedItems: inlineRemindersForResponses(request.messages) }
1011
+ : this.extractSystemRemindersForResponsesAPI(request.messages);
986
1012
  // Check reasoning support
987
1013
  const supportsReasoning = modelConfig.reasoning?.supported;
988
1014
  const { disableThinking, reasoningEffort, ...apiParameters } = request.parameters;
@@ -1043,6 +1069,10 @@ export class APIClient {
1043
1069
  // opt-in ZDR mode: "DESIGN NOTE — stateless ZDR mode" in
1044
1070
  // ResponsesAPIAdapter.ts (adapters/).
1045
1071
  }
1072
+ // R225 (DARK, CORTEX_OPENAI_CACHE_KEY): the same session-scoped cache routing key for OpenAI Responses.
1073
+ if (isOpenAICacheKeyEnabled() && modelConfig.provider?.toLowerCase() === 'openai' && request.conversationId) {
1074
+ responsesRequest.prompt_cache_key = request.conversationId;
1075
+ }
1046
1076
  // Set system context as instructions (enables provider-side caching).
1047
1077
  // R63: request.systemMessage (the R28 static system prompt) was previously
1048
1078
  // dropped on this path — only <system-reminder> text mined from user
@@ -1154,6 +1184,12 @@ export class APIClient {
1154
1184
  if (request.tools && request.tools.length > 0) {
1155
1185
  return this.sendGenerateContentHTTP(request, modelConfig, apiKey);
1156
1186
  }
1187
+ // R229 (DARK, CORTEX_GEMINI_SYSTEM_FIX): the @google/generative-ai SDK (v0.2.1, v1 endpoint) has no
1188
+ // systemInstruction support, so a request carrying a system prompt goes through the v1beta REST builder,
1189
+ // which sends it as system_instruction.
1190
+ if (isGeminiSystemFixEnabled() && request.systemMessage) {
1191
+ return this.sendGenerateContentHTTP(request, modelConfig, apiKey);
1192
+ }
1157
1193
  // For non-tool requests, use SDK as before
1158
1194
  if (!this.googleClient) {
1159
1195
  this.googleClient = new GoogleGenerativeAI(apiKey);
@@ -1201,6 +1237,11 @@ export class APIClient {
1201
1237
  contents: request.messages,
1202
1238
  generation_config: generationConfig // Use the nested object directly
1203
1239
  };
1240
+ // R229 (DARK, CORTEX_GEMINI_SYSTEM_FIX): deliver the system prompt (the streaming HTTP builder always did;
1241
+ // this non-streaming builder never did). Same snake_case shape as streamGenerateContentHTTP.
1242
+ if (isGeminiSystemFixEnabled() && request.systemMessage) {
1243
+ requestBody.system_instruction = { parts: [{ text: request.systemMessage }] };
1244
+ }
1204
1245
  // Add tools if present
1205
1246
  if (request.tools && request.tools.length > 0) {
1206
1247
  // REST API uses snake_case "function_declarations", not camelCase "functionDeclarations"
@@ -1338,6 +1379,13 @@ export class APIClient {
1338
1379
  }
1339
1380
  this.applyToolChoice(anthropicRequest, request, 'messages'); // §13-B1 forced tool_choice
1340
1381
  }
1382
+ // R218 (DARK): rolling message-level cache breakpoints — mirrors sendAnthropicMessagesAPI.
1383
+ if (enableCaching && isAnthropicHistoryCacheEnabled()) {
1384
+ anthropicRequest.messages = applyAnthropicHistoryCache(anthropicRequest.messages, countAnthropicBreakpoints({ system: anthropicRequest.system, tools: anthropicRequest.tools })).messages;
1385
+ }
1386
+ // R225 (DARK): automatic cache_control + 1h TTL — mirrors sendAnthropicMessagesAPI.
1387
+ if (enableCaching)
1388
+ applyAnthropicCacheLevers(anthropicRequest);
1341
1389
  // Phase 2.8: Enable extended thinking for Claude 4+ models with reasoning support
1342
1390
  // Requires beta header: anthropic-beta: interleaved-thinking-2025-05-14
1343
1391
  // Skip if disableThinking option is set (used for continuation requests)
@@ -1966,6 +2014,9 @@ export class APIClient {
1966
2014
  // R153 (2026-09-16): keep the provider's LAST non-null finish_reason so a `length` cutoff survives reassembly
1967
2015
  // (the empty-response classifier keys `truncated` on it; the old hardcode reported every text turn as `stop`).
1968
2016
  let lastFinishReason = null;
2017
+ // R224a (DARK, CORTEX_STREAM_USAGE): the provider's final usage chunk (choices: []) when requested.
2018
+ const captureStreamUsage = isStreamUsageEnabled();
2019
+ let streamUsage = null;
1969
2020
  // Capture this context before entering generator
1970
2021
  const self = this;
1971
2022
  // Create async generator that both yields chunks AND accumulates final message
@@ -1979,7 +2030,9 @@ export class APIClient {
1979
2030
  if (!firstChunk)
1980
2031
  firstChunk = chunk;
1981
2032
  chunkCount++;
1982
- const delta = chunk.choices[0]?.delta;
2033
+ if (captureStreamUsage && chunk?.usage)
2034
+ streamUsage = chunk.usage;
2035
+ const delta = chunk.choices?.[0]?.delta;
1983
2036
  // Debug: Log first few chunks to see what fields are present
1984
2037
  if ((process.env.DEBUG === 'true' || process.env.DEBUG_THINKING === 'true') && chunkCount <= 3) {
1985
2038
  console.log(`[DEBUG APIClient] Chunk ${chunkCount} delta keys:`, delta ? Object.keys(delta) : 'null');
@@ -2030,7 +2083,7 @@ export class APIClient {
2030
2083
  }
2031
2084
  }
2032
2085
  // Check if finish_reason indicates tool_calls completion (or length-truncated tool call)
2033
- const finishReason = chunk.choices[0]?.finish_reason;
2086
+ const finishReason = chunk.choices?.[0]?.finish_reason;
2034
2087
  if (finishReason)
2035
2088
  lastFinishReason = String(finishReason);
2036
2089
  if ((finishReason === 'tool_calls' || finishReason === 'length') && accumulatedToolCalls.size > 0) {
@@ -2096,11 +2149,7 @@ export class APIClient {
2096
2149
  // ('length' = output cap hit) instead of a synthetic 'stop'.
2097
2150
  finish_reason: finalToolCalls.length > 0 ? 'tool_calls' : (lastFinishReason ?? 'stop')
2098
2151
  }],
2099
- usage: {
2100
- prompt_tokens: 0,
2101
- completion_tokens: 0,
2102
- total_tokens: 0
2103
- }
2152
+ usage: streamFinalUsage(streamUsage)
2104
2153
  });
2105
2154
  }();
2106
2155
  return {
@@ -2125,7 +2174,10 @@ export class APIClient {
2125
2174
  // Re-wrapping them would strip tool results and function calls, breaking the tool loop.
2126
2175
  //
2127
2176
  // Extract <system-reminder> content from user messages into `instructions` parameter.
2128
- const { instructions, cleanedItems: inputItems } = this.extractSystemRemindersForResponsesAPI(request.messages);
2177
+ // R215 (DARK): CORTEX_RESPONSES_INLINE_REMINDERS=on keeps them in place (mirrors sendResponsesAPI).
2178
+ const { instructions, cleanedItems: inputItems } = isResponsesInlineRemindersEnabled()
2179
+ ? { instructions: undefined, cleanedItems: inlineRemindersForResponses(request.messages) }
2180
+ : this.extractSystemRemindersForResponsesAPI(request.messages);
2129
2181
  // Accumulate content from stream
2130
2182
  let fullContent = '';
2131
2183
  let fullReasoningContent = '';
@@ -2197,6 +2249,10 @@ export class APIClient {
2197
2249
  responsesRequest.prompt_cache_key = request.conversationId;
2198
2250
  }
2199
2251
  }
2252
+ // R225 (DARK, CORTEX_OPENAI_CACHE_KEY): mirrors sendResponsesAPI.
2253
+ if (isOpenAICacheKeyEnabled() && modelConfig.provider?.toLowerCase() === 'openai' && request.conversationId) {
2254
+ responsesRequest.prompt_cache_key = request.conversationId;
2255
+ }
2200
2256
  // Set system context as instructions (enables provider-side caching).
2201
2257
  // R63: merge the R28 static system prompt (previously dropped on this
2202
2258
  // path) ahead of reminders mined from user messages; XAI gets it as a
@@ -2427,7 +2483,12 @@ export class APIClient {
2427
2483
  prompt_tokens: 0,
2428
2484
  completion_tokens: 0,
2429
2485
  total_tokens: 0
2430
- }
2486
+ },
2487
+ // R216 (DARK, CORTEX_RESPONSES_STOP_REASON=on): carry the terminal event's status +
2488
+ // incomplete_details (response.completed / response.incomplete) so extractStopReason sees truncation.
2489
+ ...(isResponsesStopReasonEnabled() && typeof finalResponse?.status === 'string'
2490
+ ? { status: finalResponse.status, incomplete_details: finalResponse.incomplete_details ?? null }
2491
+ : {})
2431
2492
  });
2432
2493
  }();
2433
2494
  return {
@@ -2452,6 +2513,11 @@ export class APIClient {
2452
2513
  if (request.tools && request.tools.length > 0) {
2453
2514
  return this.streamGenerateContentHTTP(request, modelConfig, apiKey);
2454
2515
  }
2516
+ // R229 (DARK, CORTEX_GEMINI_SYSTEM_FIX): the old SDK cannot send a system prompt — use the v1beta REST
2517
+ // streaming builder (already sends system_instruction) whenever one is present.
2518
+ if (isGeminiSystemFixEnabled() && request.systemMessage) {
2519
+ return this.streamGenerateContentHTTP(request, modelConfig, apiKey);
2520
+ }
2455
2521
  // For non-tool requests, use SDK streaming
2456
2522
  if (!this.googleClient) {
2457
2523
  this.googleClient = new GoogleGenerativeAI(apiKey);
@@ -2820,7 +2886,14 @@ export class APIClient {
2820
2886
  config
2821
2887
  };
2822
2888
  if (request.systemMessage) {
2823
- sdkRequest.systemInstruction = request.systemMessage;
2889
+ if (isGeminiSystemFixEnabled()) {
2890
+ // R229 (DARK): @google/genai reads the system prompt ONLY from config.systemInstruction
2891
+ // (GenerateContentParameters = {model, contents, config}); a top-level field is dropped.
2892
+ config.systemInstruction = request.systemMessage;
2893
+ }
2894
+ else {
2895
+ sdkRequest.systemInstruction = request.systemMessage;
2896
+ }
2824
2897
  }
2825
2898
  if (process.env.DEBUG === 'true') {
2826
2899
  console.log(`[DEBUG APIClient SDK] Non-streaming request for model: ${modelId}`);
@@ -2917,9 +2990,15 @@ export class APIClient {
2917
2990
  contents: request.messages,
2918
2991
  config // Config contains both generation params and tools
2919
2992
  };
2920
- // Add system instruction if present (top level, not in config)
2993
+ // Add system instruction if present. Legacy: top level (the SDK DROPS it — GenerateContentParameters =
2994
+ // {model, contents, config}). R229 (DARK, CORTEX_GEMINI_SYSTEM_FIX): config.systemInstruction.
2921
2995
  if (request.systemMessage) {
2922
- sdkRequest.systemInstruction = request.systemMessage;
2996
+ if (isGeminiSystemFixEnabled()) {
2997
+ config.systemInstruction = request.systemMessage;
2998
+ }
2999
+ else {
3000
+ sdkRequest.systemInstruction = request.systemMessage;
3001
+ }
2923
3002
  }
2924
3003
  if (process.env.DEBUG === 'true') {
2925
3004
  console.log(`[DEBUG APIClient SDK] Using model: ${modelId}`);