@nexus-cortex/core 4.124.44 → 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 (37) hide show
  1. package/.env.defaults +103 -0
  2. package/dist/adapters/GatewayTranslationLayer.d.ts.map +1 -1
  3. package/dist/adapters/GatewayTranslationLayer.js +4 -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/effectiveConfig.d.ts.map +1 -1
  9. package/dist/config/effectiveConfig.js +12 -0
  10. package/dist/config/effectiveConfig.js.map +1 -1
  11. package/dist/orchestrator/APIClient.d.ts.map +1 -1
  12. package/dist/orchestrator/APIClient.js +66 -10
  13. package/dist/orchestrator/APIClient.js.map +1 -1
  14. package/dist/orchestrator/CortexOrchestrator.d.ts +22 -0
  15. package/dist/orchestrator/CortexOrchestrator.d.ts.map +1 -1
  16. package/dist/orchestrator/CortexOrchestrator.js +207 -81
  17. package/dist/orchestrator/CortexOrchestrator.js.map +1 -1
  18. package/dist/orchestrator/appendOnlyHistory.d.ts +39 -0
  19. package/dist/orchestrator/appendOnlyHistory.d.ts.map +1 -0
  20. package/dist/orchestrator/appendOnlyHistory.js +75 -0
  21. package/dist/orchestrator/appendOnlyHistory.js.map +1 -0
  22. package/dist/orchestrator/transportCacheFixes.d.ts +22 -0
  23. package/dist/orchestrator/transportCacheFixes.d.ts.map +1 -0
  24. package/dist/orchestrator/transportCacheFixes.js +114 -0
  25. package/dist/orchestrator/transportCacheFixes.js.map +1 -0
  26. package/dist/orchestrator/wallGuard.d.ts +3 -1
  27. package/dist/orchestrator/wallGuard.d.ts.map +1 -1
  28. package/dist/orchestrator/wallGuard.js +15 -2
  29. package/dist/orchestrator/wallGuard.js.map +1 -1
  30. package/dist/tools/ClientSideToolFilter.d.ts +9 -2
  31. package/dist/tools/ClientSideToolFilter.d.ts.map +1 -1
  32. package/dist/tools/ClientSideToolFilter.js +26 -3
  33. package/dist/tools/ClientSideToolFilter.js.map +1 -1
  34. package/dist/training/DecisionStore.d.ts +1 -1
  35. package/dist/training/DecisionStore.d.ts.map +1 -1
  36. package/dist/training/DecisionStore.js.map +1 -1
  37. package/package.json +3 -3
@@ -20,6 +20,7 @@ import { v4 as uuidv4 } from 'uuid';
20
20
  import { assertCompletionBody } from './completionBodyGuard.js';
21
21
  import { parseHFCompletion, normalizeToolCallArguments } from '../models/hfSpace/normalize.js';
22
22
  import { isResponsesInlineRemindersEnabled, inlineRemindersForResponses, isResponsesStopReasonEnabled, isAnthropicHistoryCacheEnabled, applyAnthropicHistoryCache, countAnthropicBreakpoints, } from './transportFixes.js';
23
+ import { isGeminiSystemFixEnabled, isOpenAICacheKeyEnabled, isStreamUsageEnabled, applyAnthropicCacheLevers, streamFinalUsage, } from './transportCacheFixes.js';
23
24
  import { anthropicCredentialService, CredentialError } from '../config/AnthropicCredentialService.js';
24
25
  /**
25
26
  * Anthropic families on the adaptive-thinking-only request surface — sending
@@ -359,6 +360,10 @@ export class APIClient {
359
360
  if (enableCaching && isAnthropicHistoryCacheEnabled()) {
360
361
  anthropicRequest.messages = applyAnthropicHistoryCache(anthropicRequest.messages, countAnthropicBreakpoints({ system: anthropicRequest.system, tools: anthropicRequest.tools })).messages;
361
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);
362
367
  // Phase 2.8: Enable extended thinking for Claude 4+ models with reasoning support
363
368
  // Requires beta header: anthropic-beta: interleaved-thinking-2025-05-14
364
369
  // Skip if disableThinking option is set (used for continuation requests)
@@ -784,6 +789,16 @@ export class APIClient {
784
789
  chatRequest.tools = request.tools;
785
790
  this.applyToolChoice(chatRequest, request, 'chat/completions'); // §13-B1 forced tool_choice
786
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
+ }
787
802
  this.logChatCompletionsPayload(chatRequest, request.modelId, opts.stream);
788
803
  return { client, chatRequest };
789
804
  }
@@ -1054,6 +1069,10 @@ export class APIClient {
1054
1069
  // opt-in ZDR mode: "DESIGN NOTE — stateless ZDR mode" in
1055
1070
  // ResponsesAPIAdapter.ts (adapters/).
1056
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
+ }
1057
1076
  // Set system context as instructions (enables provider-side caching).
1058
1077
  // R63: request.systemMessage (the R28 static system prompt) was previously
1059
1078
  // dropped on this path — only <system-reminder> text mined from user
@@ -1165,6 +1184,12 @@ export class APIClient {
1165
1184
  if (request.tools && request.tools.length > 0) {
1166
1185
  return this.sendGenerateContentHTTP(request, modelConfig, apiKey);
1167
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
+ }
1168
1193
  // For non-tool requests, use SDK as before
1169
1194
  if (!this.googleClient) {
1170
1195
  this.googleClient = new GoogleGenerativeAI(apiKey);
@@ -1212,6 +1237,11 @@ export class APIClient {
1212
1237
  contents: request.messages,
1213
1238
  generation_config: generationConfig // Use the nested object directly
1214
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
+ }
1215
1245
  // Add tools if present
1216
1246
  if (request.tools && request.tools.length > 0) {
1217
1247
  // REST API uses snake_case "function_declarations", not camelCase "functionDeclarations"
@@ -1353,6 +1383,9 @@ export class APIClient {
1353
1383
  if (enableCaching && isAnthropicHistoryCacheEnabled()) {
1354
1384
  anthropicRequest.messages = applyAnthropicHistoryCache(anthropicRequest.messages, countAnthropicBreakpoints({ system: anthropicRequest.system, tools: anthropicRequest.tools })).messages;
1355
1385
  }
1386
+ // R225 (DARK): automatic cache_control + 1h TTL — mirrors sendAnthropicMessagesAPI.
1387
+ if (enableCaching)
1388
+ applyAnthropicCacheLevers(anthropicRequest);
1356
1389
  // Phase 2.8: Enable extended thinking for Claude 4+ models with reasoning support
1357
1390
  // Requires beta header: anthropic-beta: interleaved-thinking-2025-05-14
1358
1391
  // Skip if disableThinking option is set (used for continuation requests)
@@ -1981,6 +2014,9 @@ export class APIClient {
1981
2014
  // R153 (2026-09-16): keep the provider's LAST non-null finish_reason so a `length` cutoff survives reassembly
1982
2015
  // (the empty-response classifier keys `truncated` on it; the old hardcode reported every text turn as `stop`).
1983
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;
1984
2020
  // Capture this context before entering generator
1985
2021
  const self = this;
1986
2022
  // Create async generator that both yields chunks AND accumulates final message
@@ -1994,7 +2030,9 @@ export class APIClient {
1994
2030
  if (!firstChunk)
1995
2031
  firstChunk = chunk;
1996
2032
  chunkCount++;
1997
- const delta = chunk.choices[0]?.delta;
2033
+ if (captureStreamUsage && chunk?.usage)
2034
+ streamUsage = chunk.usage;
2035
+ const delta = chunk.choices?.[0]?.delta;
1998
2036
  // Debug: Log first few chunks to see what fields are present
1999
2037
  if ((process.env.DEBUG === 'true' || process.env.DEBUG_THINKING === 'true') && chunkCount <= 3) {
2000
2038
  console.log(`[DEBUG APIClient] Chunk ${chunkCount} delta keys:`, delta ? Object.keys(delta) : 'null');
@@ -2045,7 +2083,7 @@ export class APIClient {
2045
2083
  }
2046
2084
  }
2047
2085
  // Check if finish_reason indicates tool_calls completion (or length-truncated tool call)
2048
- const finishReason = chunk.choices[0]?.finish_reason;
2086
+ const finishReason = chunk.choices?.[0]?.finish_reason;
2049
2087
  if (finishReason)
2050
2088
  lastFinishReason = String(finishReason);
2051
2089
  if ((finishReason === 'tool_calls' || finishReason === 'length') && accumulatedToolCalls.size > 0) {
@@ -2111,11 +2149,7 @@ export class APIClient {
2111
2149
  // ('length' = output cap hit) instead of a synthetic 'stop'.
2112
2150
  finish_reason: finalToolCalls.length > 0 ? 'tool_calls' : (lastFinishReason ?? 'stop')
2113
2151
  }],
2114
- usage: {
2115
- prompt_tokens: 0,
2116
- completion_tokens: 0,
2117
- total_tokens: 0
2118
- }
2152
+ usage: streamFinalUsage(streamUsage)
2119
2153
  });
2120
2154
  }();
2121
2155
  return {
@@ -2215,6 +2249,10 @@ export class APIClient {
2215
2249
  responsesRequest.prompt_cache_key = request.conversationId;
2216
2250
  }
2217
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
+ }
2218
2256
  // Set system context as instructions (enables provider-side caching).
2219
2257
  // R63: merge the R28 static system prompt (previously dropped on this
2220
2258
  // path) ahead of reminders mined from user messages; XAI gets it as a
@@ -2475,6 +2513,11 @@ export class APIClient {
2475
2513
  if (request.tools && request.tools.length > 0) {
2476
2514
  return this.streamGenerateContentHTTP(request, modelConfig, apiKey);
2477
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
+ }
2478
2521
  // For non-tool requests, use SDK streaming
2479
2522
  if (!this.googleClient) {
2480
2523
  this.googleClient = new GoogleGenerativeAI(apiKey);
@@ -2843,7 +2886,14 @@ export class APIClient {
2843
2886
  config
2844
2887
  };
2845
2888
  if (request.systemMessage) {
2846
- 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
+ }
2847
2897
  }
2848
2898
  if (process.env.DEBUG === 'true') {
2849
2899
  console.log(`[DEBUG APIClient SDK] Non-streaming request for model: ${modelId}`);
@@ -2940,9 +2990,15 @@ export class APIClient {
2940
2990
  contents: request.messages,
2941
2991
  config // Config contains both generation params and tools
2942
2992
  };
2943
- // 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.
2944
2995
  if (request.systemMessage) {
2945
- sdkRequest.systemInstruction = request.systemMessage;
2996
+ if (isGeminiSystemFixEnabled()) {
2997
+ config.systemInstruction = request.systemMessage;
2998
+ }
2999
+ else {
3000
+ sdkRequest.systemInstruction = request.systemMessage;
3001
+ }
2946
3002
  }
2947
3003
  if (process.env.DEBUG === 'true') {
2948
3004
  console.log(`[DEBUG APIClient SDK] Using model: ${modelId}`);