@juspay/neurolink 12.41.6 → 12.41.8
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/CHANGELOG.md +2 -2
- package/dist/browser/neurolink.min.js +360 -356
- package/dist/cli/commands/models.js +16 -1
- package/dist/providers/catalog/fireworks.json +4 -3
- package/dist/providers/googleVertex/client.d.ts +217 -4
- package/dist/providers/googleVertex/client.js +650 -56
- package/dist/utils/modelChoices.d.ts +20 -0
- package/dist/utils/modelChoices.js +37 -4
- package/docs-site/static/search-index.json +3 -3
- package/package.json +2 -1
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { ModelResolver, formatSearchResults, formatRecommendation, formatComparison, } from "../../models/modelResolver.js";
|
|
7
7
|
import { getAllModels, getModelsByProvider, getAvailableProviders, formatModelForDisplay, } from "../../models/modelRegistry.js";
|
|
8
|
+
import { getCatalogJsonEntries } from "../../providers/catalog/loader.js";
|
|
8
9
|
import chalk from "chalk";
|
|
9
10
|
import ora from "ora";
|
|
10
11
|
import { logger } from "../../utils/logger.js";
|
|
@@ -334,9 +335,23 @@ export class ModelsCommandFactory {
|
|
|
334
335
|
try {
|
|
335
336
|
const { AIProviderFactory } = await import("../../core/factory.js");
|
|
336
337
|
const provider = (await AIProviderFactory.createProvider(providerName));
|
|
337
|
-
const
|
|
338
|
+
const rawLiveIds = typeof provider.getAvailableModels === "function"
|
|
338
339
|
? await provider.getAvailableModels()
|
|
339
340
|
: [];
|
|
341
|
+
// Project against the JSON catalog's non-retired ids, mirroring
|
|
342
|
+
// getAllModels()'s listing filter: a catalog-backed provider's
|
|
343
|
+
// vendor `/models` endpoint often keeps listing an id long after
|
|
344
|
+
// it 404s on chat completions (see e.g. fireworks.json's
|
|
345
|
+
// `evidence.liveMatrix`), so an unfiltered live listing would
|
|
346
|
+
// print a retired id as a usable "live" result. Providers with no
|
|
347
|
+
// catalog entry (litellm, ollama, openai-compatible gateways,
|
|
348
|
+
// lm-studio, llamacpp) have nothing to project against, so their
|
|
349
|
+
// live discovery stays unrestricted — that is the whole point of
|
|
350
|
+
// this fallback for them.
|
|
351
|
+
const catalogEntry = getCatalogJsonEntries().find((entry) => entry.id === providerName);
|
|
352
|
+
const liveIds = catalogEntry
|
|
353
|
+
? rawLiveIds.filter((id) => catalogEntry.models.catalog[id]?.status !== "retired")
|
|
354
|
+
: rawLiveIds;
|
|
340
355
|
if (liveIds.length > 0) {
|
|
341
356
|
if (spinner) {
|
|
342
357
|
spinner.succeed(`Found ${liveIds.length} models (live from ${providerName})`);
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"enumMember": "KIMI_K2P6",
|
|
24
24
|
"vision": false,
|
|
25
25
|
"status": "retired",
|
|
26
|
-
"description": "Retired 2026-09 — still on the Fireworks roster, but
|
|
26
|
+
"description": "Retired 2026-09 — still listed on the Fireworks /models roster, but the chat endpoint 404s 'Model not found, inaccessible, and/or not deployed' (since the 2026-09-26 nightly); superseded by kimi-k3, same Moonshot family"
|
|
27
27
|
},
|
|
28
28
|
"accounts/fireworks/models/gpt-oss-120b": {
|
|
29
29
|
"enumMember": "GPT_OSS_120B",
|
|
@@ -107,7 +107,8 @@
|
|
|
107
107
|
"topModels": [
|
|
108
108
|
"accounts/fireworks/models/kimi-k3",
|
|
109
109
|
"accounts/fireworks/models/gpt-oss-120b",
|
|
110
|
-
"accounts/fireworks/models/qwen3p8-max"
|
|
110
|
+
"accounts/fireworks/models/qwen3p8-max",
|
|
111
|
+
"accounts/fireworks/models/glm-5p3"
|
|
111
112
|
]
|
|
112
113
|
},
|
|
113
114
|
"capabilities": {
|
|
@@ -146,7 +147,7 @@
|
|
|
146
147
|
},
|
|
147
148
|
"liveMatrix": {
|
|
148
149
|
"date": "2026-09-28",
|
|
149
|
-
"result": "kimi-k2p6
|
|
150
|
+
"result": "Issue #1796: the 2026-09-26 nightly model-liveness gate reported the default, kimi-k2p6, as dead, sending the matrix vision test down the text-only fallback. Confirmed live — GET /models still lists kimi-k2p6, but POST /chat/completions 404s 'Model not found, inaccessible, and/or not deployed', the same still-listed-but-unservable pattern deepseek-v4-pro hit in 2026-08 (hung past 120s rather than 404ing). Moved the default to kimi-k3, the same Moonshot family's newest generation: 200 OK on both a text-only call and a call carrying a PNG, and a full-length call returns a proper OpenAI-shaped tool_calls entry with finish_reason=tool_calls, confirming vision and tool support both survive the swap. kimi-k2p6 marked retired rather than deleted, per the frozen-enum rule. gpt-oss-120b, qwen3p8-max and glm-5p3 (the rest of fallbacks/topModels) were re-probed alive at the same time; glm-5p3 still only answers text calls, not image ones, as found 2026-08-30."
|
|
150
151
|
},
|
|
151
152
|
"addedInPR": "https://github.com/juspay/neurolink/pull/1587"
|
|
152
153
|
}
|
|
@@ -172,6 +172,38 @@ export declare class GoogleVertexProvider extends BaseProvider {
|
|
|
172
172
|
* This bypasses @ai-sdk/google-vertex to properly handle thought_signature
|
|
173
173
|
*/
|
|
174
174
|
private executeNativeGemini3Stream;
|
|
175
|
+
/**
|
|
176
|
+
* Resolve the text a native Vertex *generate* call actually sends, for
|
|
177
|
+
* both `executeNativeGemini3Generate` and `executeNativeAnthropicGenerate`.
|
|
178
|
+
*
|
|
179
|
+
* The baseline here is the same `input.text || prompt || "Please
|
|
180
|
+
* respond."` chain both call sites have always used — `input.text` wins
|
|
181
|
+
* when set because the file preprocessors (`processUnifiedFilesArray`,
|
|
182
|
+
* `processCSVFilesForNativeSDK`) append attached-file content to it while
|
|
183
|
+
* `options.prompt` stays the pre-attachment snapshot; `prompt` is the
|
|
184
|
+
* fallback for the legacy prompt-only `generateText()` convention, which
|
|
185
|
+
* never sets `input` at all; the literal is the last resort when neither
|
|
186
|
+
* is set.
|
|
187
|
+
*
|
|
188
|
+
* That `||` chain alone has a gap model middleware falls into:
|
|
189
|
+
* `applyTurnParamsRewrite` writes every rewritten turn back onto
|
|
190
|
+
* `options.input.text`, including an *emptied* one (a redaction). `||`
|
|
191
|
+
* treats that empty string exactly like an unset `input.text` and falls
|
|
192
|
+
* through to `options.prompt` — which middleware never touched, since it
|
|
193
|
+
* is a plain snapshot taken before middleware ran — so a redaction a
|
|
194
|
+
* middleware applied is silently discarded and the ORIGINAL text still
|
|
195
|
+
* reaches Vertex.
|
|
196
|
+
*
|
|
197
|
+
* The fix is narrow: when `input.text` is *set* (not undefined) and
|
|
198
|
+
* differs from `prompt`, something deliberately changed it since the
|
|
199
|
+
* snapshot was taken — a middleware rewrite, or a file preprocessor's
|
|
200
|
+
* attachment-content append — and that divergence itself is the signal to
|
|
201
|
+
* trust `input.text` outright, empty string included. When the two agree
|
|
202
|
+
* (the untouched, no-middleware case, including the STT-silence
|
|
203
|
+
* `input.text === prompt === ""` placeholder) there is no divergence to
|
|
204
|
+
* trust, so the original fallback chain still applies unchanged.
|
|
205
|
+
*/
|
|
206
|
+
private resolveNativeGenerateText;
|
|
175
207
|
/**
|
|
176
208
|
* Execute generate using native @google/genai SDK for Gemini 3 models on Vertex AI
|
|
177
209
|
* This bypasses @ai-sdk/google-vertex to properly handle thought_signature
|
|
@@ -293,15 +325,196 @@ export declare class GoogleVertexProvider extends BaseProvider {
|
|
|
293
325
|
* `hasLifecycleErrorFired`) skips its own fire for the same failure.
|
|
294
326
|
*/
|
|
295
327
|
private wrapStreamResultWithLifecycle;
|
|
328
|
+
/**
|
|
329
|
+
* The text a native Vertex turn is built from before any model middleware
|
|
330
|
+
* rewrite — `options.input.text` when the caller set it (the normal
|
|
331
|
+
* `generate()`/`stream()` convention), else `options.prompt` (the legacy
|
|
332
|
+
* prompt-only `generateText()` convention, where `input` is never
|
|
333
|
+
* populated — see `generateTextInInstanceScope` in `src/lib/neurolink.ts`,
|
|
334
|
+
* which validates `options.prompt` and never touches `options.input`).
|
|
335
|
+
*
|
|
336
|
+
* `buildTurnPromptForMiddleware` and `applyTurnParamsRewrite` both read
|
|
337
|
+
* this so they agree on one baseline: the first so a prompt-only caller
|
|
338
|
+
* shows middleware its real text instead of an empty turn, the second so
|
|
339
|
+
* a middleware-rewritten turn is compared against what middleware actually
|
|
340
|
+
* started from — not a baseline that ignores `prompt` entirely, which
|
|
341
|
+
* would make a prompt-only call look "unedited" no matter what middleware
|
|
342
|
+
* did to it. `StreamOptions` carries no top-level `prompt` field, hence
|
|
343
|
+
* the `"prompt" in options` guard instead of a cast.
|
|
344
|
+
*/
|
|
345
|
+
private vertexTurnBaselineText;
|
|
346
|
+
/**
|
|
347
|
+
* Build the V3 entry-turn prompt middleware sees for a native call.
|
|
348
|
+
* Native Vertex loops build their own multi-turn conversation internally
|
|
349
|
+
* once they run — this is only the caller's system prompt + text input,
|
|
350
|
+
* the one turn middleware is given visibility into before that loop
|
|
351
|
+
* starts.
|
|
352
|
+
*
|
|
353
|
+
* The user turn is an array of text parts rather than a bare string. That
|
|
354
|
+
* is the V3 prompt shape, and prompt-editing middleware is written against
|
|
355
|
+
* it: one that spreads `content` into a longer array turns a string into
|
|
356
|
+
* one element per character, and one that calls `.map` / `.filter` on it
|
|
357
|
+
* throws. The AI Studio path already hands its middleware parts
|
|
358
|
+
* (`geminiContentsToV3Prompt`); this makes Vertex agree with it.
|
|
359
|
+
*
|
|
360
|
+
* The text itself comes from `vertexTurnBaselineText`, not
|
|
361
|
+
* `options.input?.text` alone — a prompt-only `generateText()` caller
|
|
362
|
+
* never sets `input`, and without the `options.prompt` fallback middleware
|
|
363
|
+
* would be shown an empty turn and have nothing of the caller's to inspect
|
|
364
|
+
* or build on.
|
|
365
|
+
*/
|
|
366
|
+
private buildTurnPromptForMiddleware;
|
|
367
|
+
/** Sampling params a native call already honors, carried onto the V3 view. */
|
|
368
|
+
private buildTurnV3Params;
|
|
369
|
+
/**
|
|
370
|
+
* Read a middleware-transformed prompt back into the two things a native
|
|
371
|
+
* Vertex turn can carry: one system instruction and one user text.
|
|
372
|
+
*
|
|
373
|
+
* Every system message counts (joined with a blank line, the way
|
|
374
|
+
* `v3PromptToGeminiContents` joins them for AI Studio) and so does every
|
|
375
|
+
* user message, not just the last. A middleware that appends or prepends
|
|
376
|
+
* context leaves the caller's own text in the prompt beside it; reading
|
|
377
|
+
* only the last user message would send the addition without the question
|
|
378
|
+
* it was meant to qualify, or drop it and send the question bare. Text
|
|
379
|
+
* blocks — across messages and across the parts of one message — are joined
|
|
380
|
+
* with a blank line for the same reason: they are separate blocks, and
|
|
381
|
+
* gluing them runs the last word of one into the first of the next.
|
|
382
|
+
*
|
|
383
|
+
* `unmapped` counts what a native turn has no place for — non-text user
|
|
384
|
+
* parts (files, images) and assistant or tool messages — so the caller can
|
|
385
|
+
* say it was dropped rather than drop it silently.
|
|
386
|
+
*/
|
|
387
|
+
private readTurnFromPrompt;
|
|
388
|
+
/**
|
|
389
|
+
* Apply a middleware-transformed turn back onto the native call options.
|
|
390
|
+
*
|
|
391
|
+
* The system instruction and the user text are each written back only when
|
|
392
|
+
* they differ from what middleware actually started from — `systemPrompt`
|
|
393
|
+
* against `options.systemPrompt`, user text against
|
|
394
|
+
* `vertexTurnBaselineText(options)`, not `options.input?.text` alone — so a
|
|
395
|
+
* middleware that touches neither leaves both exactly as they were. An
|
|
396
|
+
* edit is honoured in every direction — a changed, added or removed system
|
|
397
|
+
* message, an appended or prepended user message, a user message emptied
|
|
398
|
+
* outright (a redaction) — because every native generate/stream executor
|
|
399
|
+
* resolves its wire text through `options.input.text` once this write-back
|
|
400
|
+
* has run (`resolveNativeGenerateText` on the generate paths, which
|
|
401
|
+
* special-cases exactly this divergence so an emptied `input.text` is not
|
|
402
|
+
* mistaken for an unset one and does not fall back to the stale
|
|
403
|
+
* `options.prompt` snapshot; a direct `options.input.text` read on the
|
|
404
|
+
* stream paths, which have no such fallback to fall into). Comparing
|
|
405
|
+
* against `options.input?.text` alone — ignoring `options.prompt` — would
|
|
406
|
+
* make a prompt-only `generateText()` caller's untouched turn look
|
|
407
|
+
* "changed" the first time middleware ran (nothing to compare `turn.text`
|
|
408
|
+
* against but `""`), writing the real prompt into `input.text` as a
|
|
409
|
+
* spurious edit on every such call even when no middleware did anything.
|
|
410
|
+
*
|
|
411
|
+
* Sampling params are written back the same way and can be removed as well
|
|
412
|
+
* as changed: a middleware that drops `temperature` or `topP` from the
|
|
413
|
+
* params must reach the wire as "not sent", not as the caller's original
|
|
414
|
+
* value kept because the key went missing.
|
|
415
|
+
*
|
|
416
|
+
* `tools` is offered to middleware read-only — a middleware that rewrites
|
|
417
|
+
* it gets a WARN rather than a silent drop, matching the OpenAI-compatible
|
|
418
|
+
* streaming path's contract: native tool wiring is derived independently
|
|
419
|
+
* of this V3 view, and re-deriving it here would diverge from it.
|
|
420
|
+
*/
|
|
421
|
+
private applyTurnParamsRewrite;
|
|
422
|
+
/**
|
|
423
|
+
* Strip the lifecycle middleware from the options handed to
|
|
424
|
+
* `applyMiddlewareToModel` for a native Vertex call, when something else is
|
|
425
|
+
* already firing the same callbacks.
|
|
426
|
+
*
|
|
427
|
+
* NeuroLink's `applyGenerateLifecycleMiddleware` /
|
|
428
|
+
* `applyStreamLifecycleMiddleware` (neurolink.ts) mirror a caller's
|
|
429
|
+
* top-level `onFinish` / `onError` / `onChunk` into
|
|
430
|
+
* `options.middleware.middlewareConfig.lifecycle.config` — the exact same
|
|
431
|
+
* callback references — before this provider sees `options`. Left enabled,
|
|
432
|
+
* the built-in lifecycle middleware would fire them again from inside the
|
|
433
|
+
* bridge, and with malformed payloads: it reads the legacy `textDelta` chunk
|
|
434
|
+
* field and a bare `finishReason`, neither of which a V3 model produces.
|
|
435
|
+
*
|
|
436
|
+
* Who else fires them differs by path, so the exclusion does too:
|
|
437
|
+
*
|
|
438
|
+
* - generate: only `fireGenerateOnFinish` / `fireGenerateOnError`, which read
|
|
439
|
+
* the TOP-LEVEL callbacks. The entry is stripped only when one is present.
|
|
440
|
+
* A caller who configures `middlewareConfig.lifecycle` directly has no
|
|
441
|
+
* other firer here, so that middleware applies exactly once, unmodified.
|
|
442
|
+
* - stream: `BaseProvider.stream()` wraps every stream in
|
|
443
|
+
* `wrapStreamWithLifecycleCallbacks`, which fires whatever sits in
|
|
444
|
+
* `lifecycle.config` however it got there — top-level shorthand or direct
|
|
445
|
+
* config. The entry is stripped whenever it exists, or a direct-config
|
|
446
|
+
* caller would get every callback twice (and `onChunk` a third time, for
|
|
447
|
+
* the `finish` part the middleware also reports).
|
|
448
|
+
*
|
|
449
|
+
* Only the `lifecycle` entry is disabled, so every other configured
|
|
450
|
+
* middleware (guardrails, transformParams, custom hooks, analytics, ...)
|
|
451
|
+
* applies normally.
|
|
452
|
+
*/
|
|
453
|
+
private excludeAutoLifecycleMiddleware;
|
|
454
|
+
/**
|
|
455
|
+
* Run the native Gemini generate loop and, when Vertex rejects an
|
|
456
|
+
* over-constrained `responseSchema`, retry once without it.
|
|
457
|
+
*
|
|
458
|
+
* The retry sits inside the function `runNativeGenerateWithMiddleware` hands
|
|
459
|
+
* to the model bridge rather than around the bridge, because it is
|
|
460
|
+
* provider-internal recovery: model middleware must see one `doGenerate`
|
|
461
|
+
* that succeeds. Retrying outside would show every middleware the failed
|
|
462
|
+
* first call — the lifecycle middleware would report an `onError` for a
|
|
463
|
+
* request that then succeeded, and `transformParams` would run twice.
|
|
464
|
+
*/
|
|
465
|
+
private executeNativeGemini3GenerateWithSchemaFallback;
|
|
466
|
+
/**
|
|
467
|
+
* Apply the configured middleware chain around a native Vertex generate
|
|
468
|
+
* loop. `callNative` is `executeNativeAnthropicGenerate` or
|
|
469
|
+
* `executeNativeGemini3Generate` — a self-contained black box that runs
|
|
470
|
+
* its own multi-step tool loop and returns a fully-resolved
|
|
471
|
+
* `EnhancedGenerateResult`. Wrapping happens around that call, not inside
|
|
472
|
+
* it: `transformParams` can rewrite the entry turn before the loop starts,
|
|
473
|
+
* and `wrapGenerate` can observe the result or replace it outright (a
|
|
474
|
+
* guardrail that blocks the call entirely never reaches `callNative`, so
|
|
475
|
+
* `nativeResult` stays unset and a settled result is synthesized purely
|
|
476
|
+
* from what middleware produced, then run through `enhanceResult` like any
|
|
477
|
+
* other result so `enableAnalytics` / `enableEvaluation` still apply).
|
|
478
|
+
*/
|
|
479
|
+
private runNativeGenerateWithMiddleware;
|
|
480
|
+
/**
|
|
481
|
+
* Apply the configured middleware chain around a native Vertex stream
|
|
482
|
+
* loop. `callNative` is `executeNativeAnthropicStream` or
|
|
483
|
+
* `executeNativeGemini3Stream`. Both are bridged through the same lazy V3
|
|
484
|
+
* `ReadableStream` (`nativeChunksToV3Stream` / `v3StreamToNativeChunks`)
|
|
485
|
+
* regardless of whether the underlying loop is genuinely live (Anthropic)
|
|
486
|
+
* or already fully resolved (Gemini3) by the time it returns — pulling one
|
|
487
|
+
* item at a time is correct for both, and never turns a live stream into
|
|
488
|
+
* collect-then-replay.
|
|
489
|
+
*
|
|
490
|
+
* A guardrail that blocks the call never invokes `doStream`, so
|
|
491
|
+
* `nativeResult` stays unset; a `StreamResult` is synthesized instead,
|
|
492
|
+
* with `usage` / `finishReason` resolving once the merged stream is fully
|
|
493
|
+
* drained (the same late-resolving-getter contract
|
|
494
|
+
* `preserveStreamResultAccessors` already exists for).
|
|
495
|
+
*/
|
|
496
|
+
private runNativeStreamWithMiddleware;
|
|
296
497
|
/**
|
|
297
498
|
* Re-apply getter-based accessor properties from a source StreamResult onto
|
|
298
499
|
* a wrapper copy. Wrapper spreads (`{ ...result }`) invoke and SNAPSHOT
|
|
299
500
|
* enumerable getters at wrap time — for background-loop streams (the native
|
|
300
501
|
* Anthropic path) that resolve finishReason / structuredOutput / toolCalls
|
|
301
|
-
* only as the consumer drains, the snapshot is permanently
|
|
302
|
-
* Copying the accessor descriptors keeps the wrapped
|
|
303
|
-
* built from plain data properties (the buffered
|
|
304
|
-
*
|
|
502
|
+
* / usage only as the consumer drains, the snapshot is permanently
|
|
503
|
+
* undefined/empty. Copying the accessor descriptors keeps the wrapped
|
|
504
|
+
* result live. Results built from plain data properties (the buffered
|
|
505
|
+
* Gemini paths, and the native Anthropic stream's own `usage` — a mutable
|
|
506
|
+
* object reference rather than a getter, so a spread keeps its identity
|
|
507
|
+
* and later mutations stay visible) have no matching getter here and pass
|
|
508
|
+
* through untouched.
|
|
509
|
+
*
|
|
510
|
+
* The re-applied property also accepts a direct write: NeuroLink.stream()
|
|
511
|
+
* backstops a missing `usage` from analytics once the outer stream drains
|
|
512
|
+
* by assigning `mcpStreamOutcome.usage = resolvedUsage` on whatever result
|
|
513
|
+
* object it was handed. Copying the bare getter-only descriptor verbatim
|
|
514
|
+
* would turn that assignment into a TypeError ("Cannot set property usage
|
|
515
|
+
* of #<Object> which has only a getter"), so each re-applied accessor is
|
|
516
|
+
* rebuilt with a setter that remembers an override and prefers it over the
|
|
517
|
+
* live source getter once one has been written.
|
|
305
518
|
*/
|
|
306
519
|
private preserveStreamResultAccessors;
|
|
307
520
|
/**
|