@nexus-cortex/core 4.95.0 → 4.96.1

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.
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * Pure — no orchestrator state.
13
13
  */
14
- export type EmptyResponseKind = 'not_empty' | 'reasoning_only' | 'no_visible_content' | 'truncated';
14
+ export type EmptyResponseKind = 'not_empty' | 'reasoning_only' | 'reasoning_only_active' | 'no_visible_content' | 'truncated';
15
15
  export interface EmptyResponseClassification {
16
16
  kind: EmptyResponseKind;
17
17
  /** The model emitted thinking/redacted_thinking blocks. */
@@ -19,14 +19,27 @@ export interface EmptyResponseClassification {
19
19
  /** The model emitted an (unexecuted) tool_use — not an empty turn. */
20
20
  hadToolUse: boolean;
21
21
  }
22
- export declare function classifyEmptyResponse(content: unknown, stopReason?: string): EmptyResponseClassification;
22
+ /**
23
+ * @param loopHasBudget — HB-ENDTURN-TERMINAL (2026-09-08): the tool loop still has budget/iterations
24
+ * left (computed by the orchestrator; gated behind CORTEX_EMPTY_TURN_CONTINUE). A reasoning-only turn
25
+ * that ISN'T truncated is AMBIGUOUS: "reasoned to a final answer, forgot to surface it" (exhausted →
26
+ * force the answer, no tools) vs "reasoned about the NEXT action mid-recon" (has budget → CONTINUE with
27
+ * tools). The budget-blind classifier previously routed BOTH to `reasoning_only` (write-your-answer +
28
+ * forbid tools), which forced premature terminal surrender on DeepSeek mid-recon builds. With budget
29
+ * remaining we split it into `reasoning_only_active` (continue-with-tools), mirroring the D-E `truncated`
30
+ * carve-out. When loopHasBudget is undefined/false the behavior is byte-identical to before.
31
+ */
32
+ export declare function classifyEmptyResponse(content: unknown, stopReason?: string, loopHasBudget?: boolean): EmptyResponseClassification;
23
33
  /**
24
34
  * Nudge tailored to the empty-response kind. `reasoning_only` means the model
25
35
  * did the thinking but never surfaced the answer — tell it exactly that;
26
- * `no_visible_content` gets the generic completion prompt.
36
+ * `reasoning_only_active` (budget remaining) means it was thinking about its
37
+ * NEXT action — tell it to continue; `no_visible_content` gets the generic
38
+ * completion prompt.
27
39
  */
28
40
  export declare function emptyResponseNudge(kind: EmptyResponseKind): string;
29
41
  /** D-E: a truncated turn was cut off — it should be allowed to CONTINUE (incl. tools), not be told
30
- * "do not call any more tools" (which the reasoning_only/no_content path appends). */
42
+ * "do not call any more tools" (which the reasoning_only/no_content path appends).
43
+ * HB-ENDTURN-TERMINAL: `reasoning_only_active` (mid-recon, budget remaining) is likewise a CONTINUE. */
31
44
  export declare function nudgeForbidsTools(kind: EmptyResponseKind): boolean;
32
45
  //# sourceMappingURL=emptyResponseClassifier.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"emptyResponseClassifier.d.ts","sourceRoot":"","sources":["../../src/orchestrator/emptyResponseClassifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,gBAAgB,GAAG,oBAAoB,GAAG,WAAW,CAAC;AAKpG,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,iBAAiB,CAAC;IACxB,2DAA2D;IAC3D,YAAY,EAAE,OAAO,CAAC;IACtB,sEAAsE;IACtE,UAAU,EAAE,OAAO,CAAC;CACrB;AAMD,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,2BAA2B,CAsBxG;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAQlE;AAED;sFACsF;AACtF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAElE"}
1
+ {"version":3,"file":"emptyResponseClassifier.d.ts","sourceRoot":"","sources":["../../src/orchestrator/emptyResponseClassifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,MAAM,iBAAiB,GACzB,WAAW,GACX,gBAAgB,GAChB,uBAAuB,GACvB,oBAAoB,GACpB,WAAW,CAAC;AAKhB,MAAM,WAAW,2BAA2B;IAC1C,IAAI,EAAE,iBAAiB,CAAC;IACxB,2DAA2D;IAC3D,YAAY,EAAE,OAAO,CAAC;IACtB,sEAAsE;IACtE,UAAU,EAAE,OAAO,CAAC;CACrB;AAMD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,UAAU,CAAC,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,OAAO,GACtB,2BAA2B,CAuB7B;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,iBAAiB,GAAG,MAAM,CAWlE;AAED;;wGAEwG;AACxG,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAElE"}
@@ -17,7 +17,17 @@ const TRUNCATION_STOP = new Set(['max_tokens', 'length', 'max_output_tokens', 'm
17
17
  function blocks(content) {
18
18
  return Array.isArray(content) ? content : [];
19
19
  }
20
- export function classifyEmptyResponse(content, stopReason) {
20
+ /**
21
+ * @param loopHasBudget — HB-ENDTURN-TERMINAL (2026-09-08): the tool loop still has budget/iterations
22
+ * left (computed by the orchestrator; gated behind CORTEX_EMPTY_TURN_CONTINUE). A reasoning-only turn
23
+ * that ISN'T truncated is AMBIGUOUS: "reasoned to a final answer, forgot to surface it" (exhausted →
24
+ * force the answer, no tools) vs "reasoned about the NEXT action mid-recon" (has budget → CONTINUE with
25
+ * tools). The budget-blind classifier previously routed BOTH to `reasoning_only` (write-your-answer +
26
+ * forbid tools), which forced premature terminal surrender on DeepSeek mid-recon builds. With budget
27
+ * remaining we split it into `reasoning_only_active` (continue-with-tools), mirroring the D-E `truncated`
28
+ * carve-out. When loopHasBudget is undefined/false the behavior is byte-identical to before.
29
+ */
30
+ export function classifyEmptyResponse(content, stopReason, loopHasBudget) {
21
31
  const bs = blocks(content);
22
32
  const hadReasoning = bs.some((b) => b?.type === 'thinking' || b?.type === 'redacted_thinking');
23
33
  const hadToolUse = bs.some((b) => b?.type === 'tool_use');
@@ -31,29 +41,36 @@ export function classifyEmptyResponse(content, stopReason) {
31
41
  if (stopReason && TRUNCATION_STOP.has(stopReason.trim().toLowerCase())) {
32
42
  return { kind: 'truncated', hadReasoning, hadToolUse };
33
43
  }
34
- return {
35
- kind: hadReasoning ? 'reasoning_only' : 'no_visible_content',
36
- hadReasoning,
37
- hadToolUse,
38
- };
44
+ if (hadReasoning) {
45
+ // HB-ENDTURN-TERMINAL: with budget remaining this is a mid-recon reasoning turn (continue), not a
46
+ // finished-but-unsurfaced answer. Only when budget is spent do we demand the final answer (no tools).
47
+ return { kind: loopHasBudget ? 'reasoning_only_active' : 'reasoning_only', hadReasoning, hadToolUse };
48
+ }
49
+ return { kind: 'no_visible_content', hadReasoning, hadToolUse };
39
50
  }
40
51
  /**
41
52
  * Nudge tailored to the empty-response kind. `reasoning_only` means the model
42
53
  * did the thinking but never surfaced the answer — tell it exactly that;
43
- * `no_visible_content` gets the generic completion prompt.
54
+ * `reasoning_only_active` (budget remaining) means it was thinking about its
55
+ * NEXT action — tell it to continue; `no_visible_content` gets the generic
56
+ * completion prompt.
44
57
  */
45
58
  export function emptyResponseNudge(kind) {
46
59
  if (kind === 'truncated') {
47
60
  return 'Your previous response was cut off by the output token limit before you finished — it was NOT complete. Continue from where you stopped and finish concisely; do not restart from the beginning.';
48
61
  }
62
+ if (kind === 'reasoning_only_active') {
63
+ return 'You produced reasoning but took no action and gave no final answer, and you still have budget remaining. Continue the task now — take your next concrete action (call a tool), or give your complete, verified final answer only if you are actually finished.';
64
+ }
49
65
  if (kind === 'reasoning_only') {
50
66
  return 'You produced reasoning but no visible answer. Write out your complete final answer now, in plain text, based on that reasoning.';
51
67
  }
52
68
  return 'Your previous response had no content. Provide your complete final answer now in plain text.';
53
69
  }
54
70
  /** D-E: a truncated turn was cut off — it should be allowed to CONTINUE (incl. tools), not be told
55
- * "do not call any more tools" (which the reasoning_only/no_content path appends). */
71
+ * "do not call any more tools" (which the reasoning_only/no_content path appends).
72
+ * HB-ENDTURN-TERMINAL: `reasoning_only_active` (mid-recon, budget remaining) is likewise a CONTINUE. */
56
73
  export function nudgeForbidsTools(kind) {
57
- return kind !== 'truncated';
74
+ return kind !== 'truncated' && kind !== 'reasoning_only_active';
58
75
  }
59
76
  //# sourceMappingURL=emptyResponseClassifier.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"emptyResponseClassifier.js","sourceRoot":"","sources":["../../src/orchestrator/emptyResponseClassifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAIrE,qGAAqG;AACrG,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,QAAQ,EAAE,mBAAmB,EAAE,cAAc,CAAC,CAAC,CAAC;AAU/F,SAAS,MAAM,CAAC,OAAgB;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,OAAgB,EAAE,UAAmB;IACzE,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3B,MAAM,YAAY,GAAG,EAAE,CAAC,IAAI,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,UAAU,IAAI,CAAC,EAAE,IAAI,KAAK,mBAAmB,CACjE,CAAC;IACF,MAAM,UAAU,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,UAAU,CAAC,CAAC;IAE1D,IAAI,uBAAuB,CAAC,OAAc,CAAC,IAAI,UAAU,EAAE,CAAC;QAC1D,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IACzD,CAAC;IACD,gGAAgG;IAChG,gGAAgG;IAChG,+FAA+F;IAC/F,+FAA+F;IAC/F,IAAI,UAAU,IAAI,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QACvE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IACzD,CAAC;IACD,OAAO;QACL,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,oBAAoB;QAC5D,YAAY;QACZ,UAAU;KACX,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAuB;IACxD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO,kMAAkM,CAAC;IAC5M,CAAC;IACD,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;QAC9B,OAAO,iIAAiI,CAAC;IAC3I,CAAC;IACD,OAAO,8FAA8F,CAAC;AACxG,CAAC;AAED;sFACsF;AACtF,MAAM,UAAU,iBAAiB,CAAC,IAAuB;IACvD,OAAO,IAAI,KAAK,WAAW,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"emptyResponseClassifier.js","sourceRoot":"","sources":["../../src/orchestrator/emptyResponseClassifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AASrE,qGAAqG;AACrG,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,CAAC,YAAY,EAAE,QAAQ,EAAE,mBAAmB,EAAE,cAAc,CAAC,CAAC,CAAC;AAU/F,SAAS,MAAM,CAAC,OAAgB;IAC9B,OAAO,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,qBAAqB,CACnC,OAAgB,EAChB,UAAmB,EACnB,aAAuB;IAEvB,MAAM,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3B,MAAM,YAAY,GAAG,EAAE,CAAC,IAAI,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,UAAU,IAAI,CAAC,EAAE,IAAI,KAAK,mBAAmB,CACjE,CAAC;IACF,MAAM,UAAU,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,UAAU,CAAC,CAAC;IAE1D,IAAI,uBAAuB,CAAC,OAAc,CAAC,IAAI,UAAU,EAAE,CAAC;QAC1D,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IACzD,CAAC;IACD,gGAAgG;IAChG,gGAAgG;IAChG,+FAA+F;IAC/F,+FAA+F;IAC/F,IAAI,UAAU,IAAI,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC;QACvE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IACzD,CAAC;IACD,IAAI,YAAY,EAAE,CAAC;QACjB,kGAAkG;QAClG,sGAAsG;QACtG,OAAO,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAC,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;IACxG,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAAuB;IACxD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;QACzB,OAAO,kMAAkM,CAAC;IAC5M,CAAC;IACD,IAAI,IAAI,KAAK,uBAAuB,EAAE,CAAC;QACrC,OAAO,gQAAgQ,CAAC;IAC1Q,CAAC;IACD,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;QAC9B,OAAO,iIAAiI,CAAC;IAC3I,CAAC;IACD,OAAO,8FAA8F,CAAC;AACxG,CAAC;AAED;;wGAEwG;AACxG,MAAM,UAAU,iBAAiB,CAAC,IAAuB;IACvD,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,uBAAuB,CAAC;AAClE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexus-cortex/core",
3
- "version": "4.95.0",
3
+ "version": "4.96.1",
4
4
  "description": "Core orchestration library implementing Claude CLI architecture patterns",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -47,8 +47,8 @@
47
47
  "@google/generative-ai": "^0.2.1",
48
48
  "@gradio/client": "^2.3.1",
49
49
  "@modelcontextprotocol/sdk": "^1.20.2",
50
- "@nexus-cortex/executors": "4.95.0",
51
- "@nexus-cortex/types": "4.95.0",
50
+ "@nexus-cortex/executors": "4.96.1",
51
+ "@nexus-cortex/types": "4.96.1",
52
52
  "@types/uuid": "^10.0.0",
53
53
  "ajv": "^8.12.0",
54
54
  "chokidar": "^3.6.0",