@juspay/neurolink 12.49.8 → 12.49.10

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.
@@ -0,0 +1,2 @@
1
+ import type { DecideDialectName, DecisionDialect } from "../../../types/index.js";
2
+ export declare const getDecisionDialect: (name: DecideDialectName) => DecisionDialect;
@@ -0,0 +1,5 @@
1
+ import { systemOneDialect } from "./systemOne.js";
2
+ const DIALECTS = {
3
+ "system-one": systemOneDialect,
4
+ };
5
+ export const getDecisionDialect = (name) => DIALECTS[name];
@@ -0,0 +1,2 @@
1
+ import type { DecisionDialect } from "../../../types/index.js";
2
+ export declare const systemOneDialect: DecisionDialect;
@@ -0,0 +1,104 @@
1
+ import { asNumber, asNumberMap, asStringMap, isRecord } from "../guards.js";
2
+ /**
3
+ * Last-resort confidence, when no transport reported one.
4
+ *
5
+ * The peak probability is what a calibrated confidence approximates, but it is
6
+ * NOT the same number, so a threshold tuned against a vendor's calibrated
7
+ * figure does not transfer unexamined; an even distribution lands near 1/N
8
+ * rather than 0.
9
+ */
10
+ function deriveConfidence(probabilities) {
11
+ const values = Object.values(probabilities);
12
+ return values.length > 0 ? Math.max(...values) : 0;
13
+ }
14
+ /**
15
+ * Validate one answer off the wire. Returns null rather than throwing so a
16
+ * single malformed answer degrades to "unanswered" instead of failing the
17
+ * whole batch — the batch may hold hundreds of usable answers.
18
+ */
19
+ function parseDecisionAnswer(raw, reportedConfidence) {
20
+ if (!isRecord(raw)) {
21
+ return null;
22
+ }
23
+ switch (raw.type) {
24
+ // "noul" is the System One wire's own spelling; "boolean" is the neutral
25
+ // one (Vercel's gateway), which renames both the type and the field.
26
+ // Accepting both keeps one parser for every transport.
27
+ case "noul":
28
+ case "boolean": {
29
+ const probability = asNumber(raw.noul) ?? asNumber(raw.probability);
30
+ return probability === undefined
31
+ ? null
32
+ : { type: "boolean", probability };
33
+ }
34
+ case "choice": {
35
+ const probabilities = asNumberMap(raw.probabilities);
36
+ if (typeof raw.choice !== "string" || !probabilities) {
37
+ return null;
38
+ }
39
+ return {
40
+ type: "choice",
41
+ choice: raw.choice,
42
+ confidence: asNumber(raw.confidence) ??
43
+ reportedConfidence ??
44
+ deriveConfidence(probabilities),
45
+ probabilities,
46
+ };
47
+ }
48
+ case "score": {
49
+ const score = asNumber(raw.score);
50
+ const legend = asStringMap(raw.legend);
51
+ const probabilities = asNumberMap(raw.probabilities);
52
+ if (score === undefined || !legend || !probabilities) {
53
+ return null;
54
+ }
55
+ return {
56
+ type: "score",
57
+ score,
58
+ confidence: asNumber(raw.confidence) ??
59
+ reportedConfidence ??
60
+ deriveConfidence(probabilities),
61
+ legend,
62
+ probabilities,
63
+ };
64
+ }
65
+ default:
66
+ return null;
67
+ }
68
+ }
69
+ /**
70
+ * The System One wire calls the yes/no primitive `noul`; this codebase and
71
+ * every SDK exposing it call it `boolean`.
72
+ */
73
+ function encodeQuestion(question) {
74
+ if (question.type === "boolean") {
75
+ return {
76
+ type: "noul",
77
+ instructions: question.instructions,
78
+ ...(question.criteria ? { criteria: question.criteria } : {}),
79
+ };
80
+ }
81
+ return question;
82
+ }
83
+ export const systemOneDialect = {
84
+ name: "system-one",
85
+ encodeQuestion,
86
+ readAnswers: (decoded, reportedConfidence) => {
87
+ const raw = decoded.answers;
88
+ if (!isRecord(raw)) {
89
+ return undefined;
90
+ }
91
+ const answers = {};
92
+ const dropped = [];
93
+ for (const [id, value] of Object.entries(raw)) {
94
+ const parsed = parseDecisionAnswer(value, reportedConfidence[id]);
95
+ if (parsed) {
96
+ answers[id] = parsed;
97
+ }
98
+ else {
99
+ dropped.push(id);
100
+ }
101
+ }
102
+ return { answers, dropped };
103
+ },
104
+ };
@@ -0,0 +1,4 @@
1
+ export declare const isRecord: (v: unknown) => v is Record<string, unknown>;
2
+ export declare const asNumber: (v: unknown) => number | undefined;
3
+ export declare const asNumberMap: (v: unknown) => Record<string, number> | undefined;
4
+ export declare const asStringMap: (v: unknown) => Record<string, string> | undefined;
@@ -0,0 +1,29 @@
1
+ export const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
2
+ export const asNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
3
+ export const asNumberMap = (v) => {
4
+ if (!isRecord(v)) {
5
+ return undefined;
6
+ }
7
+ const out = {};
8
+ for (const [k, raw] of Object.entries(v)) {
9
+ const n = asNumber(raw);
10
+ if (n === undefined) {
11
+ return undefined;
12
+ }
13
+ out[k] = n;
14
+ }
15
+ return out;
16
+ };
17
+ export const asStringMap = (v) => {
18
+ if (!isRecord(v)) {
19
+ return undefined;
20
+ }
21
+ const out = {};
22
+ for (const [k, raw] of Object.entries(v)) {
23
+ if (typeof raw !== "string") {
24
+ return undefined;
25
+ }
26
+ out[k] = raw;
27
+ }
28
+ return out;
29
+ };
@@ -1,15 +1,14 @@
1
1
  import type { AIProviderName } from "../constants/enums.js";
2
2
  import { BaseProvider } from "../core/baseProvider.js";
3
3
  import { ProviderError } from "../types/index.js";
4
- import type { DecisionError, DecisionQuestion, DecisionRequest, DecisionResult, DecisionPreparedMedia, DecisionState, LanguageModel, StreamOptions, StreamResult, ValidationSchema } from "../types/index.js";
4
+ import type { DecisionDialect, DecisionError, DecisionQuestion, DecisionRequest, DecisionResult, DecisionPreparedMedia, DecisionState, LanguageModel, StreamOptions, StreamResult, ValidationSchema } from "../types/index.js";
5
5
  /**
6
6
  * Generous enough for a cold start (measured at 2.0–2.7s after idle on Jev)
7
7
  * while still bounded. Every internal caller is fail-open, so this only bites
8
8
  * on a genuine stall.
9
9
  */
10
10
  export declare const DEFAULT_DECISION_TIMEOUT_MS = 5000;
11
- export declare const isRecord: (v: unknown) => v is Record<string, unknown>;
12
- export declare const asNumber: (v: unknown) => number | undefined;
11
+ export { asNumber, isRecord } from "./decide/guards.js";
13
12
  /**
14
13
  * FastAPI's request-validation envelope, `{"detail":[{loc, msg, input}]}`,
15
14
  * reduced to its field paths and messages. `input` echoes the caller's own
@@ -73,6 +72,11 @@ export declare abstract class SystemOneDecisionProvider extends BaseProvider {
73
72
  * every SDK exposing it call it `boolean`.
74
73
  */
75
74
  protected encodeQuestion(question: DecisionQuestion): Record<string, unknown>;
75
+ /**
76
+ * The wire family this provider speaks. A provider on another layout
77
+ * overrides it; every one so far speaks System One.
78
+ */
79
+ protected dialect(): DecisionDialect;
76
80
  /**
77
81
  * How long a rate-limited or unavailable response asks the caller to wait.
78
82
  * Undefined keeps the default backoff. A wait longer than what is left of the
@@ -7,6 +7,8 @@ import { prepareDecisionMedia } from "../utils/decisionMedia.js";
7
7
  import { logger } from "../utils/logger.js";
8
8
  import { redactUrlsInText } from "../utils/logSanitize.js";
9
9
  import { estimateDecisionStateTokens, resolveDecisionLimitsReading, } from "../utils/decisionLimits.js";
10
+ import { systemOneDialect } from "./decide/dialects/systemOne.js";
11
+ import { asNumber, isRecord } from "./decide/guards.js";
10
12
  /**
11
13
  * Generous enough for a cold start (measured at 2.0–2.7s after idle on Jev)
12
14
  * while still bounded. Every internal caller is fail-open, so this only bites
@@ -14,102 +16,7 @@ import { estimateDecisionStateTokens, resolveDecisionLimitsReading, } from "../u
14
16
  */
15
17
  export const DEFAULT_DECISION_TIMEOUT_MS = 5000;
16
18
  const DEFAULT_MAX_RETRIES = 1;
17
- export const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
18
- export const asNumber = (v) => typeof v === "number" && Number.isFinite(v) ? v : undefined;
19
- const asNumberMap = (v) => {
20
- if (!isRecord(v)) {
21
- return undefined;
22
- }
23
- const out = {};
24
- for (const [k, raw] of Object.entries(v)) {
25
- const n = asNumber(raw);
26
- if (n === undefined) {
27
- return undefined;
28
- }
29
- out[k] = n;
30
- }
31
- return out;
32
- };
33
- const asStringMap = (v) => {
34
- if (!isRecord(v)) {
35
- return undefined;
36
- }
37
- const out = {};
38
- for (const [k, raw] of Object.entries(v)) {
39
- if (typeof raw !== "string") {
40
- return undefined;
41
- }
42
- out[k] = raw;
43
- }
44
- return out;
45
- };
46
- /**
47
- * Last-resort confidence, when no transport reported one.
48
- *
49
- * The peak probability is what a calibrated confidence approximates, but it is
50
- * NOT the same number, so a threshold tuned against a vendor's calibrated
51
- * figure does not transfer unexamined; an even distribution lands near 1/N
52
- * rather than 0.
53
- */
54
- function deriveConfidence(probabilities) {
55
- const values = Object.values(probabilities);
56
- return values.length > 0 ? Math.max(...values) : 0;
57
- }
58
- /**
59
- * Validate one answer off the wire. Returns null rather than throwing so a
60
- * single malformed answer degrades to "unanswered" instead of failing the
61
- * whole batch — the batch may hold hundreds of usable answers.
62
- */
63
- function parseDecisionAnswer(raw, reportedConfidence) {
64
- if (!isRecord(raw)) {
65
- return null;
66
- }
67
- switch (raw.type) {
68
- // "noul" is the System One wire's own spelling; "boolean" is the neutral
69
- // one (Vercel's gateway), which renames both the type and the field.
70
- // Accepting both keeps one parser for every transport.
71
- case "noul":
72
- case "boolean": {
73
- const probability = asNumber(raw.noul) ?? asNumber(raw.probability);
74
- return probability === undefined
75
- ? null
76
- : { type: "boolean", probability };
77
- }
78
- case "choice": {
79
- const probabilities = asNumberMap(raw.probabilities);
80
- if (typeof raw.choice !== "string" || !probabilities) {
81
- return null;
82
- }
83
- return {
84
- type: "choice",
85
- choice: raw.choice,
86
- confidence: asNumber(raw.confidence) ??
87
- reportedConfidence ??
88
- deriveConfidence(probabilities),
89
- probabilities,
90
- };
91
- }
92
- case "score": {
93
- const score = asNumber(raw.score);
94
- const legend = asStringMap(raw.legend);
95
- const probabilities = asNumberMap(raw.probabilities);
96
- if (score === undefined || !legend || !probabilities) {
97
- return null;
98
- }
99
- return {
100
- type: "score",
101
- score,
102
- confidence: asNumber(raw.confidence) ??
103
- reportedConfidence ??
104
- deriveConfidence(probabilities),
105
- legend,
106
- probabilities,
107
- };
108
- }
109
- default:
110
- return null;
111
- }
112
- }
19
+ export { asNumber, isRecord } from "./decide/guards.js";
113
20
  /**
114
21
  * FastAPI's request-validation envelope, `{"detail":[{loc, msg, input}]}`,
115
22
  * reduced to its field paths and messages. `input` echoes the caller's own
@@ -210,14 +117,14 @@ export class SystemOneDecisionProvider extends BaseProvider {
210
117
  * every SDK exposing it call it `boolean`.
211
118
  */
212
119
  encodeQuestion(question) {
213
- if (question.type === "boolean") {
214
- return {
215
- type: "noul",
216
- instructions: question.instructions,
217
- ...(question.criteria ? { criteria: question.criteria } : {}),
218
- };
219
- }
220
- return question;
120
+ return this.dialect().encodeQuestion(question);
121
+ }
122
+ /**
123
+ * The wire family this provider speaks. A provider on another layout
124
+ * overrides it; every one so far speaks System One.
125
+ */
126
+ dialect() {
127
+ return systemOneDialect;
221
128
  }
222
129
  /**
223
130
  * How long a rate-limited or unavailable response asks the caller to wait.
@@ -389,7 +296,10 @@ export class SystemOneDecisionProvider extends BaseProvider {
389
296
  continue;
390
297
  }
391
298
  const decoded = this.readDecisionPayload(payload);
392
- if (!isRecord(decoded) || !isRecord(decoded.answers)) {
299
+ const reading = isRecord(decoded)
300
+ ? this.dialect().readAnswers(decoded, this.reportedConfidence(decoded))
301
+ : undefined;
302
+ if (!isRecord(decoded) || !reading) {
393
303
  throw this.decisionError({
394
304
  kind: "server",
395
305
  message: `${label} returned a response without an answers map.`,
@@ -398,19 +308,12 @@ export class SystemOneDecisionProvider extends BaseProvider {
398
308
  retryable: false,
399
309
  });
400
310
  }
401
- const reported = this.reportedConfidence(decoded);
402
- const answers = {};
403
- for (const [id, raw] of Object.entries(decoded.answers)) {
404
- const parsed = parseDecisionAnswer(raw, reported[id]);
405
- if (parsed) {
406
- answers[id] = parsed;
407
- }
408
- else {
409
- logger.warn(`${label}: dropped unparseable answer "${id}"`, {
410
- requestId,
411
- });
412
- }
311
+ for (const id of reading.dropped) {
312
+ logger.warn(`${label}: dropped unparseable answer "${id}"`, {
313
+ requestId,
314
+ });
413
315
  }
316
+ const answers = { ...reading.answers };
414
317
  const usage = isRecord(decoded.usage) ? decoded.usage : {};
415
318
  return {
416
319
  // `resolvedModel`, not `this.modelName`: when the caller pinned a
@@ -522,3 +522,20 @@ export type DecisionBooleanGate = {
522
522
  /** Minimum {@link decisionBooleanConfidence} to act at all. Default 0.4. */
523
523
  minConfidence?: number;
524
524
  };
525
+ /** The wire family a decide provider speaks. */
526
+ export type DecideDialectName = "system-one";
527
+ export type DecisionAnswerReading = {
528
+ readonly answers: Readonly<Record<string, DecisionAnswer>>;
529
+ /** Ids of answers the server returned that could not be parsed. */
530
+ readonly dropped: readonly string[];
531
+ };
532
+ /**
533
+ * How questions are written to, and answers read from, a decide wire. One
534
+ * dialect serves every vendor that speaks the same layout.
535
+ */
536
+ export type DecisionDialect = {
537
+ readonly name: DecideDialectName;
538
+ encodeQuestion: (question: DecisionQuestion) => Record<string, unknown>;
539
+ /** `undefined` means the response has no usable answers container. */
540
+ readAnswers: (decoded: Readonly<Record<string, unknown>>, reportedConfidence: Readonly<Record<string, number>>) => DecisionAnswerReading | undefined;
541
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "12.49.8",
3
+ "version": "12.49.10",
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": {