@juspay/neurolink 12.44.0 → 12.44.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.
- package/CHANGELOG.md +4 -3
- package/dist/browser/neurolink.min.js +378 -378
- package/dist/neurolink.d.ts +13 -0
- package/dist/neurolink.js +57 -2
- package/dist/utils/decisionBatches.d.ts +24 -0
- package/dist/utils/decisionBatches.js +58 -0
- package/dist/utils/logSanitize.js +12 -0
- package/docs-site/static/search-index.json +2 -2
- package/package.json +1 -1
package/dist/neurolink.d.ts
CHANGED
|
@@ -2427,8 +2427,21 @@ export declare class NeuroLink {
|
|
|
2427
2427
|
* that is unconfigured, slow, rate-limited or down must never change
|
|
2428
2428
|
* NeuroLink's observable behaviour — the caller falls back to whatever it
|
|
2429
2429
|
* did before the decision was available.
|
|
2430
|
+
*
|
|
2431
|
+
* It also takes more questions than a provider's per-request cap: the map is
|
|
2432
|
+
* split at the cap, the batches run a few at a time, and the answers come
|
|
2433
|
+
* back joined. A batch that fails costs only its own answers, which every
|
|
2434
|
+
* consumer already reads as "no decision"; null comes back only when every
|
|
2435
|
+
* batch failed. `decide()` itself stays strict and refuses an over-cap request.
|
|
2430
2436
|
*/
|
|
2431
2437
|
tryDecide(options: DecisionOptions): Promise<DecisionResult | null>;
|
|
2438
|
+
/**
|
|
2439
|
+
* One `decide()` call, or, when the question map is longer than the resolved
|
|
2440
|
+
* provider's cap, several run a few at a time with their results joined. The
|
|
2441
|
+
* provider is resolved here exactly as `decide()` resolves it, so the cap that
|
|
2442
|
+
* is read is the cap of the provider that will answer.
|
|
2443
|
+
*/
|
|
2444
|
+
private decideInBatches;
|
|
2432
2445
|
/**
|
|
2433
2446
|
* Evaluate an AI response using the specified pipeline or scorers.
|
|
2434
2447
|
* This is a convenience method that creates a pipeline and executes it in one call.
|
package/dist/neurolink.js
CHANGED
|
@@ -30,7 +30,8 @@ import { buildToolRoutingCatalog, buildRoutingQueryFromHistory, resolveToolRouti
|
|
|
30
30
|
import { ToolRoutingCache } from "./core/toolRoutingCache.js";
|
|
31
31
|
import { DEFAULT_RECENT_TURNS, KnowledgeGroundingEngine, } from "./knowledge/index.js";
|
|
32
32
|
import { AIProviderFactory } from "./core/factory.js";
|
|
33
|
-
import { describeDecisionProviderKeys, resolveDefaultDecisionProvider, } from "./factories/providerDescriptors.js";
|
|
33
|
+
import { describeDecisionProviderKeys, PROVIDER_ALIAS_INDEX, PROVIDER_DESCRIPTORS_BY_NAME, resolveDefaultDecisionProvider, } from "./factories/providerDescriptors.js";
|
|
34
|
+
import { MAX_PARALLEL_DECISION_BATCHES, mergeDecisionResults, splitDecisionRequest, } from "./utils/decisionBatches.js";
|
|
34
35
|
import { resolveRequestKind } from "./core/resolveRequestKind.js";
|
|
35
36
|
import { createToolEventPayload } from "./core/toolEvents.js";
|
|
36
37
|
import { ProviderFactory } from "./factories/providerFactory.js";
|
|
@@ -13080,10 +13081,16 @@ Current user's request: ${currentInput}`;
|
|
|
13080
13081
|
* that is unconfigured, slow, rate-limited or down must never change
|
|
13081
13082
|
* NeuroLink's observable behaviour — the caller falls back to whatever it
|
|
13082
13083
|
* did before the decision was available.
|
|
13084
|
+
*
|
|
13085
|
+
* It also takes more questions than a provider's per-request cap: the map is
|
|
13086
|
+
* split at the cap, the batches run a few at a time, and the answers come
|
|
13087
|
+
* back joined. A batch that fails costs only its own answers, which every
|
|
13088
|
+
* consumer already reads as "no decision"; null comes back only when every
|
|
13089
|
+
* batch failed. `decide()` itself stays strict and refuses an over-cap request.
|
|
13083
13090
|
*/
|
|
13084
13091
|
async tryDecide(options) {
|
|
13085
13092
|
try {
|
|
13086
|
-
const result = await this.
|
|
13093
|
+
const result = await this.decideInBatches(options);
|
|
13087
13094
|
if (logger.shouldLog("debug")) {
|
|
13088
13095
|
logger.debug(`decide: ${Object.keys(result.answers).length} answers in ${result.latencyMs}ms` +
|
|
13089
13096
|
(result.upstreamMs ? ` (upstream ${result.upstreamMs}ms)` : ""), {
|
|
@@ -13100,6 +13107,54 @@ Current user's request: ${currentInput}`;
|
|
|
13100
13107
|
return null;
|
|
13101
13108
|
}
|
|
13102
13109
|
}
|
|
13110
|
+
/**
|
|
13111
|
+
* One `decide()` call, or, when the question map is longer than the resolved
|
|
13112
|
+
* provider's cap, several run a few at a time with their results joined. The
|
|
13113
|
+
* provider is resolved here exactly as `decide()` resolves it, so the cap that
|
|
13114
|
+
* is read is the cap of the provider that will answer.
|
|
13115
|
+
*/
|
|
13116
|
+
async decideInBatches(options) {
|
|
13117
|
+
const providerName = options.provider ??
|
|
13118
|
+
resolveDefaultDecisionProvider(this.resolveCredentials(options.credentials));
|
|
13119
|
+
// The name a caller passes may be an alias (`jev` for `typesafe`), so it is
|
|
13120
|
+
// resolved to the canonical provider before its descriptor is read.
|
|
13121
|
+
const canonical = providerName
|
|
13122
|
+
? PROVIDER_ALIAS_INDEX.get(providerName.toLowerCase())
|
|
13123
|
+
: undefined;
|
|
13124
|
+
const cap = canonical
|
|
13125
|
+
? PROVIDER_DESCRIPTORS_BY_NAME.get(canonical)?.decisionLimits
|
|
13126
|
+
?.maxQuestions
|
|
13127
|
+
: undefined;
|
|
13128
|
+
const batches = splitDecisionRequest(options, cap);
|
|
13129
|
+
if (batches.length === 1) {
|
|
13130
|
+
return this.decide(options);
|
|
13131
|
+
}
|
|
13132
|
+
const answered = [];
|
|
13133
|
+
let firstFailure;
|
|
13134
|
+
for (let from = 0; from < batches.length; from += MAX_PARALLEL_DECISION_BATCHES) {
|
|
13135
|
+
const settled = await Promise.allSettled(batches
|
|
13136
|
+
.slice(from, from + MAX_PARALLEL_DECISION_BATCHES)
|
|
13137
|
+
.map((batch) => this.decide(batch)));
|
|
13138
|
+
for (const outcome of settled) {
|
|
13139
|
+
if (outcome.status === "fulfilled") {
|
|
13140
|
+
answered.push(outcome.value);
|
|
13141
|
+
}
|
|
13142
|
+
else {
|
|
13143
|
+
firstFailure ??= outcome.reason;
|
|
13144
|
+
}
|
|
13145
|
+
}
|
|
13146
|
+
}
|
|
13147
|
+
const [first, ...rest] = answered;
|
|
13148
|
+
if (first === undefined) {
|
|
13149
|
+
throw firstFailure instanceof Error
|
|
13150
|
+
? firstFailure
|
|
13151
|
+
: new Error(String(firstFailure));
|
|
13152
|
+
}
|
|
13153
|
+
if (rest.length + 1 < batches.length) {
|
|
13154
|
+
logger.debug(`decide: ${batches.length - answered.length} of ${batches.length} batches failed; using the answers of the rest`);
|
|
13155
|
+
}
|
|
13156
|
+
return mergeDecisionResults([first, ...rest]);
|
|
13157
|
+
}
|
|
13103
13158
|
/**
|
|
13104
13159
|
* Evaluate an AI response using the specified pipeline or scorers.
|
|
13105
13160
|
* This is a convenience method that creates a pipeline and executes it in one call.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DecisionOptions, DecisionResult } from "../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* How many batches of one split request are in flight at once. A request that
|
|
4
|
+
* splits into many must not meet the vendor's rate limit first: Perplexity, for
|
|
5
|
+
* one, allows ten requests a second.
|
|
6
|
+
*/
|
|
7
|
+
export declare const MAX_PARALLEL_DECISION_BATCHES = 4;
|
|
8
|
+
/**
|
|
9
|
+
* Cut a request whose question map is longer than a provider's cap into
|
|
10
|
+
* requests the provider takes, keeping the questions in the order they were
|
|
11
|
+
* given. A request that fits, or a provider with no cap, comes back as the one
|
|
12
|
+
* request it was.
|
|
13
|
+
*
|
|
14
|
+
* `state` and any images or video travel with every batch, since each batch is
|
|
15
|
+
* a decision of its own.
|
|
16
|
+
*/
|
|
17
|
+
export declare function splitDecisionRequest(options: DecisionOptions, maxQuestions: number | undefined): DecisionOptions[];
|
|
18
|
+
/**
|
|
19
|
+
* One result from the results of several batches: the answers joined, usage and
|
|
20
|
+
* media summed, the latency of the slowest (the batches ran side by side), and
|
|
21
|
+
* the request ids listed. Model and provider are the first batch's, which is
|
|
22
|
+
* the same for all of them.
|
|
23
|
+
*/
|
|
24
|
+
export declare function mergeDecisionResults(results: readonly [DecisionResult, ...DecisionResult[]]): DecisionResult;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How many batches of one split request are in flight at once. A request that
|
|
3
|
+
* splits into many must not meet the vendor's rate limit first: Perplexity, for
|
|
4
|
+
* one, allows ten requests a second.
|
|
5
|
+
*/
|
|
6
|
+
export const MAX_PARALLEL_DECISION_BATCHES = 4;
|
|
7
|
+
/**
|
|
8
|
+
* Cut a request whose question map is longer than a provider's cap into
|
|
9
|
+
* requests the provider takes, keeping the questions in the order they were
|
|
10
|
+
* given. A request that fits, or a provider with no cap, comes back as the one
|
|
11
|
+
* request it was.
|
|
12
|
+
*
|
|
13
|
+
* `state` and any images or video travel with every batch, since each batch is
|
|
14
|
+
* a decision of its own.
|
|
15
|
+
*/
|
|
16
|
+
export function splitDecisionRequest(options, maxQuestions) {
|
|
17
|
+
const entries = Object.entries(options.questions);
|
|
18
|
+
if (maxQuestions === undefined ||
|
|
19
|
+
maxQuestions < 1 ||
|
|
20
|
+
entries.length <= maxQuestions) {
|
|
21
|
+
return [options];
|
|
22
|
+
}
|
|
23
|
+
const batches = [];
|
|
24
|
+
for (let from = 0; from < entries.length; from += maxQuestions) {
|
|
25
|
+
batches.push({
|
|
26
|
+
...options,
|
|
27
|
+
questions: Object.fromEntries(entries.slice(from, from + maxQuestions)),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return batches;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* One result from the results of several batches: the answers joined, usage and
|
|
34
|
+
* media summed, the latency of the slowest (the batches ran side by side), and
|
|
35
|
+
* the request ids listed. Model and provider are the first batch's, which is
|
|
36
|
+
* the same for all of them.
|
|
37
|
+
*/
|
|
38
|
+
export function mergeDecisionResults(results) {
|
|
39
|
+
const [first] = results;
|
|
40
|
+
const upstream = results.flatMap((r) => r.upstreamMs === undefined ? [] : [r.upstreamMs]);
|
|
41
|
+
const media = results.flatMap((r) => r.mediaBytes === undefined ? [] : [r.mediaBytes]);
|
|
42
|
+
const requestIds = results.flatMap((r) => (r.requestId ? [r.requestId] : []));
|
|
43
|
+
return {
|
|
44
|
+
model: first.model,
|
|
45
|
+
provider: first.provider,
|
|
46
|
+
answers: Object.assign({}, ...results.map((r) => r.answers)),
|
|
47
|
+
usage: {
|
|
48
|
+
inputTokens: results.reduce((sum, r) => sum + r.usage.inputTokens, 0),
|
|
49
|
+
outputTokens: results.reduce((sum, r) => sum + r.usage.outputTokens, 0),
|
|
50
|
+
},
|
|
51
|
+
latencyMs: Math.max(...results.map((r) => r.latencyMs)),
|
|
52
|
+
...(requestIds.length > 0 ? { requestId: requestIds.join(",") } : {}),
|
|
53
|
+
...(upstream.length > 0 ? { upstreamMs: Math.max(...upstream) } : {}),
|
|
54
|
+
...(media.length > 0
|
|
55
|
+
? { mediaBytes: media.reduce((sum, bytes) => sum + bytes, 0) }
|
|
56
|
+
: {}),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
@@ -214,6 +214,18 @@ export function redactUrlForError(url) {
|
|
|
214
214
|
const truncate = (s) => s.length > 200 ? `${s.slice(0, 200)}…` : s;
|
|
215
215
|
try {
|
|
216
216
|
const parsed = new URL(url);
|
|
217
|
+
// `user:pass@host:80` has no `//`, so it is not an authority: it parses as
|
|
218
|
+
// the scheme `user:` with the opaque path `pass@host:80`, and rebuilding it
|
|
219
|
+
// from scheme and path would hand the password back. An opaque path that
|
|
220
|
+
// holds an `@` is read as credentials and cut at the last one. A file URL
|
|
221
|
+
// has a path that starts with `/`, and a Windows drive path has a one-letter
|
|
222
|
+
// scheme, so neither is touched.
|
|
223
|
+
if (parsed.host === "" &&
|
|
224
|
+
!parsed.pathname.startsWith("/") &&
|
|
225
|
+
parsed.pathname.includes("@") &&
|
|
226
|
+
!/^[a-z]:$/i.test(parsed.protocol)) {
|
|
227
|
+
return truncate(`[redacted]@${parsed.pathname.slice(parsed.pathname.lastIndexOf("@") + 1)}`);
|
|
228
|
+
}
|
|
217
229
|
// Reconstruct explicitly from protocol + host + pathname — never
|
|
218
230
|
// parsed.username/parsed.password, and never parsed.href (which
|
|
219
231
|
// re-serializes any embedded userinfo) — so a `user:pass@host` in the
|
|
@@ -3358,7 +3358,7 @@
|
|
|
3358
3358
|
{"objectID":"19994573e52cd09183db8050eadaea8ece3e291ef40c3009a5c44dfa959bf99c","title":"XOR, at a deployment or a LiteLLM proxy route","url":"/docs/features/decide-inference-type#xor-at-a-deployment-or-a-litellm-proxy-route","content":"XOR, Juspay's open-weights decision model, has no built-in endpoint either.\nNeuroLink calls <base URL>/v1/systemone, and a trailing /v1 on the base URL\nis accepted. The base URL and key can equally come from the config passed to the\nSDK, new NeuroLink({ credentials: { xor: { baseURL, apiKey } } }), or per\ncall; config set there counts when NeuroLink picks the default decision\nprovider, exactly as the environment does. On a LiteLLM proxy the key's team\nmust allow xor-1.1, otherwise the proxy answers 403 team_model_access_denied.\n\nBuilt-in features use the first configured decision provider in the order\nTypeSafe, Laya, XOR, Perplexity. XOR counts as configured only with both its key\nand its base URL, and runs where a caller names it (provider: \"xor\") or when\nneither TypeSafe nor Laya is configured. It reads images and video; see\nImages and video and the\nXOR provider guide.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"XOR, at a deployment or a LiteLLM proxy route","lvl3":""}},
|
|
3359
3359
|
{"objectID":"dc8b9e9a2c66b1d2a60305a09a44263ceca755d40f04b6771e0a7c05a5237a64","title":"Perplexity, at its hosted endpoint","url":"/docs/features/decide-inference-type#perplexity-at-its-hosted-endpoint","content":"Perplexity's pplx-decider-v1-27b is a hosted API at a public endpoint, so a key\nalone configures it and there is no base URL to set. NeuroLink calls\n<base URL>/v1/decisions; a trailing /v1 on an override is accepted. The key\ncan equally come from the config passed to the SDK,\nnew NeuroLink({ credentials: { perplexityDecider: { apiKey } } }), or per call;\nconfig set there counts when a decide() call picks the default decision\nprovider, exactly as the environment does. The classifier router's auto gate is\nread differently: it looks at the constructor's credentials and the environment\nonly, so a credentials.perplexityDecider passed on one call does not influence\nit. The provider id is perplexity-decider: the perplexity provider is the\nSonar text provider, which serves generate() and stream() and not decide().\n\nPERPLEXITY_API_KEY is shared with that text provider. A host that set it\nonly to use Sonar has therefore also configured decide, and built-in features\nwill use Perplexity whenever none of TypeSafe, Laya or XOR is configured.\nPerplexity comes after XOR in descriptor order, so it never displaces one that\nis. Context compaction's relevance stage and summary gate need no opt-in of their\nown, so earlier conversation text starts going to Perplexity the first time a\nconversation outgrows its budget; model routing, tool routing and RAG planning do\nnothing unless enabled. To keep the shared key from activating decisions, pass\nthe text provider's key as credentials.perplexity instead of through the\nenvironment, and keep it out of .env too, because the SDK and the CLI load that\nfile into the environment, or configure one of TypeSafe, Laya and XOR, which then\nreceives those texts instead. The Perplexity provider guide lists\nwhat each consumer sends\nand the\nexact switches.\nIt reads images but no video; see Images and video.\n\nThe degradation contract. resolveDefaultDecisionProvider() returns\nundefined when no decision provider is configured (a key, plus a base URL for\nLaya and","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Perplexity, at its hosted endpoint","lvl3":""}},
|
|
3360
3360
|
{"objectID":"7990ffc08aca0afbeae4310cfdcd3758daf52da4d9edd1da90a82b683f4d7d41","title":"Two transports","url":"/docs/features/decide-inference-type#two-transports","content":"The same model is reachable two ways. Which one runs is decided once, in the\nconstructor:\n\n| | Direct | Vercel AI Gateway |\n| ------------------- | ------------------ | --------------------------------------------- |\n| Key | TYPESAFE_API_KEY | AI_GATEWAY_API_KEY |\n| Endpoint | api.typesafe.ai | ai-gateway.vercel.sh/v4/ai/evaluation-model |\n| Model named in | request body | ai-model-id header |\n| Question vocabulary | noul | boolean |\n| confidence | on each answer | on providerMetadata, not on the answer |\n| Billed by | TypeSafe | Vercel |\n\nHolding both keys keeps the direct transport, so the confidence figures a\nhost already sees do not shift underneath it when a second key appears. Both\ntransports report the vendor's calibrated confidence — the gateway simply puts\nit somewhere else, under providerMetadata.typesafe.confidence.<questionId>,\nleaving the answer objects without one. Set TYPESAFE_TRANSPORT=gateway (or\ncredentials.typesafe.transport) to override.\n\n⚠️ Read that field, not the distribution peak. It is tempting to take\nmax(probabilities) when an answer carries no confidence, and on a\nnear-certain answer the two agree. On an uncertain one they do not, and not by a\nlittle: a measured four-way choice returned probabilities\n{alpha 0.16, beta 0.28, gamma 0.33, delta 0.23} — a peak of 0.33 against a\nreported confidence of 0.10. That gap straddles the default\nminUpgradeConfidence of 0.3, so the derived number clears a bar the real one\nfails and a near-random pick gets acted on as a confident one. The peak stays as\nthe fallback when neither source reports a confidence, and it is genuinely a\ndifferent quantity: an even distribution over N options lands near 1/N, not 0.\n\nUsage is spelled differently t","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Two transports","lvl3":""}},
|
|
3361
|
-
{"objectID":"e5df7db87d4cb31c67fcce769cf5a3573764cb358ed9ee4b41f7ce86cb3954b7","title":"Using it","url":"/docs/features/decide-inference-type#using-it","content":"readDecisionBoolean / readDecisionChoice / readDecisionScore validate at\nruntime and return undefined for a missing id or a mismatched type, so no\ncall site needs a type assertion.\n\nUse decide() instead of tryDecide() when you want the failure to surface;\nit throws a ProviderError whose cause carries a typed kind\n(authentication, rate_limit, max_tokens_exceeded, …).","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Using it","lvl3":""}},
|
|
3361
|
+
{"objectID":"e5df7db87d4cb31c67fcce769cf5a3573764cb358ed9ee4b41f7ce86cb3954b7","title":"Using it","url":"/docs/features/decide-inference-type#using-it","content":"readDecisionBoolean / readDecisionChoice / readDecisionScore validate at\nruntime and return undefined for a missing id or a mismatched type, so no\ncall site needs a type assertion.\n\nUse decide() instead of tryDecide() when you want the failure to surface;\nit throws a ProviderError whose cause carries a typed kind\n(authentication, rate_limit, max_tokens_exceeded, …).\n\nMore questions than a provider takes. A provider that caps the questions in\none request (Laya takes 64) refuses a longer map from decide() with\nmax_tokens_exceeded. tryDecide(), which every built-in consumer calls,\nsplits the map at the cap instead, keeps the questions in the order given, runs\nup to four batches at a time and joins the answers into one result: usage is\nsummed, the latency is the slowest batch's, and requestId lists the batches'\nids. A batch that fails costs only its own questions, which then have no answer\n(the read* helpers return undefined for them, and every built-in consumer\ncarries on without that decision); tryDecide() returns null only when every\nbatch failed. The state and any media are sent with each batch, so a split\nrequest costs the state's tokens once for each batch. A provider with no cap\n(TypeSafe, XOR) always gets one request.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Using it","lvl3":""}},
|
|
3362
3362
|
{"objectID":"7232a490e9e72e01dbe1a12de9470a38ed66ef91aa076b8c8cc745770eb03545","title":"From the CLI","url":"/docs/features/decide-inference-type#from-the-cli","content":"The same primitive is available as neurolink decide [state], which calls\ndecide() (not tryDecide()) and prints one line per answer:\n\nTo ask about an image or a video, add --image <path> (repeatable) or\n--video <path>. XOR reads both, Perplexity reads images only, and TypeSafe and\nLaya read neither:\n\nSee the CLI command reference for the full flag\nlist, including --state-file, --questions-file, --image, --video and\n--format json.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"From the CLI","lvl3":""}},
|
|
3363
3363
|
{"objectID":"3b801c727cb399feb7390c3ad67aba9ea5f77581096bb852b7aafb87b70998aa","title":"A choice answer is also a ranking","url":"/docs/features/decide-inference-type#a-choice-answer-is-also-a-ranking","content":"readDecisionChoice returns ranked — every option sorted by probability,\nhighest first. One choice question over N options therefore ranks all N in a\nsingle request. This is the basis for picking from a large catalogue.","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"A choice answer is also a ranking","lvl3":""}},
|
|
3364
3364
|
{"objectID":"e67682840a5ce9650dba2a1d437b0dfbba456cae60fa3f607127e209bf1ec3e7","title":"Images and video","url":"/docs/features/decide-inference-type#images-and-video","content":"A decision provider whose descriptor declares media limits reads images, and\npossibly one video, alongside state. XOR does, and so does Perplexity, which\ndeclares images only and no video; TypeSafe and Laya do not. Two optional fields\non the request carry them, for decide() and tryDecide() alike:\nimages — up to 8 images, the limit XOR and Perplexity each declare.\nvideo — one video, for a provider that declares video (XOR).\n\nEach image and the video takes the same three input forms:\na Buffer;\na local file path;\na data:image/…;base64, or data:video/…;base64, URL.\n\nNeuroLink identifies a Buffer or a file from its bytes, not its extension — PNG,\nJPEG, WebP and GIF images, and MP4, MOV and WebM video —\nand sends it as a data: URL. A data: URL you pass yourself must hold base64\nimage or video content, and is sent as given. Perplexity reads PNG, JPEG and\nWebP only, and refuses a GIF before any request.\n\nWhat is refused. Everything NeuroLink can check is refused before any\nrequest, as a non-retryable invalid_request:\nan http(s) URL — media is not fetched for you, so pass a Buffer, a file path\n or a data: URL;\na string that is not a file path or a data: URL, such as bare base64 or a\n URL with another scheme;\na missing file, a directory, or an empty Buffer or file;\nsomething that is not an image or a video;\nmore than 8 images;\na request body over the provider's limit: 8 MB for XOR, 32 MiB for Perplexity.\n The limit applies to the encoded body, so the base64 form counts. A file over\n it is refused from its size, before it is read;\na video sent to a provider that declares no video (Perplexity);\nan image Perplexity cannot read: one of another type, or over 2,048 tiles of\n 32 × 32 pixels, which the API would otherwise hold for about a minute before\n answering 504;\nany media sent to a provider that declares no media capability (TypeSafe,\n Laya). The message names the providers that accept media.\n\nImages and a video can be sent together to XOR (up to 8 images and one\nvideo),","hierarchy":{"lvl0":"Features","lvl1":"The `decide` inference type","lvl2":"Images and video","lvl3":""}},
|
|
@@ -6156,7 +6156,7 @@
|
|
|
6156
6156
|
{"objectID":"50860d1f7a27dbe3ad7452ad7079ea437658db372b97081d0a509429369cacc6","title":"[TypeSafe (Jev)](/docs/getting-started/providers/typesafe)","url":"/docs/getting-started/providers#typesafe-jevdocsgetting-startedproviderstypesafe","content":"Typed, calibrated judgments instead of text\n🎯 boolean / choice / score answers, each with a calibrated confidence\n⚡ Latency flat in question count — 1 question ~393 ms, 400 questions ~465 ms\n💰 ~$0.00002 per decision (~$0.042/M input, output billed at zero)\n🔌 Two transports: TypeSafe direct, or the Vercel AI Gateway\n🛡️ Fails open — with no decision provider configured, every consumer behaves exactly as before\n🔑 API key from console.typesafe.ai/keys\n🔄 Aliases: jev, typesafe-ai\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[TypeSafe (Jev)](/docs/getting-started/providers/typesafe)","lvl3":""}},
|
|
6157
6157
|
{"objectID":"43b838d60f2794ce46361196d6fc8a708b3a301398dd55f2c8015d567aa21c2c","title":"[Laya](/docs/getting-started/providers/laya)","url":"/docs/getting-started/providers#layadocsgetting-startedproviderslaya","content":"Open-weights decision provider — the same typed boolean/choice/score answers as Jev, from Convai Innovations' Apache-2.0 checkpoints, at a Laya server or LiteLLM proxy route you configure\n🧭 Serves decide only; built-in features use it when its key and base URL are set and neither TYPESAFE_API_KEY nor AI_GATEWAY_API_KEY is\n📏 Refuses more than ~768 tokens of state (320 on english) before any network call, since its encoders read only 1,024 (512)\n🔌 No built-in endpoint: LAYA_BASE_URL (or credentials.laya.baseURL) names a Laya server or a LiteLLM pass-through route to one\n🔑 LAYA_API_KEY is the key that endpoint accepts; on LiteLLM, the route must be in the key's Allowed Routes\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[Laya](/docs/getting-started/providers/laya)","lvl3":""}},
|
|
6158
6158
|
{"objectID":"613cbeca5e8fa0bbe765b8db9ec4ed2ff76a913dd45b8dab5e2de06a6e5f19ff","title":"[XOR](/docs/getting-started/providers/xor)","url":"/docs/getting-started/providers#xordocsgetting-startedprovidersxor","content":"Open-weights decision provider — the same typed boolean/choice/score answers as Jev, from xor-1.1, Juspay's Apache-2.0 model, at a deployment or LiteLLM proxy route you configure\n🧭 Serves decide only; built-in features use it when its key and base URL are set and no TypeSafe key, no AI_GATEWAY_API_KEY and no Laya key and base URL is\n🖼️ Takes up to 8 images or one video with a decision, as a Buffer, a local file path or a data: URL; TypeSafe and Laya refuse media before any request, and Perplexity refuses a video\n📏 Refuses more than about 200,000 estimated tokens of state before any network call\n🔌 No built-in endpoint: XOR_BASE_URL (or credentials.xor.baseURL) is the origin of a deployment or of a LiteLLM route to one; requests go to <base URL>/v1/systemone\n🔑 XOR_API_KEY is the key that endpoint accepts; on LiteLLM, the key's team must allow xor-1.1\n📦 Weights and setup: huggingface.co/juspay/xor\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[XOR](/docs/getting-started/providers/xor)","lvl3":""}},
|
|
6159
|
-
{"objectID":"6ab8cdd8152a0d7c9844d54b6d4eaccc905b60e79f4b28508d78d52c3cfe9470","title":"[Perplexity Decisions](/docs/getting-started/providers/perplexity-decider)","url":"/docs/getting-started/providers#perplexity-decisionsdocsgetting-startedprovidersperplexity-decider","content":"Hosted decision provider — the same typed boolean/choice/score answers as Jev, from Perplexity's pplx-decider-v1-27b, at https://api.perplexity.ai\n🧭 Serves decide only (provider id perplexity-decider, not the Sonar text provider perplexity); built-in features use it when it is configured and no TypeSafe key, no AI_GATEWAY_API_KEY, no Laya key and base URL and no XOR key and base URL is\n🔑 PERPLEXITY_API_KEY alone configures it, and it is the same key the Perplexity text provider reads, so a key set for Sonar also lets built-in features use it when none of TypeSafe, Laya or XOR is configured; the guide lists what each consumer then sends\n🖼️ Takes up to 8 PNG, JPEG or WebP images with a decision; no video\n💰 $0.04 per million input tokens (image tokens included), output free, as Perplexity documents it\n📏 Refuses more than about 100,000 estimated tokens of state (NeuroLink's own window; the server's ceiling is 262,144 input tokens), or more than 128 questions, before any network call. The 128-question cap, the server's token ceiling and the latency were measured on a real account in October 2026\n🔌 Hosted endpoint, so no base URL is needed; PERPLEXITY_DECIDER_BASE_URL (or credentials.perplexityDecider.baseURL) can name another origin\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[Perplexity Decisions](/docs/getting-started/providers/perplexity-decider)","lvl3":""}},
|
|
6159
|
+
{"objectID":"6ab8cdd8152a0d7c9844d54b6d4eaccc905b60e79f4b28508d78d52c3cfe9470","title":"[Perplexity Decisions](/docs/getting-started/providers/perplexity-decider)","url":"/docs/getting-started/providers#perplexity-decisionsdocsgetting-startedprovidersperplexity-decider","content":"Hosted decision provider — the same typed boolean/choice/score answers as Jev, from Perplexity's pplx-decider-v1-27b, at https://api.perplexity.ai\n🧭 Serves decide only (provider id perplexity-decider, not the Sonar text provider perplexity); built-in features use it when it is configured and no TypeSafe key, no AI_GATEWAY_API_KEY, no Laya key and base URL and no XOR key and base URL is\n🔑 PERPLEXITY_API_KEY alone configures it, and it is the same key the Perplexity text provider reads, so a key set for Sonar also lets built-in features use it when none of TypeSafe, Laya or XOR is configured; the guide lists what each consumer then sends\n🖼️ Takes up to 8 PNG, JPEG or WebP images with a decision; no video\n💰 $0.04 per million input tokens (image tokens included), output free, as Perplexity documents it\n📏 Refuses more than about 100,000 estimated tokens of state (NeuroLink's own window; the server's ceiling is 262,144 input tokens), or more than 128 questions in a decide() call (tryDecide() splits them), before any network call. The 128-question cap, the server's token ceiling and the latency were measured on a real account in October 2026\n🔌 Hosted endpoint, so no base URL is needed; PERPLEXITY_DECIDER_BASE_URL (or credentials.perplexityDecider.baseURL) can name another origin\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[Perplexity Decisions](/docs/getting-started/providers/perplexity-decider)","lvl3":""}},
|
|
6160
6160
|
{"objectID":"c98403894a115164f29a019817b7f39c93b59623a9854b4575ad06bc5f597320","title":"🧩 Additional Catalog Providers","url":"/docs/getting-started/providers#-additional-catalog-providers","content":"Every provider below is a Tier-2 catalog entry. Provider-specific\nbehavioural quirks may apply, so check the provider's catalog file. The whole\nintegration is one JSON file under src/lib/providers/catalog/. Each page is\ngenerated from that file, which is also what the CI onboarding gate reads.","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"🧩 Additional Catalog Providers","lvl3":""}},
|
|
6161
6161
|
{"objectID":"026138da0a559269ecd9f0b2ceb72d9039096e72e064142afb7bfb74a5cb7455","title":"[API Route](/docs/getting-started/providers/api-route)","url":"/docs/getting-started/providers#api-routedocsgetting-startedprovidersapi-route","content":"Claude Sonnet 4.6\n🤖 8 models; default claude-sonnet-4-6 (1M context)\n🛠️ Native tool calling + structured output together\n💳 Free tier available\n✅ Roster verified 2026-09-17 (authenticated GET /v1/models)\n🔑 API key from api-route.com\n🔄 Aliases: apiroute\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[API Route](/docs/getting-started/providers/api-route)","lvl3":""}},
|
|
6162
6162
|
{"objectID":"85aa65949d959db077347ecf93a4c40ade9ebab4300d4d52c62c702f6929053b","title":"[Baseten](/docs/getting-started/providers/baseten)","url":"/docs/getting-started/providers#basetendocsgetting-startedprovidersbaseten","content":"GLM 5.3 Flash\n🤖 16 models; default zai-org/GLM-5.3-Flash (1M context)\n🛠️ Native tool calling + structured output together\n💳 Free tier available\n✅ Roster verified 2026-09-03 (authenticated GET /v1/models)\n🔑 API key from app.baseten.co\n\nSetup Guide →","hierarchy":{"lvl0":"Getting Started","lvl1":"AI Provider Guides","lvl2":"[Baseten](/docs/getting-started/providers/baseten)","lvl3":""}},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "12.44.
|
|
3
|
+
"version": "12.44.1",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
|
|
6
6
|
"author": {
|