@juspay/neurolink 12.41.3 → 12.41.5
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 +410 -408
- package/dist/core/baseProvider.js +24 -13
- package/dist/middleware/builtin/lifecycle.js +29 -6
- package/dist/neurolink.js +16 -13
- package/dist/providers/amazonBedrock/client.d.ts +27 -0
- package/dist/providers/amazonBedrock/client.js +418 -113
- package/dist/providers/amazonBedrock/modelBridge.d.ts +100 -0
- package/dist/providers/amazonBedrock/modelBridge.js +226 -0
- package/dist/providers/googleVertex/client.d.ts +20 -0
- package/dist/providers/googleVertex/client.js +42 -20
- package/dist/utils/lifecycleCallbacks.d.ts +30 -1
- package/dist/utils/lifecycleCallbacks.js +93 -0
- package/package.json +1 -1
|
@@ -24,7 +24,7 @@ import { sanitizeErrorCause } from "../utils/logSanitize.js";
|
|
|
24
24
|
import { createAnalytics as buildAnalytics } from "./analytics.js";
|
|
25
25
|
import { ErrorCategory, ErrorSeverity } from "../constants/enums.js";
|
|
26
26
|
import { duckTypedStatusCode, extractRetryAfterMsFromError, } from "../utils/providerRetry.js";
|
|
27
|
-
import { hasLifecycleErrorFired, markLifecycleErrorFired, } from "../utils/lifecycleCallbacks.js";
|
|
27
|
+
import { getLifecycleMiddlewareConfig, hasLifecycleErrorFired, markLifecycleErrorFired, } from "../utils/lifecycleCallbacks.js";
|
|
28
28
|
import { resolveLifecycleTimeoutMs } from "../utils/lifecycleTimeout.js";
|
|
29
29
|
import { logger } from "../utils/logger.js";
|
|
30
30
|
import { interleaveTTSStream } from "../utils/ttsStream.js";
|
|
@@ -51,18 +51,6 @@ import { generateOnceNative } from "../utils/nativeSingleShot.js";
|
|
|
51
51
|
import { validateExecutionControl } from "../utils/parameterValidation.js";
|
|
52
52
|
import { extractTokenUsage } from "../utils/tokenUtils.js";
|
|
53
53
|
import { preserveLiveStreamAccessors } from "../utils/streamResultAccessors.js";
|
|
54
|
-
/**
|
|
55
|
-
* Read the consumer-facing lifecycle callbacks buried inside a request's
|
|
56
|
-
* middleware blob. The parameter is `unknown` on purpose: request options
|
|
57
|
-
* arrive as several structurally-unrelated shapes (StreamOptions,
|
|
58
|
-
* TextGenerationOptions), and the lifecycle branch is an optional add-on
|
|
59
|
-
* none of them declare — a single structural view keeps the read cast-free
|
|
60
|
-
* at every call site.
|
|
61
|
-
*/
|
|
62
|
-
function getLifecycleMiddlewareConfig(options) {
|
|
63
|
-
return options?.middleware
|
|
64
|
-
?.middlewareConfig?.lifecycle?.config;
|
|
65
|
-
}
|
|
66
54
|
/**
|
|
67
55
|
* Abstract base class for all AI providers
|
|
68
56
|
* Tools are integrated as first-class citizens - always available by default
|
|
@@ -819,9 +807,32 @@ export class BaseProvider {
|
|
|
819
807
|
yield chunk;
|
|
820
808
|
}
|
|
821
809
|
if (onFinish) {
|
|
810
|
+
// Read `result.usage` / `result.finishReason` here, after the
|
|
811
|
+
// drain loop above has fully exhausted `upstreamIterable` — the
|
|
812
|
+
// same point native background-loop providers (Vertex's Gemini3
|
|
813
|
+
// and Claude paths) resolve these fields by, whether they are
|
|
814
|
+
// plain values set before `result` was returned or live getters
|
|
815
|
+
// preserved through `withStreamModelFallback`
|
|
816
|
+
// (`preserveLiveStreamAccessors`). Both fields are generic
|
|
817
|
+
// `StreamResult` members for every provider, not Vertex-specific,
|
|
818
|
+
// so this enrichment is additive for all of them: only present
|
|
819
|
+
// when `result` actually carries a value, never a synthesized
|
|
820
|
+
// default (a provider that never populated these fields keeps
|
|
821
|
+
// getting the exact same bare `{text, duration}` payload as
|
|
822
|
+
// before).
|
|
823
|
+
const { usage, finishReason } = result;
|
|
822
824
|
await safeFire(() => onFinish({
|
|
823
825
|
text: accumulated,
|
|
824
826
|
duration: Date.now() - startTime,
|
|
827
|
+
...(usage
|
|
828
|
+
? {
|
|
829
|
+
usage: {
|
|
830
|
+
promptTokens: usage.input ?? 0,
|
|
831
|
+
completionTokens: usage.output ?? 0,
|
|
832
|
+
},
|
|
833
|
+
}
|
|
834
|
+
: {}),
|
|
835
|
+
...(finishReason ? { finishReason } : {}),
|
|
825
836
|
}), "onFinish");
|
|
826
837
|
}
|
|
827
838
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { logger } from "../../utils/logger.js";
|
|
2
2
|
import { isRecoverableError } from "../../utils/errorHandling.js";
|
|
3
|
-
import { fireOnErrorOnce } from "../../utils/lifecycleCallbacks.js";
|
|
3
|
+
import { fireOnErrorOnce, isLifecycleStreamCallbacksOwnedByBaseProvider, } from "../../utils/lifecycleCallbacks.js";
|
|
4
4
|
/**
|
|
5
5
|
* Normalize a thrown value to an `Error` while preserving structured
|
|
6
6
|
* fields (`code`, `status`, `statusCode`, `retryAfter`, `details`,
|
|
@@ -88,19 +88,42 @@ export function createLifecycleMiddleware(config = {}) {
|
|
|
88
88
|
if (!config.onChunk && !config.onFinish && !config.onError) {
|
|
89
89
|
return result;
|
|
90
90
|
}
|
|
91
|
+
// BaseProvider.wrapStreamWithLifecycleCallbacks already fires
|
|
92
|
+
// onChunk/onFinish for this exact config object, from NeuroLink's
|
|
93
|
+
// own normalized stream, for every NeuroLink-internal stream() call
|
|
94
|
+
// regardless of provider/transport. When that marker is present,
|
|
95
|
+
// firing onChunk/onFinish here too would deliver each one twice —
|
|
96
|
+
// once from these raw, provider-shaped V3 chunks, once from
|
|
97
|
+
// BaseProvider's normalized ones. onError is NOT covered by this
|
|
98
|
+
// flag: it keeps its own, independent dedup via `fireOnErrorOnce`'s
|
|
99
|
+
// shared fired-marker below, unchanged.
|
|
100
|
+
const streamCallbacksOwnedByBaseProvider = isLifecycleStreamCallbacksOwnedByBaseProvider(config);
|
|
91
101
|
let sequenceNumber = 0;
|
|
92
102
|
let accumulatedText = "";
|
|
93
103
|
const transformStream = new TransformStream({
|
|
94
104
|
transform(chunk, controller) {
|
|
95
105
|
try {
|
|
96
|
-
|
|
97
|
-
|
|
106
|
+
// V3 stream parts carry the delta on `delta` (see
|
|
107
|
+
// LanguageModelV3StreamPart in types/aiCompat.ts); `textDelta`
|
|
108
|
+
// is a V2-era AI-SDK field that V3 providers (e.g. Bedrock's
|
|
109
|
+
// bridge, this package's own openaiChatCompletionsBase) never
|
|
110
|
+
// set. Reading `chunk.textDelta` alone silently produced
|
|
111
|
+
// `undefined`, which string-concatenated into a literal
|
|
112
|
+
// "undefined" per chunk. Falling back to `textDelta` keeps any
|
|
113
|
+
// caller still emitting the older shape working unchanged.
|
|
114
|
+
const textDelta = chunk.type === "text-delta"
|
|
115
|
+
? (chunk.delta ?? chunk.textDelta)
|
|
116
|
+
: undefined;
|
|
117
|
+
if (chunk.type === "text-delta" && textDelta !== undefined) {
|
|
118
|
+
accumulatedText += textDelta;
|
|
98
119
|
}
|
|
99
|
-
if (config.onChunk &&
|
|
120
|
+
if (config.onChunk &&
|
|
121
|
+
chunk.type &&
|
|
122
|
+
!streamCallbacksOwnedByBaseProvider) {
|
|
100
123
|
try {
|
|
101
124
|
const callbackResult = config.onChunk({
|
|
102
125
|
type: chunk.type,
|
|
103
|
-
textDelta
|
|
126
|
+
textDelta,
|
|
104
127
|
sequenceNumber: sequenceNumber++,
|
|
105
128
|
});
|
|
106
129
|
Promise.resolve(callbackResult).catch((e) => {
|
|
@@ -124,7 +147,7 @@ export function createLifecycleMiddleware(config = {}) {
|
|
|
124
147
|
}
|
|
125
148
|
},
|
|
126
149
|
flush() {
|
|
127
|
-
if (config.onFinish) {
|
|
150
|
+
if (config.onFinish && !streamCallbacksOwnedByBaseProvider) {
|
|
128
151
|
try {
|
|
129
152
|
const callbackResult = config.onFinish({
|
|
130
153
|
text: accumulatedText,
|
package/dist/neurolink.js
CHANGED
|
@@ -79,7 +79,7 @@ import { tracers } from "./telemetry/tracers.js";
|
|
|
79
79
|
import { getConversationMessages, storeConversationTurn, } from "./utils/conversationMemory.js";
|
|
80
80
|
// Enhanced error handling imports
|
|
81
81
|
import { CircuitBreaker, ERROR_CODES, ErrorFactory, isAbortError, isRetriableError, logStructuredError, NeuroLinkError, withRetry, withTimeout, } from "./utils/errorHandling.js";
|
|
82
|
-
import { hasLifecycleErrorFired, markLifecycleErrorFired, } from "./utils/lifecycleCallbacks.js";
|
|
82
|
+
import { hasLifecycleErrorFired, markLifecycleErrorFired, markLifecycleStreamCallbacksOwnedByBaseProvider, } from "./utils/lifecycleCallbacks.js";
|
|
83
83
|
import { interleaveTTSStream } from "./utils/ttsStream.js";
|
|
84
84
|
import { resolveLifecycleTimeoutMs } from "./utils/lifecycleTimeout.js";
|
|
85
85
|
import { cloneOptionsForCallIsolation } from "./utils/cloneOptions.js";
|
|
@@ -782,6 +782,20 @@ export class NeuroLink {
|
|
|
782
782
|
if (!options.onFinish && !options.onError && !options.onChunk) {
|
|
783
783
|
return;
|
|
784
784
|
}
|
|
785
|
+
const config = {
|
|
786
|
+
...options.middleware?.middlewareConfig?.lifecycle?.config,
|
|
787
|
+
...(options.onFinish !== undefined ? { onFinish: options.onFinish } : {}),
|
|
788
|
+
...(options.onError !== undefined ? { onError: options.onError } : {}),
|
|
789
|
+
...(options.onChunk !== undefined ? { onChunk: options.onChunk } : {}),
|
|
790
|
+
};
|
|
791
|
+
// BaseProvider.wrapStreamWithLifecycleCallbacks unconditionally wraps
|
|
792
|
+
// every provider's stream() result and fires onChunk/onFinish from
|
|
793
|
+
// there, reliably, for this exact config object. Stamp it so the
|
|
794
|
+
// model-level lifecycle middleware (builtin/lifecycle.ts) skips its own
|
|
795
|
+
// onChunk/onFinish firing for it instead of delivering each one twice.
|
|
796
|
+
// See markLifecycleStreamCallbacksOwnedByBaseProvider's doc comment for
|
|
797
|
+
// why generate()'s config below is never stamped this way.
|
|
798
|
+
markLifecycleStreamCallbacksOwnedByBaseProvider(config);
|
|
785
799
|
options.middleware = {
|
|
786
800
|
...options.middleware,
|
|
787
801
|
middlewareConfig: {
|
|
@@ -789,18 +803,7 @@ export class NeuroLink {
|
|
|
789
803
|
lifecycle: {
|
|
790
804
|
...options.middleware?.middlewareConfig?.lifecycle,
|
|
791
805
|
enabled: true,
|
|
792
|
-
config
|
|
793
|
-
...options.middleware?.middlewareConfig?.lifecycle?.config,
|
|
794
|
-
...(options.onFinish !== undefined
|
|
795
|
-
? { onFinish: options.onFinish }
|
|
796
|
-
: {}),
|
|
797
|
-
...(options.onError !== undefined
|
|
798
|
-
? { onError: options.onError }
|
|
799
|
-
: {}),
|
|
800
|
-
...(options.onChunk !== undefined
|
|
801
|
-
? { onChunk: options.onChunk }
|
|
802
|
-
: {}),
|
|
803
|
-
},
|
|
806
|
+
config,
|
|
804
807
|
},
|
|
805
808
|
},
|
|
806
809
|
};
|
|
@@ -68,6 +68,33 @@ export declare class AmazonBedrockProvider extends BaseProvider {
|
|
|
68
68
|
private convertToBedrockMessages;
|
|
69
69
|
getBedrockClient(): BedrockRuntimeClient;
|
|
70
70
|
protected executeStream(options: StreamOptions): Promise<StreamResult>;
|
|
71
|
+
/**
|
|
72
|
+
* A multimodal turn skips model middleware (see modelBridge.ts's header).
|
|
73
|
+
* WARN when middleware was configured, per request or on the provider,
|
|
74
|
+
* since it silently did not run; multimodal turns alone are unremarkable,
|
|
75
|
+
* so stay at debug otherwise.
|
|
76
|
+
*/
|
|
77
|
+
private logMultimodalMiddlewareSkip;
|
|
78
|
+
/**
|
|
79
|
+
* `inferenceConfig` carries `maxTokens` and `temperature` only, so any other
|
|
80
|
+
* sampling option a middleware sets would be dropped without a trace.
|
|
81
|
+
* `tools` is reported where it is compared, at each call site.
|
|
82
|
+
*/
|
|
83
|
+
private warnOnUnsentMiddlewareOptions;
|
|
84
|
+
/**
|
|
85
|
+
* Runs the turn behind `streamingConversationLoop`: the model-middleware
|
|
86
|
+
* path for a text-only starting turn, or the direct fallback for a
|
|
87
|
+
* multimodal one. Extracted only to keep `streamingConversationLoop`
|
|
88
|
+
* readable — the branching logic itself is unchanged from what it
|
|
89
|
+
* replaced.
|
|
90
|
+
*/
|
|
91
|
+
private buildBedrockStreamTurn;
|
|
92
|
+
/**
|
|
93
|
+
* Turns a settled loop outcome's usage into the shape both the analytics
|
|
94
|
+
* resolution and the stream's own `finally` block report. Shared so the
|
|
95
|
+
* two call sites in `streamingConversationLoop` can't drift.
|
|
96
|
+
*/
|
|
97
|
+
private summarizeBedrockStreamUsage;
|
|
71
98
|
private streamingConversationLoop;
|
|
72
99
|
/**
|
|
73
100
|
* Health check for Amazon Bedrock service
|