@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
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only request history (prompt-cache restructure, 2026-10-02). Every lever here is DARK (unset/off = byte-identical).
|
|
3
|
+
* Evidence: .cortex/research/caching-audit-2026-10-02.md (RESTRUCTURE PLAN) + prefix-stability-2026-10-02.md (harness).
|
|
4
|
+
* The anchor lift (the one intended tools-array change at the first tool_result boundary) is NOT touched by any of these.
|
|
5
|
+
*
|
|
6
|
+
* CORTEX_WALL_CACHE_FIX (R221) off | on — the general safety net: every in-place mutation of a history message whose canonical
|
|
7
|
+
* conversion may already be cached (the HB-WALL-DROP nudge on the newest tool_result, the steering carriers, the R26 empty-turn repair,
|
|
8
|
+
* the R154 image stub) drops that message's cached conversion, so every later request carries the mutated bytes (wall nudge + wall
|
|
9
|
+
* summary persist; the single tail break at the retry remains, the second break on the request after it is gone). The wall drop itself
|
|
10
|
+
* is unchanged (operator 10-02: dropping the walled tail + nudging the newest tool_result is the deliberate trade).
|
|
11
|
+
* CORTEX_PERSIST_INJECTED (R223) off | on — the first request's injected user content (repo-state note, deferred-tool announcement,
|
|
12
|
+
* MCP / slash-command notes) is what every later request of the session sends for that message; storage + display keep the raw text.
|
|
13
|
+
* CORTEX_APPEND_ONLY_TOOLS (R222) off | on — the deferred-tool filter only APPENDS: newly enabled tools go to the end in first-enable
|
|
14
|
+
* order, nothing is evicted within the orchestrator's lifetime.
|
|
15
|
+
* CORTEX_KEEP_MENTOR_MESSAGES (R227) off | on — mentor/guidance messages stay in history (no mid-history removal at turn end).
|
|
16
|
+
* CORTEX_RESPONSES_SLICE_ALL (R228) off | on — every Responses request that chains previous_response_id sends only the items added since
|
|
17
|
+
* the held response (EndTurn gate, wall/empty retries, inaction retry, tools-off synthesis), and each of those responses moves the
|
|
18
|
+
* slice checkpoint.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveWallCacheFix(env?: NodeJS.ProcessEnv): boolean;
|
|
21
|
+
export declare function resolvePersistInjected(env?: NodeJS.ProcessEnv): boolean;
|
|
22
|
+
export declare function resolveAppendOnlyTools(env?: NodeJS.ProcessEnv): boolean;
|
|
23
|
+
export declare function resolveKeepMentorMessages(env?: NodeJS.ProcessEnv): boolean;
|
|
24
|
+
export declare function resolveResponsesSliceAll(env?: NodeJS.ProcessEnv): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* R228: the slice start for a request chained on previous_response_id. `held` = messageCountAtLastResponse (history length right after
|
|
27
|
+
* the held response was pushed). A history that SHRANK below it (HB-WALL-DROP popped the walled turn the server still holds) slices from
|
|
28
|
+
* the current end, so only items appended after the drop are sent. 0 = send everything (no usable checkpoint).
|
|
29
|
+
*/
|
|
30
|
+
export declare function chainedSliceStart(held: number, length: number): number;
|
|
31
|
+
/** Messages after the newest assistant message (the "tail unit" every steering carrier writes into). */
|
|
32
|
+
export declare function tailUnitAfterLastAssistant(history: readonly any[]): any[];
|
|
33
|
+
/**
|
|
34
|
+
* R228 fallback: the provider no longer has the response named by previous_response_id (store off, expired, deleted, other backend).
|
|
35
|
+
* Matched on the error text the Responses APIs return ("Previous response with id '…' not found", "previous_response_id … invalid/expired")
|
|
36
|
+
* or a 404 that names a response. Anything else is not a chain failure and is rethrown untouched.
|
|
37
|
+
*/
|
|
38
|
+
export declare function isPreviousResponseUnavailable(err: unknown): boolean;
|
|
39
|
+
//# sourceMappingURL=appendOnlyHistory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appendOnlyHistory.d.ts","sourceRoot":"","sources":["../../src/orchestrator/appendOnlyHistory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEjF;AAED,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEpF;AAED,wBAAgB,sBAAsB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEpF;AAED,wBAAgB,yBAAyB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEvF;AAED,wBAAgB,wBAAwB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAEtF;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtE;AAED,wGAAwG;AACxG,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,SAAS,GAAG,EAAE,GAAG,GAAG,EAAE,CASzE;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAUnE"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Append-only request history (prompt-cache restructure, 2026-10-02). Every lever here is DARK (unset/off = byte-identical).
|
|
3
|
+
* Evidence: .cortex/research/caching-audit-2026-10-02.md (RESTRUCTURE PLAN) + prefix-stability-2026-10-02.md (harness).
|
|
4
|
+
* The anchor lift (the one intended tools-array change at the first tool_result boundary) is NOT touched by any of these.
|
|
5
|
+
*
|
|
6
|
+
* CORTEX_WALL_CACHE_FIX (R221) off | on — the general safety net: every in-place mutation of a history message whose canonical
|
|
7
|
+
* conversion may already be cached (the HB-WALL-DROP nudge on the newest tool_result, the steering carriers, the R26 empty-turn repair,
|
|
8
|
+
* the R154 image stub) drops that message's cached conversion, so every later request carries the mutated bytes (wall nudge + wall
|
|
9
|
+
* summary persist; the single tail break at the retry remains, the second break on the request after it is gone). The wall drop itself
|
|
10
|
+
* is unchanged (operator 10-02: dropping the walled tail + nudging the newest tool_result is the deliberate trade).
|
|
11
|
+
* CORTEX_PERSIST_INJECTED (R223) off | on — the first request's injected user content (repo-state note, deferred-tool announcement,
|
|
12
|
+
* MCP / slash-command notes) is what every later request of the session sends for that message; storage + display keep the raw text.
|
|
13
|
+
* CORTEX_APPEND_ONLY_TOOLS (R222) off | on — the deferred-tool filter only APPENDS: newly enabled tools go to the end in first-enable
|
|
14
|
+
* order, nothing is evicted within the orchestrator's lifetime.
|
|
15
|
+
* CORTEX_KEEP_MENTOR_MESSAGES (R227) off | on — mentor/guidance messages stay in history (no mid-history removal at turn end).
|
|
16
|
+
* CORTEX_RESPONSES_SLICE_ALL (R228) off | on — every Responses request that chains previous_response_id sends only the items added since
|
|
17
|
+
* the held response (EndTurn gate, wall/empty retries, inaction retry, tools-off synthesis), and each of those responses moves the
|
|
18
|
+
* slice checkpoint.
|
|
19
|
+
*/
|
|
20
|
+
function onOff(v) {
|
|
21
|
+
const s = String(v ?? '').trim().toLowerCase();
|
|
22
|
+
return s === 'on' || s === 'true' || s === '1';
|
|
23
|
+
}
|
|
24
|
+
export function resolveWallCacheFix(env = process.env) {
|
|
25
|
+
return onOff(env.CORTEX_WALL_CACHE_FIX);
|
|
26
|
+
}
|
|
27
|
+
export function resolvePersistInjected(env = process.env) {
|
|
28
|
+
return onOff(env.CORTEX_PERSIST_INJECTED);
|
|
29
|
+
}
|
|
30
|
+
export function resolveAppendOnlyTools(env = process.env) {
|
|
31
|
+
return onOff(env.CORTEX_APPEND_ONLY_TOOLS);
|
|
32
|
+
}
|
|
33
|
+
export function resolveKeepMentorMessages(env = process.env) {
|
|
34
|
+
return onOff(env.CORTEX_KEEP_MENTOR_MESSAGES);
|
|
35
|
+
}
|
|
36
|
+
export function resolveResponsesSliceAll(env = process.env) {
|
|
37
|
+
return onOff(env.CORTEX_RESPONSES_SLICE_ALL);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* R228: the slice start for a request chained on previous_response_id. `held` = messageCountAtLastResponse (history length right after
|
|
41
|
+
* the held response was pushed). A history that SHRANK below it (HB-WALL-DROP popped the walled turn the server still holds) slices from
|
|
42
|
+
* the current end, so only items appended after the drop are sent. 0 = send everything (no usable checkpoint).
|
|
43
|
+
*/
|
|
44
|
+
export function chainedSliceStart(held, length) {
|
|
45
|
+
if (!(held > 0))
|
|
46
|
+
return 0;
|
|
47
|
+
return Math.min(held, length);
|
|
48
|
+
}
|
|
49
|
+
/** Messages after the newest assistant message (the "tail unit" every steering carrier writes into). */
|
|
50
|
+
export function tailUnitAfterLastAssistant(history) {
|
|
51
|
+
const out = [];
|
|
52
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
53
|
+
const m = history[i];
|
|
54
|
+
const role = m?.message?.role ?? m?.role ?? (m?.type === 'assistant' ? 'assistant' : undefined);
|
|
55
|
+
if (role === 'assistant')
|
|
56
|
+
break;
|
|
57
|
+
out.push(m);
|
|
58
|
+
}
|
|
59
|
+
return out;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* R228 fallback: the provider no longer has the response named by previous_response_id (store off, expired, deleted, other backend).
|
|
63
|
+
* Matched on the error text the Responses APIs return ("Previous response with id '…' not found", "previous_response_id … invalid/expired")
|
|
64
|
+
* or a 404 that names a response. Anything else is not a chain failure and is rethrown untouched.
|
|
65
|
+
*/
|
|
66
|
+
export function isPreviousResponseUnavailable(err) {
|
|
67
|
+
const e = err;
|
|
68
|
+
const status = Number(e?.status ?? e?.statusCode ?? e?.response?.status ?? e?.error?.status ?? NaN);
|
|
69
|
+
const text = [e?.message, e?.error?.message, e?.error?.code, e?.code, e?.response?.data?.error?.message]
|
|
70
|
+
.filter((x) => typeof x === 'string').join(' ');
|
|
71
|
+
if (/previous[_ ]?response/i.test(text) && /not[_ ]?found|expired|invalid|does not exist|unavailable|no longer|not stored|unknown/i.test(text))
|
|
72
|
+
return true;
|
|
73
|
+
// xAI (live probe 2026-10-02): 404 {"code":"not-found","error":"Response with id=resp_… not found"}; APIClient throws it as plain text
|
|
74
|
+
// ("XAI Responses API error 404: …") with no status field, so match the body wording itself.
|
|
75
|
+
if (/response with id\s*=?\s*['"]?resp_\S*['"]? not[ _-]?found/i.test(text))
|
|
76
|
+
return true;
|
|
77
|
+
return status === 404 && /\bresponse\b/i.test(text);
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=appendOnlyHistory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"appendOnlyHistory.js","sourceRoot":"","sources":["../../src/orchestrator/appendOnlyHistory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export declare function isGeminiSystemFixEnabled(): boolean;
|
|
2
|
+
export declare function isStableToolOrderEnabled(): boolean;
|
|
3
|
+
export declare function isOpenAICacheKeyEnabled(): boolean;
|
|
4
|
+
export declare function isAnthropicAutoCacheEnabled(): boolean;
|
|
5
|
+
export declare function isForcedChoiceFullToolsEnabled(): boolean;
|
|
6
|
+
export declare function isStreamUsageEnabled(): boolean;
|
|
7
|
+
/** '1h' when CORTEX_ANTHROPIC_CACHE_TTL=1h; undefined = provider default (5 minutes, no ttl field sent). */
|
|
8
|
+
export declare function anthropicCacheTtl(): '1h' | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Applies the dark Anthropic cache levers to a built Anthropic Messages request body (Anthropic provider only —
|
|
11
|
+
* never called on the xAI Messages branch). Never mutates the input message/tool/system objects (the messages
|
|
12
|
+
* array may be the orchestrator's cached canonical conversion); replaces the affected arrays on `req` with
|
|
13
|
+
* copies. Returns what it did, for tests/logging.
|
|
14
|
+
*/
|
|
15
|
+
export declare function applyAnthropicCacheLevers(req: any): {
|
|
16
|
+
ttl?: '1h';
|
|
17
|
+
auto: boolean;
|
|
18
|
+
};
|
|
19
|
+
/** OpenAI-shape usage object for the reassembled streaming final message: the provider's usage chunk when it
|
|
20
|
+
* arrived (all its fields kept — prompt_tokens_details / prompt_cache_hit_tokens …), else the legacy zeros. */
|
|
21
|
+
export declare function streamFinalUsage(providerUsage: any): any;
|
|
22
|
+
//# sourceMappingURL=transportCacheFixes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transportCacheFixes.d.ts","sourceRoot":"","sources":["../../src/orchestrator/transportCacheFixes.ts"],"names":[],"mappings":"AAqCA,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AACD,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AACD,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AACD,wBAAgB,2BAA2B,IAAI,OAAO,CAErD;AACD,wBAAgB,8BAA8B,IAAI,OAAO,CAExD;AACD,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AACD,4GAA4G;AAC5G,wBAAgB,iBAAiB,IAAI,IAAI,GAAG,SAAS,CAEpD;AAwBD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,GAAG,GAAG;IAAE,GAAG,CAAC,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAajF;AAMD;gHACgH;AAChH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,GAAG,GAAG,GAAG,CAGxD"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport prompt-cache + correctness fixes R224a / R225 / R229 / R230 (2026-10-02; caching audit
|
|
3
|
+
* .cortex/research/caching-audit-2026-10-02.md). Each is DARK behind its own env flag; with the flag off the
|
|
4
|
+
* callers take their pre-existing code path unchanged (byte-identical requests).
|
|
5
|
+
*
|
|
6
|
+
* - R229 CORTEX_GEMINI_SYSTEM_FIX: Gemini never received the system prompt. REST generateContent (non-streaming)
|
|
7
|
+
* sent no `system_instruction`; the non-tool @google/generative-ai SDK paths sent none either (that SDK is
|
|
8
|
+
* v0.2.1 on the v1 endpoint and has no systemInstruction support, so with the flag on those requests go through
|
|
9
|
+
* the v1beta REST builders instead); the @google/genai SDK paths set a TOP-LEVEL `systemInstruction`, which the
|
|
10
|
+
* SDK drops (GenerateContentParameters = {model, contents, config}) — it must be `config.systemInstruction`.
|
|
11
|
+
* - R230 CORTEX_STABLE_TOOL_ORDER: xAI hybrid server+client tools (ENABLE_SERVER_SIDE_TOOLS) put the server
|
|
12
|
+
* tools FIRST on the first request of each user turn while continuations use the original order → the tools
|
|
13
|
+
* array (prefix head) was reordered at every user-turn boundary. On: the original order on every request.
|
|
14
|
+
* - R225 CORTEX_OPENAI_CACHE_KEY: OpenAI chat/completions + Responses get `prompt_cache_key` = the session id
|
|
15
|
+
* (the value xAI already receives) so same-session requests route to the same cache.
|
|
16
|
+
* - R225 CORTEX_ANTHROPIC_AUTO_CACHE: Anthropic Messages adds the top-level automatic `cache_control` (moves with
|
|
17
|
+
* the conversation) beside the explicit system / last-tool markers, only while a breakpoint slot is free
|
|
18
|
+
* (cap 4, R218 markers counted).
|
|
19
|
+
* - R225 CORTEX_ANTHROPIC_CACHE_TTL=1h: every cache_control this harness emits on the Anthropic path (system,
|
|
20
|
+
* last tool, R218 history, automatic) carries ttl '1h' — uniform, so the "longer TTL first" ordering rule and
|
|
21
|
+
* the "last-block marker TTL must equal the automatic TTL" rule both hold. Default (unset / 5m) = unchanged.
|
|
22
|
+
* - R225 CORTEX_FORCED_CHOICE_FULL_TOOLS: a forced named tool_choice keeps the FULL tools array (the provider's
|
|
23
|
+
* tool_choice does the forcing) instead of narrowing it to the forced tool, so the forced request does not
|
|
24
|
+
* rewrite the tools prefix twice. ⚠ DeepSeek was observed (2026-08-29) to ignore a named choice when the full
|
|
25
|
+
* catalog is present — that is why narrowing exists.
|
|
26
|
+
* - R224a CORTEX_STREAM_USAGE: streaming chat/completions sends `stream_options: {include_usage: true}` and the
|
|
27
|
+
* reassembled final message carries the provider's usage chunk instead of zeros.
|
|
28
|
+
*
|
|
29
|
+
* Pure helpers — no client state. Flags are resolved per call so tests/benches can flip them.
|
|
30
|
+
*/
|
|
31
|
+
import { countAnthropicBreakpoints, ANTHROPIC_MAX_CACHE_BREAKPOINTS } from './transportFixes.js';
|
|
32
|
+
function flagOn(raw) {
|
|
33
|
+
const v = String(raw ?? '').trim().toLowerCase();
|
|
34
|
+
return v === 'on' || v === 'true' || v === '1';
|
|
35
|
+
}
|
|
36
|
+
export function isGeminiSystemFixEnabled() {
|
|
37
|
+
return flagOn(process.env.CORTEX_GEMINI_SYSTEM_FIX);
|
|
38
|
+
}
|
|
39
|
+
export function isStableToolOrderEnabled() {
|
|
40
|
+
return flagOn(process.env.CORTEX_STABLE_TOOL_ORDER);
|
|
41
|
+
}
|
|
42
|
+
export function isOpenAICacheKeyEnabled() {
|
|
43
|
+
return flagOn(process.env.CORTEX_OPENAI_CACHE_KEY);
|
|
44
|
+
}
|
|
45
|
+
export function isAnthropicAutoCacheEnabled() {
|
|
46
|
+
return flagOn(process.env.CORTEX_ANTHROPIC_AUTO_CACHE);
|
|
47
|
+
}
|
|
48
|
+
export function isForcedChoiceFullToolsEnabled() {
|
|
49
|
+
return flagOn(process.env.CORTEX_FORCED_CHOICE_FULL_TOOLS);
|
|
50
|
+
}
|
|
51
|
+
export function isStreamUsageEnabled() {
|
|
52
|
+
return flagOn(process.env.CORTEX_STREAM_USAGE);
|
|
53
|
+
}
|
|
54
|
+
/** '1h' when CORTEX_ANTHROPIC_CACHE_TTL=1h; undefined = provider default (5 minutes, no ttl field sent). */
|
|
55
|
+
export function anthropicCacheTtl() {
|
|
56
|
+
return String(process.env.CORTEX_ANTHROPIC_CACHE_TTL ?? '').trim().toLowerCase() === '1h' ? '1h' : undefined;
|
|
57
|
+
}
|
|
58
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
59
|
+
// R225 — Anthropic automatic cache_control + TTL
|
|
60
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
61
|
+
function withTtl(node, ttl) {
|
|
62
|
+
if (Array.isArray(node)) {
|
|
63
|
+
let changed = false;
|
|
64
|
+
const out = node.map((x) => { const y = withTtl(x, ttl); if (y !== x)
|
|
65
|
+
changed = true; return y; });
|
|
66
|
+
return changed ? out : node;
|
|
67
|
+
}
|
|
68
|
+
if (!node || typeof node !== 'object')
|
|
69
|
+
return node;
|
|
70
|
+
let out = node;
|
|
71
|
+
if (node.cache_control && typeof node.cache_control === 'object') {
|
|
72
|
+
out = { ...node, cache_control: { ...node.cache_control, ttl } };
|
|
73
|
+
}
|
|
74
|
+
if (Array.isArray(node.content)) {
|
|
75
|
+
const c = withTtl(node.content, ttl);
|
|
76
|
+
if (c !== node.content)
|
|
77
|
+
out = { ...out, content: c };
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Applies the dark Anthropic cache levers to a built Anthropic Messages request body (Anthropic provider only —
|
|
83
|
+
* never called on the xAI Messages branch). Never mutates the input message/tool/system objects (the messages
|
|
84
|
+
* array may be the orchestrator's cached canonical conversion); replaces the affected arrays on `req` with
|
|
85
|
+
* copies. Returns what it did, for tests/logging.
|
|
86
|
+
*/
|
|
87
|
+
export function applyAnthropicCacheLevers(req) {
|
|
88
|
+
const ttl = anthropicCacheTtl();
|
|
89
|
+
if (ttl) {
|
|
90
|
+
if (Array.isArray(req.system))
|
|
91
|
+
req.system = withTtl(req.system, ttl);
|
|
92
|
+
if (Array.isArray(req.tools))
|
|
93
|
+
req.tools = withTtl(req.tools, ttl);
|
|
94
|
+
if (Array.isArray(req.messages))
|
|
95
|
+
req.messages = withTtl(req.messages, ttl);
|
|
96
|
+
}
|
|
97
|
+
let auto = false;
|
|
98
|
+
if (isAnthropicAutoCacheEnabled() && countAnthropicBreakpoints(req) < ANTHROPIC_MAX_CACHE_BREAKPOINTS) {
|
|
99
|
+
req.cache_control = ttl ? { type: 'ephemeral', ttl } : { type: 'ephemeral' };
|
|
100
|
+
auto = true;
|
|
101
|
+
}
|
|
102
|
+
return { ...(ttl ? { ttl } : {}), auto };
|
|
103
|
+
}
|
|
104
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
105
|
+
// R224a — streaming chat/completions usage
|
|
106
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
107
|
+
/** OpenAI-shape usage object for the reassembled streaming final message: the provider's usage chunk when it
|
|
108
|
+
* arrived (all its fields kept — prompt_tokens_details / prompt_cache_hit_tokens …), else the legacy zeros. */
|
|
109
|
+
export function streamFinalUsage(providerUsage) {
|
|
110
|
+
if (providerUsage && typeof providerUsage === 'object')
|
|
111
|
+
return providerUsage;
|
|
112
|
+
return { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 };
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=transportCacheFixes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transportCacheFixes.js","sourceRoot":"","sources":["../../src/orchestrator/transportCacheFixes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport reasoning-effort fixes (2026-10-02; stack-portability map
|
|
3
|
+
* .cortex/research/stack-portability-2026-10-02.md, note N1). Each is DARK behind its own env flag; with the flag off
|
|
4
|
+
* every caller takes its pre-existing code path unchanged (byte-identical requests).
|
|
5
|
+
*
|
|
6
|
+
* - CORTEX_OPENAI_TOOLS_REASONING: the gateway forwards the request/action effort for OpenAI reasoning cards even though they
|
|
7
|
+
* do not declare `reasoning.toggleable`, so CORTEX_ACTION_EFFORT reaches `reasoning.effort` on the RESPONSES API. Chat/completions
|
|
8
|
+
* is unchanged: R19b's drop stays because OpenAI still rejects reasoning_effort + function tools there (live probe 2026-10-03:
|
|
9
|
+
* gpt-5.4-nano + gpt-5.6-luna → 400 "use /v1/responses"); Responses accepts it with tools (200 on both).
|
|
10
|
+
* - CORTEX_ANTHROPIC_EFFORT: Anthropic adaptive-thinking families (claude-4.7 / 4.8 / claude-5 / claude-fable-5) got
|
|
11
|
+
* `thinking:{type:'adaptive'}` only, so the action effort never reached the wire. On: `output_config.effort` = the
|
|
12
|
+
* effort (low|medium|high|xhigh|max; GA, no beta header). Non-adaptive families: `max` was not in the budget map and
|
|
13
|
+
* fell to 10000; on, `max` maps to a large budget clamped below max_tokens (budget_tokens must be < max_tokens, >= 1024).
|
|
14
|
+
* - CORTEX_GEMINI_TOOLS_THINKING: Gemini thinkingConfig was never sent with tools (the @google/genai builders skipped
|
|
15
|
+
* it — "cannot coexist", a Gemini 2.0-era observation) and the REST builder only ever sent a card-level thinkingLevel.
|
|
16
|
+
* On: the action effort maps to generationConfig.thinkingConfig — `thinkingLevel` on Gemini 3.x, `thinkingBudget` on
|
|
17
|
+
* 2.5 and older — on REST and SDK, with or without tools.
|
|
18
|
+
*
|
|
19
|
+
* Pure helpers — no client state. Flags are resolved per call so tests/benches can flip them.
|
|
20
|
+
*/
|
|
21
|
+
export declare function isOpenAIToolsReasoningEnabled(): boolean;
|
|
22
|
+
export declare function isAnthropicEffortEnabled(): boolean;
|
|
23
|
+
export declare function isGeminiToolsThinkingEnabled(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* `output_config.effort` value for an adaptive-thinking family, or undefined (send nothing → provider default).
|
|
26
|
+
* 'none' / unknown values send nothing (adaptive families have no "off" effort).
|
|
27
|
+
*/
|
|
28
|
+
export declare function anthropicOutputEffort(reasoningEffort: string | undefined): string | undefined;
|
|
29
|
+
/** Target thinking budget for effort `max` on budget_tokens families (before the max_tokens clamp). */
|
|
30
|
+
export declare const ANTHROPIC_MAX_EFFORT_BUDGET = 120000;
|
|
31
|
+
/** Visible-output room kept below max_tokens when clamping the `max` budget. */
|
|
32
|
+
export declare const ANTHROPIC_MAX_EFFORT_OUTPUT_ROOM = 1024;
|
|
33
|
+
/**
|
|
34
|
+
* budget_tokens for effort `max` on a non-adaptive family: ANTHROPIC_MAX_EFFORT_BUDGET clamped to
|
|
35
|
+
* max_tokens - ANTHROPIC_MAX_EFFORT_OUTPUT_ROOM (the API requires budget_tokens < max_tokens and >= 1024).
|
|
36
|
+
* Returns undefined when max_tokens is too small to honour the floor — the caller keeps its legacy value.
|
|
37
|
+
*/
|
|
38
|
+
export declare function anthropicMaxEffortBudget(maxTokens: number | undefined): number | undefined;
|
|
39
|
+
/** Gemini 3.x takes `thinkingLevel`; 2.5 and older take `thinkingBudget` (sending both is a 400). */
|
|
40
|
+
export declare function isGeminiThinkingLevelModel(modelId: string): boolean;
|
|
41
|
+
/** thinkingBudget per effort for Gemini 2.5 (Flash range 0-24576; Pro 128-32768 — every value here is valid on both). */
|
|
42
|
+
export declare const GEMINI_BUDGET_BY_EFFORT: Record<string, number>;
|
|
43
|
+
/** thinkingLevel per effort for Gemini 3.x (levels low|medium|high; xhigh/max clamp to high). */
|
|
44
|
+
export declare const GEMINI_LEVEL_BY_EFFORT: Record<string, string>;
|
|
45
|
+
/**
|
|
46
|
+
* The generationConfig.thinkingConfig for an effort, or undefined (none / unknown effort → send nothing, API default).
|
|
47
|
+
*/
|
|
48
|
+
export declare function geminiThinkingConfigForEffort(modelId: string, reasoningEffort: string | undefined): {
|
|
49
|
+
thinkingLevel: string;
|
|
50
|
+
} | {
|
|
51
|
+
thinkingBudget: number;
|
|
52
|
+
} | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* CORTEX_ACTION_EFFORT is filled into the request params AFTER the first request of each user turn is built
|
|
55
|
+
* (CortexOrchestrator initialPrepOpts vs the `??=` in the loop setup), so request 0 ran at the card default and
|
|
56
|
+
* requests 1+ at the action effort. On DeepSeek that is harmless (card 'medium' is coerced to 'high' server-side and
|
|
57
|
+
* the anchor-lift bust lands on the same boundary); on other providers it sends a different effort on request 0 and
|
|
58
|
+
* costs one extra cache break per user turn. DARK: CORTEX_ACTION_EFFORT_FIRST=on → request 0 gets the action effort
|
|
59
|
+
* when no ramp / request param set one. Off → undefined (byte-identical).
|
|
60
|
+
*/
|
|
61
|
+
export declare function firstRequestActionEffort(env?: NodeJS.ProcessEnv): string | undefined;
|
|
62
|
+
//# sourceMappingURL=transportEffortFixes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transportEffortFixes.d.ts","sourceRoot":"","sources":["../../src/orchestrator/transportEffortFixes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,wBAAgB,6BAA6B,IAAI,OAAO,CAEvD;AACD,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AACD,wBAAgB,4BAA4B,IAAI,OAAO,CAEtD;AAQD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG7F;AAED,uGAAuG;AACvG,eAAO,MAAM,2BAA2B,SAAS,CAAC;AAClD,gFAAgF;AAChF,eAAO,MAAM,gCAAgC,OAAO,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAK1F;AAMD,qGAAqG;AACrG,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEnE;AAED,yHAAyH;AACzH,eAAO,MAAM,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAM1D,CAAC;AAEF,iGAAiG;AACjG,eAAO,MAAM,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAMzD,CAAC;AAEF;;GAEG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,GAAG,SAAS,GAClC;IAAE,aAAa,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,cAAc,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAQpE;AAMD;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAIjG"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transport reasoning-effort fixes (2026-10-02; stack-portability map
|
|
3
|
+
* .cortex/research/stack-portability-2026-10-02.md, note N1). Each is DARK behind its own env flag; with the flag off
|
|
4
|
+
* every caller takes its pre-existing code path unchanged (byte-identical requests).
|
|
5
|
+
*
|
|
6
|
+
* - CORTEX_OPENAI_TOOLS_REASONING: the gateway forwards the request/action effort for OpenAI reasoning cards even though they
|
|
7
|
+
* do not declare `reasoning.toggleable`, so CORTEX_ACTION_EFFORT reaches `reasoning.effort` on the RESPONSES API. Chat/completions
|
|
8
|
+
* is unchanged: R19b's drop stays because OpenAI still rejects reasoning_effort + function tools there (live probe 2026-10-03:
|
|
9
|
+
* gpt-5.4-nano + gpt-5.6-luna → 400 "use /v1/responses"); Responses accepts it with tools (200 on both).
|
|
10
|
+
* - CORTEX_ANTHROPIC_EFFORT: Anthropic adaptive-thinking families (claude-4.7 / 4.8 / claude-5 / claude-fable-5) got
|
|
11
|
+
* `thinking:{type:'adaptive'}` only, so the action effort never reached the wire. On: `output_config.effort` = the
|
|
12
|
+
* effort (low|medium|high|xhigh|max; GA, no beta header). Non-adaptive families: `max` was not in the budget map and
|
|
13
|
+
* fell to 10000; on, `max` maps to a large budget clamped below max_tokens (budget_tokens must be < max_tokens, >= 1024).
|
|
14
|
+
* - CORTEX_GEMINI_TOOLS_THINKING: Gemini thinkingConfig was never sent with tools (the @google/genai builders skipped
|
|
15
|
+
* it — "cannot coexist", a Gemini 2.0-era observation) and the REST builder only ever sent a card-level thinkingLevel.
|
|
16
|
+
* On: the action effort maps to generationConfig.thinkingConfig — `thinkingLevel` on Gemini 3.x, `thinkingBudget` on
|
|
17
|
+
* 2.5 and older — on REST and SDK, with or without tools.
|
|
18
|
+
*
|
|
19
|
+
* Pure helpers — no client state. Flags are resolved per call so tests/benches can flip them.
|
|
20
|
+
*/
|
|
21
|
+
function flagOn(raw) {
|
|
22
|
+
const v = String(raw ?? '').trim().toLowerCase();
|
|
23
|
+
return v === 'on' || v === 'true' || v === '1';
|
|
24
|
+
}
|
|
25
|
+
export function isOpenAIToolsReasoningEnabled() {
|
|
26
|
+
return flagOn(process.env.CORTEX_OPENAI_TOOLS_REASONING);
|
|
27
|
+
}
|
|
28
|
+
export function isAnthropicEffortEnabled() {
|
|
29
|
+
return flagOn(process.env.CORTEX_ANTHROPIC_EFFORT);
|
|
30
|
+
}
|
|
31
|
+
export function isGeminiToolsThinkingEnabled() {
|
|
32
|
+
return flagOn(process.env.CORTEX_GEMINI_TOOLS_THINKING);
|
|
33
|
+
}
|
|
34
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
35
|
+
// Anthropic
|
|
36
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
37
|
+
const ANTHROPIC_EFFORT_LEVELS = new Set(['low', 'medium', 'high', 'xhigh', 'max']);
|
|
38
|
+
/**
|
|
39
|
+
* `output_config.effort` value for an adaptive-thinking family, or undefined (send nothing → provider default).
|
|
40
|
+
* 'none' / unknown values send nothing (adaptive families have no "off" effort).
|
|
41
|
+
*/
|
|
42
|
+
export function anthropicOutputEffort(reasoningEffort) {
|
|
43
|
+
const e = String(reasoningEffort ?? '').trim().toLowerCase();
|
|
44
|
+
return ANTHROPIC_EFFORT_LEVELS.has(e) ? e : undefined;
|
|
45
|
+
}
|
|
46
|
+
/** Target thinking budget for effort `max` on budget_tokens families (before the max_tokens clamp). */
|
|
47
|
+
export const ANTHROPIC_MAX_EFFORT_BUDGET = 120000;
|
|
48
|
+
/** Visible-output room kept below max_tokens when clamping the `max` budget. */
|
|
49
|
+
export const ANTHROPIC_MAX_EFFORT_OUTPUT_ROOM = 1024;
|
|
50
|
+
/**
|
|
51
|
+
* budget_tokens for effort `max` on a non-adaptive family: ANTHROPIC_MAX_EFFORT_BUDGET clamped to
|
|
52
|
+
* max_tokens - ANTHROPIC_MAX_EFFORT_OUTPUT_ROOM (the API requires budget_tokens < max_tokens and >= 1024).
|
|
53
|
+
* Returns undefined when max_tokens is too small to honour the floor — the caller keeps its legacy value.
|
|
54
|
+
*/
|
|
55
|
+
export function anthropicMaxEffortBudget(maxTokens) {
|
|
56
|
+
const mt = Number(maxTokens);
|
|
57
|
+
if (!Number.isFinite(mt) || mt <= 0)
|
|
58
|
+
return undefined;
|
|
59
|
+
const b = Math.min(ANTHROPIC_MAX_EFFORT_BUDGET, Math.floor(mt) - ANTHROPIC_MAX_EFFORT_OUTPUT_ROOM);
|
|
60
|
+
return b >= 1024 ? b : undefined;
|
|
61
|
+
}
|
|
62
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
63
|
+
// Gemini
|
|
64
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
65
|
+
/** Gemini 3.x takes `thinkingLevel`; 2.5 and older take `thinkingBudget` (sending both is a 400). */
|
|
66
|
+
export function isGeminiThinkingLevelModel(modelId) {
|
|
67
|
+
return /^(models\/)?gemini-([3-9]|\d{2,})/i.test(String(modelId ?? '').trim());
|
|
68
|
+
}
|
|
69
|
+
/** thinkingBudget per effort for Gemini 2.5 (Flash range 0-24576; Pro 128-32768 — every value here is valid on both). */
|
|
70
|
+
export const GEMINI_BUDGET_BY_EFFORT = {
|
|
71
|
+
low: 2048,
|
|
72
|
+
medium: 8192,
|
|
73
|
+
high: 16384,
|
|
74
|
+
xhigh: 24576,
|
|
75
|
+
max: 24576,
|
|
76
|
+
};
|
|
77
|
+
/** thinkingLevel per effort for Gemini 3.x (levels low|medium|high; xhigh/max clamp to high). */
|
|
78
|
+
export const GEMINI_LEVEL_BY_EFFORT = {
|
|
79
|
+
low: 'low',
|
|
80
|
+
medium: 'medium',
|
|
81
|
+
high: 'high',
|
|
82
|
+
xhigh: 'high',
|
|
83
|
+
max: 'high',
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* The generationConfig.thinkingConfig for an effort, or undefined (none / unknown effort → send nothing, API default).
|
|
87
|
+
*/
|
|
88
|
+
export function geminiThinkingConfigForEffort(modelId, reasoningEffort) {
|
|
89
|
+
const e = String(reasoningEffort ?? '').trim().toLowerCase();
|
|
90
|
+
if (isGeminiThinkingLevelModel(modelId)) {
|
|
91
|
+
const level = GEMINI_LEVEL_BY_EFFORT[e];
|
|
92
|
+
return level ? { thinkingLevel: level } : undefined;
|
|
93
|
+
}
|
|
94
|
+
const budget = GEMINI_BUDGET_BY_EFFORT[e];
|
|
95
|
+
return budget !== undefined ? { thinkingBudget: budget } : undefined;
|
|
96
|
+
}
|
|
97
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
98
|
+
// CORTEX_ACTION_EFFORT_FIRST — request 0 of each user turn
|
|
99
|
+
// ---------------------------------------------------------------------------------------------------------
|
|
100
|
+
/**
|
|
101
|
+
* CORTEX_ACTION_EFFORT is filled into the request params AFTER the first request of each user turn is built
|
|
102
|
+
* (CortexOrchestrator initialPrepOpts vs the `??=` in the loop setup), so request 0 ran at the card default and
|
|
103
|
+
* requests 1+ at the action effort. On DeepSeek that is harmless (card 'medium' is coerced to 'high' server-side and
|
|
104
|
+
* the anchor-lift bust lands on the same boundary); on other providers it sends a different effort on request 0 and
|
|
105
|
+
* costs one extra cache break per user turn. DARK: CORTEX_ACTION_EFFORT_FIRST=on → request 0 gets the action effort
|
|
106
|
+
* when no ramp / request param set one. Off → undefined (byte-identical).
|
|
107
|
+
*/
|
|
108
|
+
export function firstRequestActionEffort(env = process.env) {
|
|
109
|
+
if (!flagOn(env.CORTEX_ACTION_EFFORT_FIRST))
|
|
110
|
+
return undefined;
|
|
111
|
+
const e = String(env.CORTEX_ACTION_EFFORT ?? '').trim();
|
|
112
|
+
return e || undefined;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=transportEffortFixes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transportEffortFixes.js","sourceRoot":"","sources":["../../src/orchestrator/transportEffortFixes.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,8 +4,10 @@ export interface WallDropResult {
|
|
|
4
4
|
dropped: boolean;
|
|
5
5
|
carrier?: 'tool_result' | 'none';
|
|
6
6
|
droppedChars?: number;
|
|
7
|
+
carrierMessage?: any;
|
|
7
8
|
}
|
|
8
|
-
/** Drops the newest message when it is a walled assistant turn (no tool call); appends `nudge` to the newest tool_result. Mutates.
|
|
9
|
+
/** Drops the newest message when it is a walled assistant turn (no tool call); appends `nudge` to the newest tool_result. Mutates.
|
|
10
|
+
* `carrierMessage` = the history record that received the nudge (R221: its cached conversion is stale and must be invalidated). */
|
|
9
11
|
export declare function dropWalledTurn(history: any[], nudge: string): WallDropResult;
|
|
10
12
|
/**
|
|
11
13
|
* HB-WALL-SUMMARY (CORTEX_WALL_SUMMARY=on, dark): on a reasoning-exhaustion wall, one helper call (the EndTurn judge's mentor wire, small
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallGuard.d.ts","sourceRoot":"","sources":["../../src/orchestrator/wallGuard.ts"],"names":[],"mappings":"AAgBA,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAG7E;AAED,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAKzF;AAED,MAAM,WAAW,cAAc;IAAG,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE;
|
|
1
|
+
{"version":3,"file":"wallGuard.d.ts","sourceRoot":"","sources":["../../src/orchestrator/wallGuard.ts"],"names":[],"mappings":"AAgBA,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAG7E;AAED,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAKzF;AAED,MAAM,WAAW,cAAc;IAAG,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAAC,cAAc,CAAC,EAAE,GAAG,CAAA;CAAE;AAInI;oIACoI;AACpI,wBAAgB,cAAc,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,cAAc,CAmB5E;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAAG,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE;AAEhH,wBAAgB,kBAAkB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,iBAAiB,CAI1F;AAED,6FAA6F;AAC7F,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,SAAS,GAAG,EAAE,GAAG,MAAM,CAStE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAG9E;AAED,eAAO,MAAM,mBAAmB,QAM6C,CAAC;AAE9E,wBAAgB,sBAAsB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAEvE;AAED,mGAAmG;AACnG,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKzD"}
|
|
@@ -25,7 +25,8 @@ export function resolveOutputCap(env = process.env) {
|
|
|
25
25
|
return n >= 1024 ? n : undefined;
|
|
26
26
|
}
|
|
27
27
|
function roleOf(m) { return m?.message?.role ?? m?.role ?? (m?.type === 'assistant' ? 'assistant' : undefined); }
|
|
28
|
-
/** Drops the newest message when it is a walled assistant turn (no tool call); appends `nudge` to the newest tool_result. Mutates.
|
|
28
|
+
/** Drops the newest message when it is a walled assistant turn (no tool call); appends `nudge` to the newest tool_result. Mutates.
|
|
29
|
+
* `carrierMessage` = the history record that received the nudge (R221: its cached conversion is stale and must be invalidated). */
|
|
29
30
|
export function dropWalledTurn(history, nudge) {
|
|
30
31
|
const last = history[history.length - 1];
|
|
31
32
|
if (!last || roleOf(last) !== 'assistant')
|
|
@@ -38,7 +39,19 @@ export function dropWalledTurn(history, nudge) {
|
|
|
38
39
|
for (const b of blocks)
|
|
39
40
|
droppedChars += String(b?.thinking ?? b?.text ?? b?.reasoning ?? '').length;
|
|
40
41
|
history.pop();
|
|
41
|
-
|
|
42
|
+
const before = history.length;
|
|
43
|
+
const carried = appendStatusToNewestToolResult(history, nudge);
|
|
44
|
+
let carrierMessage;
|
|
45
|
+
if (carried) {
|
|
46
|
+
for (let i = before - 1; i >= 0; i--) {
|
|
47
|
+
const c = history[i]?.message?.content ?? history[i]?.content;
|
|
48
|
+
if (Array.isArray(c) && c.some((b) => b?.type === 'tool_result')) {
|
|
49
|
+
carrierMessage = history[i];
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return { dropped: true, carrier: carried ? 'tool_result' : 'none', droppedChars, ...(carrierMessage ? { carrierMessage } : {}) };
|
|
42
55
|
}
|
|
43
56
|
export function resolveWallSummary(env = process.env) {
|
|
44
57
|
const v = String(env.CORTEX_WALL_SUMMARY ?? '').trim().toLowerCase();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wallGuard.js","sourceRoot":"","sources":["../../src/orchestrator/wallGuard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,8BAA8B,EAAE,MAAM,iBAAiB,CAAC;AAEjE,MAAM,UAAU,eAAe,CAAC,MAAyB,OAAO,CAAC,GAAG;IAClE,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,gBAAgB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAClE,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,CAAC;AACjD,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACnE,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9D,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACnC,CAAC;AAID,SAAS,MAAM,CAAC,CAAM,IAAwB,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,CAAC,EAAE,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAE1I
|
|
1
|
+
{"version":3,"file":"wallGuard.js","sourceRoot":"","sources":["../../src/orchestrator/wallGuard.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,8 +12,15 @@ export declare class ClientSideToolFilter {
|
|
|
12
12
|
private discoveredTools;
|
|
13
13
|
/** Record that a tool was used (adds to recent list). */
|
|
14
14
|
recordToolUse(name: string): void;
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/** R222 append-only order: every tool name ever emitted, in first-enable order (never evicted). */
|
|
16
|
+
private emittedOrder;
|
|
17
|
+
/** Get filtered tools: essential + discovered + recently-used.
|
|
18
|
+
* R222 (opts.appendOnly — CORTEX_APPEND_ONLY_TOOLS, dark): the result only ever GROWS — tools emitted before keep their position
|
|
19
|
+
* (even after falling out of the 15-slot recent list), newly enabled tools are appended at the END in first-enable order, so the
|
|
20
|
+
* tools part of the cached prefix changes only by appending. Off → the pre-existing allTools-order filter (byte-identical). */
|
|
21
|
+
getFilteredTools(allTools: CanonicalTool[], opts?: {
|
|
22
|
+
appendOnly?: boolean;
|
|
23
|
+
}): CanonicalTool[];
|
|
17
24
|
/** Get deferred tool names (standard tier, not yet discovered/used). */
|
|
18
25
|
getDeferredToolNames(allTools: CanonicalTool[]): string[];
|
|
19
26
|
/** Get deferred tools with metadata for richer announcements. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClientSideToolFilter.d.ts","sourceRoot":"","sources":["../../src/tools/ClientSideToolFilter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAM5E,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,eAAe,CAAqB;IAE5C,yDAAyD;IACzD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQjC,
|
|
1
|
+
{"version":3,"file":"ClientSideToolFilter.d.ts","sourceRoot":"","sources":["../../src/tools/ClientSideToolFilter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAM5E,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,YAAY,CAAgB;IACpC,OAAO,CAAC,eAAe,CAAqB;IAE5C,yDAAyD;IACzD,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQjC,mGAAmG;IACnG,OAAO,CAAC,YAAY,CAAgB;IAEpC;;;oIAGgI;IAChI,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,EAAE,IAAI,GAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,aAAa,EAAE;IAsBjG,wEAAwE;IACxE,oBAAoB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE;IAOzD,iEAAiE;IACjE,gBAAgB,CAAC,QAAQ,EAAE,aAAa,EAAE,GAAG;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE;IAOpF,4CAA4C;IAC5C,eAAe,IAAI,SAAS,MAAM,EAAE;IAIpC;;;;OAIG;IACH,qBAAqB,CAAC,gBAAgB,EAAE,MAAM,GAAG,IAAI;IAerD,sBAAsB;IACtB,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -20,12 +20,34 @@ export class ClientSideToolFilter {
|
|
|
20
20
|
this.recentlyUsed.pop();
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
-
/**
|
|
24
|
-
|
|
23
|
+
/** R222 append-only order: every tool name ever emitted, in first-enable order (never evicted). */
|
|
24
|
+
emittedOrder = [];
|
|
25
|
+
/** Get filtered tools: essential + discovered + recently-used.
|
|
26
|
+
* R222 (opts.appendOnly — CORTEX_APPEND_ONLY_TOOLS, dark): the result only ever GROWS — tools emitted before keep their position
|
|
27
|
+
* (even after falling out of the 15-slot recent list), newly enabled tools are appended at the END in first-enable order, so the
|
|
28
|
+
* tools part of the cached prefix changes only by appending. Off → the pre-existing allTools-order filter (byte-identical). */
|
|
29
|
+
getFilteredTools(allTools, opts = {}) {
|
|
25
30
|
const recentSet = new Set(this.recentlyUsed);
|
|
26
|
-
|
|
31
|
+
const enabled = allTools.filter((t) => t.discoveryTier === 'essential' ||
|
|
27
32
|
recentSet.has(t.name) ||
|
|
28
33
|
this.discoveredTools.has(t.name));
|
|
34
|
+
if (!opts.appendOnly)
|
|
35
|
+
return enabled;
|
|
36
|
+
const byName = new Map(allTools.map((t) => [t.name, t]));
|
|
37
|
+
const known = new Set(this.emittedOrder);
|
|
38
|
+
for (const t of enabled) {
|
|
39
|
+
if (!known.has(t.name)) {
|
|
40
|
+
this.emittedOrder.push(t.name);
|
|
41
|
+
known.add(t.name);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const out = [];
|
|
45
|
+
for (const name of this.emittedOrder) {
|
|
46
|
+
const t = byName.get(name);
|
|
47
|
+
if (t)
|
|
48
|
+
out.push(t); // a tool no longer offered at all (MCP server gone) cannot be sent
|
|
49
|
+
}
|
|
50
|
+
return out;
|
|
29
51
|
}
|
|
30
52
|
/** Get deferred tool names (standard tier, not yet discovered/used). */
|
|
31
53
|
getDeferredToolNames(allTools) {
|
|
@@ -69,6 +91,7 @@ export class ClientSideToolFilter {
|
|
|
69
91
|
reset() {
|
|
70
92
|
this.recentlyUsed = [];
|
|
71
93
|
this.discoveredTools.clear();
|
|
94
|
+
this.emittedOrder = [];
|
|
72
95
|
}
|
|
73
96
|
}
|
|
74
97
|
//# sourceMappingURL=ClientSideToolFilter.js.map
|