@nexrall/code-core 1.4.51 → 1.4.56

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.
@@ -264,11 +264,22 @@ export declare function lastToolResults(messages: Message[], count: number, maxC
264
264
  /**
265
265
  * Context window (tokens) for a model alias or real model id.
266
266
  *
267
- * The fallback is deliberately the SMALLEST window in the table rather than the
268
- * largest. An unknown model is most likely a newly added one this client build
269
- * predates, and guessing high is the failure that cannot be recovered from: the
270
- * turn hits a provider 400 with no chance to compact. Guessing low only costs
271
- * an earlier, lossy compaction annoying, not broken.
267
+ * Checks the LIVE catalogue (GET /api/code/models, modelCatalogue.ts) first
268
+ * populated once per process by whichever client fetched it (CLI at session
269
+ * start, VS Code via _postModelCatalogue, desktop via its main-process
270
+ * fetch) falling back to this hard-coded table when no live data exists yet
271
+ * (offline, older backend, or the catalogue simply hasn't been fetched by
272
+ * this call site). This is what lets a model added to the backend registry
273
+ * (services/providers/modelRegistry.js) get the CORRECT context window here
274
+ * even before this table is updated by hand for a new nexrall-code release —
275
+ * exactly the class of bug GPT-5.6's 922K-vs-1.05M mismatch was (see
276
+ * modelRegistry.js's own comment on that row).
277
+ *
278
+ * The static-table fallback is deliberately the SMALLEST window in the table
279
+ * rather than the largest. An unknown model is most likely a newly added one
280
+ * this client build predates, and guessing high is the failure that cannot be
281
+ * recovered from: the turn hits a provider 400 with no chance to compact.
282
+ * Guessing low only costs an earlier, lossy compaction — annoying, not broken.
272
283
  */
273
284
  export declare function contextWindowFor(model?: string): number;
274
285
  /** Auto-prune / auto-compact thresholds as fractions of the context window — for UI display (e.g. `/context`). */
@@ -1 +1 @@
1
- {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
@@ -90,6 +90,7 @@ const claimEvidence_1 = require("./claimEvidence");
90
90
  const audit_1 = require("./audit");
91
91
  const memory_1 = require("./memory");
92
92
  const safeSlice_1 = require("../util/safeSlice");
93
+ const modelCatalogue_1 = require("./modelCatalogue");
93
94
  const fs = __importStar(require("fs"));
94
95
  const path = __importStar(require("path"));
95
96
  const child_process_1 = require("child_process");
@@ -809,6 +810,8 @@ function humanDescription(name, input) {
809
810
  return `Browser: type "${String(input.text ?? '').slice(0, 40)}"`;
810
811
  if (action === 'snapshot')
811
812
  return 'Browser: read page';
813
+ if (action === 'read_text')
814
+ return 'Browser: read page text';
812
815
  return `Browser: ${action || '(unknown action)'}`;
813
816
  }
814
817
  default:
@@ -1638,6 +1641,16 @@ const MODEL_CONTEXT_TOKENS = {
1638
1641
  'gpt-5.4-mini': 272000,
1639
1642
  'gpt-4.1': 1047576,
1640
1643
  'gpt-4o-mini': 128000,
1644
+ // GPT-5.6 family: MEASURED 2026-09-03 via a 400 (same technique as
1645
+ // gpt-5.4's 922_000 above) — and it is the EXACT SAME 922,000-token
1646
+ // ceiling on all three sizes. This CONTRADICTS the publicly documented
1647
+ // figure (openai.com/index/gpt-5-6 + OpenRouter's model card both
1648
+ // advertise 1,050,000) — see backend services/providers/modelRegistry.js's
1649
+ // own comment on these rows for the measured 400 body. Guessing 1.05M here
1650
+ // would fire auto-compaction ~12% past the real wall.
1651
+ 'gpt-5.6-sol': 922000,
1652
+ 'gpt-5.6-terra': 922000,
1653
+ 'gpt-5.6-luna': 922000,
1641
1654
  // DeepSeek, by real model id (documented — see backend/services/providers/
1642
1655
  // modelRegistry.js's own TODO(unverified-by-400): DeepSeek accepts an
1643
1656
  // oversized max_completion_tokens without rejecting it, so there was no 400
@@ -1646,18 +1659,38 @@ const MODEL_CONTEXT_TOKENS = {
1646
1659
  'deepseek-v4-flash': 1048576,
1647
1660
  // Qwen (DashScope), by real model id (documented max input, same caveat).
1648
1661
  'qwen3.7-max': 991800,
1662
+ // Z.ai (GLM), by real model id. contextWindow is documented (Z.ai/
1663
+ // Cloudflare Workers AI model cards, both list 1,048,576) rather than
1664
+ // measured — a ~400K-token request was ACCEPTED (200), not rejected, so
1665
+ // there was no 400 to read a real ceiling out of. maxOutputTokens IS
1666
+ // measured: `max_tokens: 999999` was rejected with the ceiling in the
1667
+ // error body (backend services/providers/modelRegistry.js's glm-5.3 row
1668
+ // has the full verification notes).
1669
+ 'glm-5.3': 1048576,
1649
1670
  };
1650
1671
  /**
1651
1672
  * Context window (tokens) for a model alias or real model id.
1652
1673
  *
1653
- * The fallback is deliberately the SMALLEST window in the table rather than the
1654
- * largest. An unknown model is most likely a newly added one this client build
1655
- * predates, and guessing high is the failure that cannot be recovered from: the
1656
- * turn hits a provider 400 with no chance to compact. Guessing low only costs
1657
- * an earlier, lossy compaction annoying, not broken.
1674
+ * Checks the LIVE catalogue (GET /api/code/models, modelCatalogue.ts) first
1675
+ * populated once per process by whichever client fetched it (CLI at session
1676
+ * start, VS Code via _postModelCatalogue, desktop via its main-process
1677
+ * fetch) falling back to this hard-coded table when no live data exists yet
1678
+ * (offline, older backend, or the catalogue simply hasn't been fetched by
1679
+ * this call site). This is what lets a model added to the backend registry
1680
+ * (services/providers/modelRegistry.js) get the CORRECT context window here
1681
+ * even before this table is updated by hand for a new nexrall-code release —
1682
+ * exactly the class of bug GPT-5.6's 922K-vs-1.05M mismatch was (see
1683
+ * modelRegistry.js's own comment on that row).
1684
+ *
1685
+ * The static-table fallback is deliberately the SMALLEST window in the table
1686
+ * rather than the largest. An unknown model is most likely a newly added one
1687
+ * this client build predates, and guessing high is the failure that cannot be
1688
+ * recovered from: the turn hits a provider 400 with no chance to compact.
1689
+ * Guessing low only costs an earlier, lossy compaction — annoying, not broken.
1658
1690
  */
1659
1691
  function contextWindowFor(model) {
1660
- return MODEL_CONTEXT_TOKENS[model ?? 'turbo'] ?? 128000;
1692
+ const fallback = MODEL_CONTEXT_TOKENS[model ?? 'turbo'] ?? 128000;
1693
+ return (0, modelCatalogue_1.liveContextWindowFor)(model, fallback);
1661
1694
  }
1662
1695
  // ── Compaction thresholds (cost control) ─────────────────────────────────────
1663
1696
  // Two independent triggers, deliberately at DIFFERENT levels:
@@ -2291,7 +2324,9 @@ async function compactMessagesForResume(messages, opts) {
2291
2324
  const settings = (0, rules_1.loadSettings)(opts.workDir);
2292
2325
  if (!resolveAutoCompact(undefined, settings.raw))
2293
2326
  return false;
2294
- const contextWindow = MODEL_CONTEXT_TOKENS[opts.model ?? 'turbo'] ?? 1000000;
2327
+ // Live catalogue first (see contextWindowFor's doc comment above for why),
2328
+ // same fallback chain this call site always used otherwise.
2329
+ const contextWindow = (0, modelCatalogue_1.liveContextWindowFor)(opts.model, MODEL_CONTEXT_TOKENS[opts.model ?? 'turbo'] ?? 1000000);
2295
2330
  let bodyBytes = estimateBodyBytes(messages);
2296
2331
  let tokenGuess = estimateTokensRough(messages);
2297
2332
  // Prune fires at the EARLY threshold (mirrors the in-loop guard); summarisation
@@ -2484,7 +2519,9 @@ async function runAgentLoop(initialMessages, options) {
2484
2519
  const autoContinue = resolveAutoContinue(options.autoContinue, settings.raw);
2485
2520
  const autoCompact = resolveAutoCompact(options.autoCompact, settings.raw);
2486
2521
  const verifyNudgeOn = resolveVerificationNudge(settings.raw);
2487
- const contextWindow = MODEL_CONTEXT_TOKENS[model] ?? 200000;
2522
+ // Live catalogue first (see contextWindowFor's doc comment above for why),
2523
+ // same fallback chain this call site always used otherwise.
2524
+ const contextWindow = (0, modelCatalogue_1.liveContextWindowFor)(model, MODEL_CONTEXT_TOKENS[model] ?? 200000);
2488
2525
  // Live prompt-size estimate, updated from usage events after every stream.
2489
2526
  let lastPromptTokens = 0;
2490
2527
  let compacting = false; // re-entrancy guard — compaction itself calls streamChat
@@ -0,0 +1,67 @@
1
+ import { type CodeModelInfo } from '../api/client';
2
+ /**
3
+ * Fetch (or return the cached) live model catalogue.
4
+ *
5
+ * Returns null on ANY failure (offline, older backend without the route,
6
+ * auth not ready) — callers MUST treat null as "use your static fallback",
7
+ * never as an error to surface to the user. A coding agent that refuses to
8
+ * start because a model-picker enrichment call failed would be a strictly
9
+ * worse product than one with a slightly stale menu.
10
+ *
11
+ * @param opts.force bypass the TTL and re-fetch even if a cached result
12
+ * exists — used by callers that know the cache might be stale (e.g. after
13
+ * reconnecting from an offline state).
14
+ */
15
+ export declare function getModelCatalogue(opts?: {
16
+ force?: boolean;
17
+ }): Promise<{
18
+ models: CodeModelInfo[];
19
+ defaultModel: string;
20
+ } | null>;
21
+ /** Synchronous read of whatever is currently cached, with NO fetch triggered. */
22
+ export declare function getCachedModelCatalogue(): {
23
+ models: CodeModelInfo[];
24
+ defaultModel: string;
25
+ } | null;
26
+ /**
27
+ * Live context window for `id`, or `fallback` when the catalogue has not
28
+ * been fetched yet or does not know this model.
29
+ */
30
+ export declare function liveContextWindowFor(id: string | undefined, fallback: number): number;
31
+ /** Live max-output-tokens for `id`, or `fallback`. */
32
+ export declare function liveMaxOutputTokensFor(id: string | undefined, fallback: number): number;
33
+ /**
34
+ * Live vision-support for `id`, or `fallback` when unknown. Callers pass
35
+ * their own static-table answer as `fallback` so a cache miss degrades to
36
+ * today's behaviour rather than a hardcoded guess.
37
+ */
38
+ export declare function liveSupportsImageInput(id: string | undefined, fallback: boolean): boolean;
39
+ /** Live PDF (native document-block) support for `id`, or `fallback`. */
40
+ export declare function liveSupportsPdfInput(id: string | undefined, fallback: boolean): boolean;
41
+ /** Live reasoning-effort style string for `id` (backend's raw value), or undefined. */
42
+ export declare function liveReasoningEffortStyle(id: string | undefined): string | undefined;
43
+ /**
44
+ * Live vendor label for `id` (e.g. 'Anthropic', 'OpenAI', 'DeepSeek'), or
45
+ * undefined when unknown. Needed alongside liveReasoningEffortStyle because
46
+ * the backend reports reasoningEffortStyle 'none' for EVERY Anthropic model
47
+ * (Claude has no `reasoning_effort` field at all — its lever is a separate
48
+ * mechanism), so callers that maintain a distinct "Anthropic" effort style
49
+ * locally must branch on vendor, not just the style string, to tell "this is
50
+ * Anthropic" apart from "this model genuinely has no effort concept"
51
+ * (gpt-4.1, gpt-4o-mini). Mirrors vscode/webview/main.js's applyModelCatalogue,
52
+ * which makes the identical vendor-based exception.
53
+ */
54
+ export declare function liveVendorFor(id: string | undefined): string | undefined;
55
+ /** Live display label for `id`, or `fallback` (typically the id itself). */
56
+ export declare function liveLabelFor(id: string | undefined, fallback: string): string;
57
+ /** Live relative cost multiplier for `id`, or `fallback` when unknown. */
58
+ export declare function liveCostMultiplierFor(id: string | undefined, fallback: number | undefined): number | undefined;
59
+ /**
60
+ * The list of selectable model ids the live catalogue offers, or null when
61
+ * no catalogue has been fetched yet — callers fall back to their own static
62
+ * SELECTABLE_MODELS list in that case.
63
+ */
64
+ export declare function liveSelectableModelIds(): string[] | null;
65
+ /** Test-only: reset the module-level cache between test cases. */
66
+ export declare function _resetModelCatalogueCacheForTests(): void;
67
+ //# sourceMappingURL=modelCatalogue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelCatalogue.d.ts","sourceRoot":"","sources":["../../src/agent/modelCatalogue.ts"],"names":[],"mappings":"AAgDA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AAiBlE;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAC7B,OAAO,CAAC;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAuBnE;AAED,iFAAiF;AACjF,wBAAgB,uBAAuB,IAAI;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAElG;AAOD;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAErF;AAED,sDAAsD;AACtD,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEvF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAGzF;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAGvF;AAED,uFAAuF;AACvF,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEnF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAExE;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE7E;AAED,0EAA0E;AAC1E,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAG9G;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,EAAE,GAAG,IAAI,CAExD;AAED,kEAAkE;AAClE,wBAAgB,iCAAiC,IAAI,IAAI,CAGxD"}
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ // ---------------------------------------------------------------------------
3
+ // Live model catalogue cache — ONE fetch, ONE cache, shared by CLI/VS
4
+ // Code/Desktop, all backed by GET /api/code/models (services/codeModels.js on
5
+ // the backend, itself sourced from services/providers/modelRegistry.js).
6
+ // ---------------------------------------------------------------------------
7
+ //
8
+ // WHY THIS FILE EXISTS
9
+ //
10
+ // Before this, "which models exist, what do they cost, do they support
11
+ // vision/PDF, what's their context window, what reasoning-effort style do
12
+ // they use" was answered by up to 8 separate hand-maintained tables spread
13
+ // across 4 packages (cli/chat.ts: MODEL_LABELS/SELECTABLE_MODELS/
14
+ // MODEL_COST_MULTIPLIER/NO_VISION_MODELS/NO_PDF_MODELS/MODEL_EFFORT_STYLE;
15
+ // vscode/ChatPanel.ts + webview/main.js: copies of most of the same;
16
+ // desktop/shared/modelCatalogue.ts + renderer/main.js: another copy, with the
17
+ // renderer's being a SECOND hand-copy of the first because esbuild does not
18
+ // bundle TS into that plain-JS file). Adding GLM-5.3 (2026-08-30) required
19
+ // editing 3 files by hand; adding GPT-5.6 (2026-09-03) required editing 7.
20
+ // A model added to the backend registry without also touching this repo
21
+ // simply never appears in the menu, and — the sharper failure mode —
22
+ // vision/PDF gating (NO_VISION_MODELS/NO_PDF_MODELS) could silently disagree
23
+ // with what the backend actually supports, since nothing enforced they track
24
+ // the SAME set as modelRegistry.js's supportsImageInput.
25
+ //
26
+ // This module is the fix: fetch the catalogue ONCE per process (TTL-cached,
27
+ // not re-fetched every turn), and expose lookup functions every call site can
28
+ // use INSTEAD OF a hand-maintained table. Every call site still needs a
29
+ // static fallback for offline/older-backend use — that is a deliberate,
30
+ // permanent feature of this design, not a gap: a coding agent must still
31
+ // work with no network. But the fallback should be the EXCEPTION path, not
32
+ // the only path, and it should never need to be edited when the fact it
33
+ // approximates has already been added on the backend.
34
+ //
35
+ // WHO CALLS THIS
36
+ //
37
+ // - CLI (chat.ts): fetches once at session start, before the model picker
38
+ // is ever shown.
39
+ // - VS Code (ChatPanel.ts): already fetched via getCodeModels() for its
40
+ // menu rebuild (_postModelCatalogue) — now ALSO feeds this cache so the
41
+ // same data drives vision/PDF gating, not just the menu's HTML.
42
+ // - Desktop (main process): fetches once, forwards the result to the
43
+ // renderer over IPC the same way ChatPanel.ts forwards it to its webview.
44
+ //
45
+ // This module does NOT talk to the network itself for freshness beyond the
46
+ // TTL — callers control WHEN to fetch (session start is enough; a model
47
+ // added mid-session is vanishingly rare and would need a restart to use
48
+ // safely anyway, since the picker itself is also static per-render).
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.getModelCatalogue = getModelCatalogue;
51
+ exports.getCachedModelCatalogue = getCachedModelCatalogue;
52
+ exports.liveContextWindowFor = liveContextWindowFor;
53
+ exports.liveMaxOutputTokensFor = liveMaxOutputTokensFor;
54
+ exports.liveSupportsImageInput = liveSupportsImageInput;
55
+ exports.liveSupportsPdfInput = liveSupportsPdfInput;
56
+ exports.liveReasoningEffortStyle = liveReasoningEffortStyle;
57
+ exports.liveVendorFor = liveVendorFor;
58
+ exports.liveLabelFor = liveLabelFor;
59
+ exports.liveCostMultiplierFor = liveCostMultiplierFor;
60
+ exports.liveSelectableModelIds = liveSelectableModelIds;
61
+ exports._resetModelCatalogueCacheForTests = _resetModelCatalogueCacheForTests;
62
+ const client_1 = require("../api/client");
63
+ /** How long a successful fetch is trusted before a caller should re-fetch. */
64
+ const CACHE_TTL_MS = 5 * 60 * 1000; // 5 minutes — matches backend's own getPricing() TTL
65
+ let _state = null;
66
+ // Coalesce concurrent callers into ONE in-flight fetch rather than one each —
67
+ // several call sites (CLI startup, a background re-check) could race on
68
+ // process boot otherwise, each paying the round-trip independently.
69
+ let _inFlight = null;
70
+ /**
71
+ * Fetch (or return the cached) live model catalogue.
72
+ *
73
+ * Returns null on ANY failure (offline, older backend without the route,
74
+ * auth not ready) — callers MUST treat null as "use your static fallback",
75
+ * never as an error to surface to the user. A coding agent that refuses to
76
+ * start because a model-picker enrichment call failed would be a strictly
77
+ * worse product than one with a slightly stale menu.
78
+ *
79
+ * @param opts.force bypass the TTL and re-fetch even if a cached result
80
+ * exists — used by callers that know the cache might be stale (e.g. after
81
+ * reconnecting from an offline state).
82
+ */
83
+ async function getModelCatalogue(opts = {}) {
84
+ const fresh = _state && Date.now() - _state.fetchedAt < CACHE_TTL_MS;
85
+ if (fresh && !opts.force)
86
+ return _state;
87
+ if (_inFlight)
88
+ return _inFlight;
89
+ _inFlight = (async () => {
90
+ try {
91
+ const { models, defaultModel } = await (0, client_1.getCodeModels)();
92
+ if (!models.length)
93
+ return _state; // empty response — keep any existing cache rather than blanking it
94
+ const next = { models, defaultModel, fetchedAt: Date.now() };
95
+ _state = next;
96
+ return next;
97
+ }
98
+ catch {
99
+ // Network/auth failure: keep serving the last good cache if one
100
+ // exists (better a slightly stale menu than none), else null.
101
+ return _state;
102
+ }
103
+ finally {
104
+ _inFlight = null;
105
+ }
106
+ })();
107
+ return _inFlight;
108
+ }
109
+ /** Synchronous read of whatever is currently cached, with NO fetch triggered. */
110
+ function getCachedModelCatalogue() {
111
+ return _state;
112
+ }
113
+ function findModel(id) {
114
+ if (!id || !_state)
115
+ return undefined;
116
+ return _state.models.find((m) => m.id === id);
117
+ }
118
+ /**
119
+ * Live context window for `id`, or `fallback` when the catalogue has not
120
+ * been fetched yet or does not know this model.
121
+ */
122
+ function liveContextWindowFor(id, fallback) {
123
+ return findModel(id)?.contextWindow ?? fallback;
124
+ }
125
+ /** Live max-output-tokens for `id`, or `fallback`. */
126
+ function liveMaxOutputTokensFor(id, fallback) {
127
+ return findModel(id)?.maxOutputTokens ?? fallback;
128
+ }
129
+ /**
130
+ * Live vision-support for `id`, or `fallback` when unknown. Callers pass
131
+ * their own static-table answer as `fallback` so a cache miss degrades to
132
+ * today's behaviour rather than a hardcoded guess.
133
+ */
134
+ function liveSupportsImageInput(id, fallback) {
135
+ const m = findModel(id);
136
+ return m ? m.supportsImageInput : fallback;
137
+ }
138
+ /** Live PDF (native document-block) support for `id`, or `fallback`. */
139
+ function liveSupportsPdfInput(id, fallback) {
140
+ const m = findModel(id);
141
+ return m ? m.supportsPdfInput : fallback;
142
+ }
143
+ /** Live reasoning-effort style string for `id` (backend's raw value), or undefined. */
144
+ function liveReasoningEffortStyle(id) {
145
+ return findModel(id)?.reasoningEffortStyle;
146
+ }
147
+ /**
148
+ * Live vendor label for `id` (e.g. 'Anthropic', 'OpenAI', 'DeepSeek'), or
149
+ * undefined when unknown. Needed alongside liveReasoningEffortStyle because
150
+ * the backend reports reasoningEffortStyle 'none' for EVERY Anthropic model
151
+ * (Claude has no `reasoning_effort` field at all — its lever is a separate
152
+ * mechanism), so callers that maintain a distinct "Anthropic" effort style
153
+ * locally must branch on vendor, not just the style string, to tell "this is
154
+ * Anthropic" apart from "this model genuinely has no effort concept"
155
+ * (gpt-4.1, gpt-4o-mini). Mirrors vscode/webview/main.js's applyModelCatalogue,
156
+ * which makes the identical vendor-based exception.
157
+ */
158
+ function liveVendorFor(id) {
159
+ return findModel(id)?.vendor;
160
+ }
161
+ /** Live display label for `id`, or `fallback` (typically the id itself). */
162
+ function liveLabelFor(id, fallback) {
163
+ return findModel(id)?.label ?? fallback;
164
+ }
165
+ /** Live relative cost multiplier for `id`, or `fallback` when unknown. */
166
+ function liveCostMultiplierFor(id, fallback) {
167
+ const m = findModel(id);
168
+ return m && typeof m.costMultiplier === 'number' ? m.costMultiplier : fallback;
169
+ }
170
+ /**
171
+ * The list of selectable model ids the live catalogue offers, or null when
172
+ * no catalogue has been fetched yet — callers fall back to their own static
173
+ * SELECTABLE_MODELS list in that case.
174
+ */
175
+ function liveSelectableModelIds() {
176
+ return _state ? _state.models.filter((m) => m.available !== false).map((m) => m.id) : null;
177
+ }
178
+ /** Test-only: reset the module-level cache between test cases. */
179
+ function _resetModelCatalogueCacheForTests() {
180
+ _state = null;
181
+ _inFlight = null;
182
+ }
183
+ //# sourceMappingURL=modelCatalogue.js.map
@@ -131,6 +131,26 @@ export interface DescribeAttachmentResult {
131
131
  }
132
132
  export declare function describeAttachment(kind: 'image' | 'pdf', data: string, mediaType?: string, name?: string): Promise<DescribeAttachmentResult>;
133
133
  export declare function getBalance(): Promise<number>;
134
+ export interface CodeModelInfo {
135
+ id: string;
136
+ label: string;
137
+ vendor: string;
138
+ blurb: string;
139
+ costMultiplier?: number;
140
+ contextWindow: number;
141
+ maxOutputTokens: number;
142
+ supportsImageInput: boolean;
143
+ supportsPdfInput: boolean;
144
+ supportsWebSearch: boolean;
145
+ /** One of modelRegistry.js's REASONING_EFFORT_STYLE values, or absent for 'none'. */
146
+ reasoningEffortStyle?: string;
147
+ /** False when this deployment has no credential configured for the model's provider. */
148
+ available: boolean;
149
+ }
150
+ export declare function getCodeModels(): Promise<{
151
+ models: CodeModelInfo[];
152
+ defaultModel: string;
153
+ }>;
134
154
  export interface UsageDailyDay {
135
155
  date: string;
136
156
  total: number;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ exports.cancelTurn = cancelTurn;
10
10
  exports.revokeRefreshToken = revokeRefreshToken;
11
11
  exports.describeAttachment = describeAttachment;
12
12
  exports.getBalance = getBalance;
13
+ exports.getCodeModels = getCodeModels;
13
14
  exports.getUsageDaily = getUsageDaily;
14
15
  exports.exchangeVscodeCode = exchangeVscodeCode;
15
16
  exports.login = login;
@@ -212,6 +213,42 @@ function isExpiredTokenResponse(status, body) {
212
213
  const MAX_RETRIES = 5;
213
214
  const RETRY_BASE_MS = 1000;
214
215
  const RETRY_MAX_MS = 30000;
216
+ /**
217
+ * SSE frames that are backend HOUSEKEEPING, not model output.
218
+ *
219
+ * These decide which STALL LIMIT a turn is held to: the generous time-to-first-token
220
+ * allowance (300 s) while the upstream is still processing the prompt, or the tighter
221
+ * mid-stream one (150 s) once tokens are flowing. See the `sawModelEvent` assignment
222
+ * in the parser for the full story.
223
+ *
224
+ * They are emitted by routes/code.js BEFORE (or independently of) the upstream model
225
+ * call, so their arrival proves only that the BACKEND is alive — never that the MODEL
226
+ * has started responding:
227
+ *
228
+ * resumable — turn registered + frame numbering announced. Emitted at
229
+ * routes/code.js:1151; openStream() is not called until :1318.
230
+ * This one alone held every production turn to the 150 s
231
+ * mid-stream limit during prompt processing.
232
+ * context_warning — server-side history trim/compact, already handled server-side.
233
+ * tool_progress — a liveness ping during long tool-argument generation.
234
+ *
235
+ * DELIBERATELY NOT LISTED (they mean the model really has started responding, and MUST
236
+ * count): text, thinking, thinking_delta, thinking_progress, tool_use,
237
+ * tool_result_info, message_complete, usage, balance_status, done, error.
238
+ *
239
+ * `thinking_progress` counts on purpose: it is derived from tokens the model has
240
+ * actually emitted, so time-to-first-token is genuinely over by then.
241
+ *
242
+ * Kept as an explicit ALLOWLIST of things to ignore rather than a denylist of things
243
+ * that count: a new backend frame type then defaults to "the model is responding",
244
+ * whose worst case is holding a turn to the tighter stall limit — visible and
245
+ * self-correcting, unlike the silent 300 s→150 s downgrade this list exists to stop.
246
+ */
247
+ const HOUSEKEEPING_FRAMES = new Set([
248
+ 'resumable',
249
+ 'context_warning',
250
+ 'tool_progress',
251
+ ]);
215
252
  /**
216
253
  * Wall-clock ceiling on ALL reconnect effort for a single streamChat() call.
217
254
  *
@@ -436,7 +473,21 @@ async function streamChat(messages, options, onEvent) {
436
473
  // see it. We detect it in the parser and retry the WHOLE attempt with exponential backoff
437
474
  // — but only while nothing has been emitted to the caller yet, so a retry can never
438
475
  // duplicate already-rendered text or tool calls.
439
- const isRetryableStreamMsg = (m) => /overloaded|rate.?limit|temporarily|unavailable|try again|internal server error/i.test(String(m ?? ''));
476
+ const isRetryableStreamMsg = (m) => {
477
+ const s = String(m ?? '');
478
+ // Anthropic's intermittent upstream refusal, reproduced verbatim through the AI
479
+ // Gateway passthrough:
480
+ // 403 {"error":{"type":"forbidden","message":"Request not allowed"}}
481
+ // Sporadic and gone on retry rather than a real permissions failure. A modern
482
+ // backend now flags this explicitly (`retryable` on the error frame), which is the
483
+ // reliable signal; this pattern is the FALLBACK for older backends that don't,
484
+ // and is deliberately narrow — it requires the upstream's own `"type":"forbidden"`
485
+ // envelope, so Nexrall's own auth 403s (a completely different body) stay terminal
486
+ // and a genuinely revoked key is still bounded by the capped retry budget.
487
+ if (/403[\s\S]*"type"\s*:\s*"forbidden"/i.test(s))
488
+ return true;
489
+ return /overloaded|rate.?limit|temporarily|unavailable|try again|internal server error/i.test(s);
490
+ };
440
491
  // Tracks whether a "reconnecting…" signal has been shown to the caller so we know to
441
492
  // clear it (retry_resolved) once real data starts flowing again. Shared across both
442
493
  // the connect-time retry loop and the outer stream-retry loop below, and across a
@@ -1055,10 +1106,35 @@ async function streamChat(messages, options, onEvent) {
1055
1106
  return;
1056
1107
  }
1057
1108
  const evt = parsed;
1058
- // Reaching here means a well-formed model event was parsed (": ping" keepalive
1109
+ // Reaching here means a well-formed frame was parsed (": ping" keepalive
1059
1110
  // comments never produce a ParsedEvent with data) — count it as real progress.
1111
+ //
1112
+ // `lastProgressAt` is bumped for EVERY frame, including the housekeeping ones
1113
+ // below: they prove the backend is alive and talking to us, which is exactly
1114
+ // what the stall watchdog measures.
1060
1115
  lastProgressAt = Date.now();
1061
- sawModelEvent = true;
1116
+ // …but `sawModelEvent` means something STRICTLY NARROWER: "the upstream model
1117
+ // has started responding". It selects which stall limit applies — the generous
1118
+ // time-to-first-token allowance (FIRST_EVENT_TIMEOUT_MS, 300 s) or the tighter
1119
+ // mid-stream one (PROGRESS_TIMEOUT_MS, 150 s) — so it must not be flipped by a
1120
+ // frame the BACKEND sent on its own initiative.
1121
+ //
1122
+ // routes/code.js emits `resumable` as soon as the turn is registered
1123
+ // (line ~1151) — BEFORE it calls openStream() (line ~1318), i.e. before the
1124
+ // model has been asked anything at all. Counting that as "the model is
1125
+ // responding" downgraded every turn to the 150 s mid-stream limit while the
1126
+ // upstream was still doing prompt processing, which is exactly the phase that
1127
+ // legitimately needs 300 s on a large cold-cache context. The result was
1128
+ // spurious stalls on big conversations that then "worked on retry" — because
1129
+ // the first attempt had warmed the prompt cache.
1130
+ //
1131
+ // NOTE: this flag deliberately no longer gates the empty-turn recovery in
1132
+ // `stream.on('end')`. That check now asks what the turn actually PRODUCED
1133
+ // (see `producedNothing` there), because "a frame arrived" and "content
1134
+ // exists" are different questions — conflating them is what made that guard
1135
+ // dead code in production.
1136
+ if (!HOUSEKEEPING_FRAMES.has(evt.type))
1137
+ sawModelEvent = true;
1062
1138
  // Real data is flowing again — clear any "reconnecting…" indicator the caller
1063
1139
  // may be showing from an earlier retry on THIS same attempt.
1064
1140
  clearRetryIfNeeded();
@@ -1249,6 +1325,26 @@ async function streamChat(messages, options, onEvent) {
1249
1325
  // — so this always needs a fresh turnId, which the outer loop mints via
1250
1326
  // `forceRestart`.
1251
1327
  const notResumable = evt.notResumable === true;
1328
+ // Does the BACKEND say this is worth retrying? Set by routes/code.js from
1329
+ // the upstream HTTP STATUS (403/408/409/429/5xx and bare transport
1330
+ // failures — see isTransientUpstreamError there), which is information
1331
+ // only the server has and which no amount of reading the message text can
1332
+ // reliably recover.
1333
+ //
1334
+ // This closes a real hole. `res.flushHeaders()` runs before the model is
1335
+ // called, so the HTTP status is pinned at 200 and an upstream failure can
1336
+ // only arrive as this frame — making the connect-time 403 retry logic
1337
+ // below unreachable in production. The only remaining hook was
1338
+ // `isRetryableStreamMsg`, whose regex does NOT match the string Anthropic
1339
+ // actually emits (`403 {"error":{"type":"forbidden",…}}`), so an
1340
+ // intermittent upstream refusal killed the run with a raw `⚠️ 403 …`
1341
+ // instead of being retried. Same lesson as `notResumable` directly above:
1342
+ // read a flag the server sets deliberately, never English prose.
1343
+ //
1344
+ // OR'd with the legacy text match rather than replacing it, so a client
1345
+ // running against an older backend that doesn't send the flag keeps
1346
+ // exactly its current behaviour.
1347
+ const serverSaysRetryable = evt.retryable === true;
1252
1348
  // Transient upstream failure before any output → let the outer loop retry it
1253
1349
  // transparently instead of killing the turn (this is the "Overloaded" case).
1254
1350
  // But never retry once the turn's message has already been delivered in
@@ -1265,7 +1361,7 @@ async function streamChat(messages, options, onEvent) {
1265
1361
  stream.destroy?.();
1266
1362
  reject(Object.assign(tagTransient(new Error(message)), { forceRestart: true }));
1267
1363
  }
1268
- else if (isRetryableStreamMsg(message) && (!emittedToCaller || allowRestartAfterRender)) {
1364
+ else if ((serverSaysRetryable || isRetryableStreamMsg(message)) && (!emittedToCaller || allowRestartAfterRender)) {
1269
1365
  clearInterval(heartbeatWatchdog);
1270
1366
  stream.destroy?.();
1271
1367
  reject(tagTransient(new Error(message)));
@@ -1298,12 +1394,34 @@ async function streamChat(messages, options, onEvent) {
1298
1394
  });
1299
1395
  stream.on('end', () => {
1300
1396
  clearInterval(heartbeatWatchdog);
1301
- // A clean 'end' with ZERO model events means the connection was dropped before
1302
- // the backend produced anything (deploy restart, proxy reset). Without this,
1303
- // the fallback below returns an EMPTY assistant message and the agent loop
1304
- // treats it as a silent no-op the turn just vanishes. Nothing was emitted,
1305
- // so a retry cannot duplicate output tag retryable.
1306
- if (!sawModelEvent && !completedMessage) {
1397
+ // A clean 'end' that produced NOTHING USABLE means the turn died before the
1398
+ // model committed any content (deploy restart, proxy reset, upstream refusal).
1399
+ // Without this, the fallback below returns an EMPTY assistant message and the
1400
+ // agent loop reports "⚠️ The model returned an empty response" telling the
1401
+ // user to send "continue" by hand to do the retry that belongs here.
1402
+ //
1403
+ // The condition is deliberately "produced no usable content", NOT "saw no
1404
+ // frames". Those are different, and the difference is the whole bug:
1405
+ //
1406
+ // • `resumable` / `context_warning` / `tool_progress` are emitted by
1407
+ // routes/code.js BEFORE (or independently of) the model call, so keying on
1408
+ // "any frame arrived" made this guard dead code on every production turn —
1409
+ // `resumable` alone is sent at routes/code.js:1151, while openStream() is
1410
+ // not reached until :1318.
1411
+ // • `thinking_progress` is the subtler half: it IS real evidence the model is
1412
+ // working (it counts tokens the model emitted), so classifying frames by
1413
+ // name would keep it "counting" — yet thinking tokens are stripped from
1414
+ // history, so a turn that dies there still has zero content and still
1415
+ // surfaces as an empty response. Frame-name classification cannot express
1416
+ // that; asking what the turn actually PRODUCED can.
1417
+ //
1418
+ // Retrying is safe precisely because there is no content: with nothing
1419
+ // accumulated, a fresh attempt cannot duplicate anything on screen. Anything
1420
+ // already rendered (text/tool_use) leaves `textParts`/`toolUseBlocks` non-empty
1421
+ // and takes the normal resolve path, so a real partial answer is never
1422
+ // discarded or re-billed.
1423
+ const producedNothing = !completedMessage && textParts.length === 0 && toolUseBlocks.length === 0;
1424
+ if (producedNothing) {
1307
1425
  reject(Object.assign(new Error('Connection closed before the model responded. Retrying…'), { retryable: true }));
1308
1426
  return;
1309
1427
  }
@@ -1546,6 +1664,28 @@ async function getBalance() {
1546
1664
  const data = (await response.json());
1547
1665
  return typeof data.balance === 'number' ? data.balance : 0;
1548
1666
  }
1667
+ async function getCodeModels() {
1668
+ const fetchOnce = () => (0, node_fetch_1.default)(`${exports.API_BASE}/api/code/models`, { method: 'GET', headers: authHeaders() });
1669
+ let response = await fetchOnce();
1670
+ if (response.status === 401 || response.status === 403) {
1671
+ const body = await response.text().catch(() => '');
1672
+ if (isExpiredTokenResponse(response.status, body) && await refreshAccessToken()) {
1673
+ response = await fetchOnce();
1674
+ }
1675
+ else {
1676
+ throw new Error(`API error ${response.status}: ${body}`);
1677
+ }
1678
+ }
1679
+ if (!response.ok) {
1680
+ const errText = await response.text();
1681
+ throw new Error(`API error ${response.status}: ${errText}`);
1682
+ }
1683
+ const data = (await response.json());
1684
+ return {
1685
+ models: Array.isArray(data.models) ? data.models : [],
1686
+ defaultModel: typeof data.defaultModel === 'string' ? data.defaultModel : 'claude-sonnet-5',
1687
+ };
1688
+ }
1549
1689
  /**
1550
1690
  * Day-by-day spend breakdown, same endpoint the web app's Settings > Usage
1551
1691
  * chart reads (backend/routes/user.js's /usage-daily). Used by Nexrall Work's
package/dist/index.d.ts CHANGED
@@ -3,6 +3,7 @@ export * from './auth/index';
3
3
  export * from './api/client';
4
4
  export * from './tools/executor';
5
5
  export * from './agent/loop';
6
+ export * from './agent/modelCatalogue';
6
7
  export * from './agent/testIntegrity';
7
8
  export * from './agent/editCompleteness';
8
9
  export * from './agent/securityLint';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC;AACtC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uBAAuB,CAAC;AACtC,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,eAAe,CAAC"}
package/dist/index.js CHANGED
@@ -19,6 +19,7 @@ __exportStar(require("./auth/index"), exports);
19
19
  __exportStar(require("./api/client"), exports);
20
20
  __exportStar(require("./tools/executor"), exports);
21
21
  __exportStar(require("./agent/loop"), exports);
22
+ __exportStar(require("./agent/modelCatalogue"), exports);
22
23
  __exportStar(require("./agent/testIntegrity"), exports);
23
24
  __exportStar(require("./agent/editCompleteness"), exports);
24
25
  __exportStar(require("./agent/securityLint"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexrall/code-core",
3
- "version": "1.4.51",
3
+ "version": "1.4.56",
4
4
  "description": "Core agent loop, tools, and extension primitives for Nexrall Code \u2014 embed an AI coding agent in any Node.js application.",
5
5
  "license": "MIT",
6
6
  "author": "Nexrall <support@nexrall.com> (https://nexrall.com)",