@juspay/neurolink 9.81.3 → 9.83.0
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 +18 -0
- package/README.md +4 -0
- package/dist/browser/neurolink.min.js +342 -342
- package/dist/cli/commands/proxy.js +5 -0
- package/dist/cli/factories/commandFactory.d.ts +2 -1
- package/dist/cli/factories/commandFactory.js +36 -16
- package/dist/cli/utils/audioPlayer.d.ts +37 -0
- package/dist/cli/utils/audioPlayer.js +138 -0
- package/dist/core/modules/GenerationHandler.js +7 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.js +14 -6
- package/dist/lib/core/modules/GenerationHandler.js +7 -1
- package/dist/lib/index.d.ts +6 -1
- package/dist/lib/index.js +14 -6
- package/dist/lib/providers/googleAiStudio.js +25 -4
- package/dist/lib/providers/googleNativeGemini3.js +22 -2
- package/dist/lib/providers/googleVertex.js +28 -4
- package/dist/lib/proxy/proxyDispatcher.d.ts +5 -0
- package/dist/lib/proxy/proxyDispatcher.js +61 -0
- package/dist/lib/types/common.d.ts +3 -0
- package/dist/lib/types/providers.d.ts +8 -0
- package/dist/lib/utils/pricing.js +144 -26
- package/dist/lib/utils/systemMessages.d.ts +29 -0
- package/dist/lib/utils/systemMessages.js +45 -0
- package/dist/lib/utils/tokenUtils.d.ts +11 -0
- package/dist/lib/utils/tokenUtils.js +33 -2
- package/dist/providers/googleAiStudio.js +25 -4
- package/dist/providers/googleNativeGemini3.js +22 -2
- package/dist/providers/googleVertex.js +28 -4
- package/dist/proxy/proxyDispatcher.d.ts +5 -0
- package/dist/proxy/proxyDispatcher.js +60 -0
- package/dist/types/common.d.ts +3 -0
- package/dist/types/providers.d.ts +8 -0
- package/dist/utils/pricing.js +144 -26
- package/dist/utils/systemMessages.d.ts +29 -0
- package/dist/utils/systemMessages.js +44 -0
- package/dist/utils/tokenUtils.d.ts +11 -0
- package/dist/utils/tokenUtils.js +33 -2
- package/package.json +3 -2
|
@@ -17,6 +17,7 @@ import ora from "ora";
|
|
|
17
17
|
import { buildProxyHealthResponse, createProxyReadinessState, markProxyReady, waitForProxyReadiness, } from "../../lib/proxy/proxyHealth.js";
|
|
18
18
|
import { logger } from "../../lib/utils/logger.js";
|
|
19
19
|
import { formatUptime, isProcessRunning, StateFileManager, } from "../utils/serverUtils.js";
|
|
20
|
+
import { configureProxyKeepAliveDispatcher } from "../../lib/proxy/proxyDispatcher.js";
|
|
20
21
|
import { loadProxyEnvFile, resolveProxyEnvFile, } from "../../lib/proxy/proxyEnv.js";
|
|
21
22
|
import { createRequire } from "node:module";
|
|
22
23
|
import { fileURLToPath } from "node:url";
|
|
@@ -1285,6 +1286,10 @@ async function startProxyCommandHandler(argv) {
|
|
|
1285
1286
|
await ensureProxyStartAllowed(spinner);
|
|
1286
1287
|
}
|
|
1287
1288
|
const loadedEnvFile = await loadProxyStartEnv(argv, spinner);
|
|
1289
|
+
// Reuse upstream TCP connections (longer keep-alive + bounded pool) instead
|
|
1290
|
+
// of opening a new flow per request — cuts outbound flow churn through host
|
|
1291
|
+
// content-filters. Runs once, after env load so it can be tuned via env.
|
|
1292
|
+
configureProxyKeepAliveDispatcher();
|
|
1288
1293
|
const { neurolink, cleanupLogs } = await createProxyNeurolinkRuntime(devPaths?.logsDir);
|
|
1289
1294
|
const { proxyConfig, strategy, modelRouter, passthrough, primaryAccountKey, } = await loadProxyStartConfiguration(argv, spinner);
|
|
1290
1295
|
if (spinner) {
|
|
@@ -35,8 +35,9 @@ export declare class CLICommandFactory {
|
|
|
35
35
|
private static validateAnthropicSubscriptionOptions;
|
|
36
36
|
private static handleOutput;
|
|
37
37
|
/**
|
|
38
|
-
* Helper method to handle TTS audio file output
|
|
38
|
+
* Helper method to handle TTS audio file output and playback
|
|
39
39
|
* Saves audio to file when --tts-output flag is provided
|
|
40
|
+
* Plays audio when --tts-play flag is provided
|
|
40
41
|
*/
|
|
41
42
|
private static handleTTSOutput;
|
|
42
43
|
/**
|
|
@@ -20,6 +20,7 @@ import { handleError } from "../errorHandler.js";
|
|
|
20
20
|
import { LoopSession } from "../loop/session.js";
|
|
21
21
|
import { initializeCliParser } from "../parser.js";
|
|
22
22
|
import { formatFileSize, saveAudioToFile } from "../utils/audioFileUtils.js";
|
|
23
|
+
import { playAudio } from "../utils/audioPlayer.js";
|
|
23
24
|
import { resolveFilePaths } from "../utils/pathResolver.js";
|
|
24
25
|
import { animatedWrite } from "../utils/typewriter.js";
|
|
25
26
|
import { createStreamAbortHandler } from "../utils/abortHandler.js";
|
|
@@ -1040,13 +1041,15 @@ export class CLICommandFactory {
|
|
|
1040
1041
|
}
|
|
1041
1042
|
}
|
|
1042
1043
|
/**
|
|
1043
|
-
* Helper method to handle TTS audio file output
|
|
1044
|
+
* Helper method to handle TTS audio file output and playback
|
|
1044
1045
|
* Saves audio to file when --tts-output flag is provided
|
|
1046
|
+
* Plays audio when --tts-play flag is provided
|
|
1045
1047
|
*/
|
|
1046
1048
|
static async handleTTSOutput(result, options) {
|
|
1047
|
-
// Check if --tts-output flag is provided
|
|
1048
1049
|
const ttsOutputPath = options.ttsOutput;
|
|
1049
|
-
|
|
1050
|
+
const shouldPlay = options.ttsPlay;
|
|
1051
|
+
// Nothing to do if neither save nor play is requested
|
|
1052
|
+
if (!ttsOutputPath && !shouldPlay) {
|
|
1050
1053
|
return;
|
|
1051
1054
|
}
|
|
1052
1055
|
// Extract audio from result with proper type checking
|
|
@@ -1061,20 +1064,36 @@ export class CLICommandFactory {
|
|
|
1061
1064
|
}
|
|
1062
1065
|
return;
|
|
1063
1066
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
if (
|
|
1069
|
-
|
|
1067
|
+
// Save audio to file if --tts-output is provided
|
|
1068
|
+
if (ttsOutputPath) {
|
|
1069
|
+
try {
|
|
1070
|
+
const saveResult = await saveAudioToFile(audio, ttsOutputPath);
|
|
1071
|
+
if (saveResult.success) {
|
|
1072
|
+
if (!options.quiet) {
|
|
1073
|
+
logger.always(chalk.green(`🔊 Audio saved to: ${saveResult.path} (${formatFileSize(saveResult.size)})`));
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
else {
|
|
1077
|
+
handleError(new Error(saveResult.error || "Failed to save audio file"), "TTS Output");
|
|
1070
1078
|
}
|
|
1071
1079
|
}
|
|
1072
|
-
|
|
1073
|
-
handleError(
|
|
1080
|
+
catch (error) {
|
|
1081
|
+
handleError(error, "TTS Output");
|
|
1074
1082
|
}
|
|
1075
1083
|
}
|
|
1076
|
-
|
|
1077
|
-
|
|
1084
|
+
// Play audio if --tts-play is provided
|
|
1085
|
+
if (shouldPlay) {
|
|
1086
|
+
try {
|
|
1087
|
+
if (!options.quiet) {
|
|
1088
|
+
logger.always(chalk.blue("Playing audio..."));
|
|
1089
|
+
}
|
|
1090
|
+
await playAudio(audio.buffer, audio.format);
|
|
1091
|
+
}
|
|
1092
|
+
catch (err) {
|
|
1093
|
+
// Non-fatal: warn but don't crash
|
|
1094
|
+
logger.always(chalk.yellow(`Audio playback failed: ${err.message}`));
|
|
1095
|
+
logger.always(chalk.yellow(" Tip: Save the audio with --tts-output <file> and play manually."));
|
|
1096
|
+
}
|
|
1078
1097
|
}
|
|
1079
1098
|
}
|
|
1080
1099
|
/**
|
|
@@ -2898,15 +2917,16 @@ export class CLICommandFactory {
|
|
|
2898
2917
|
logger.always(`\nOutput saved to ${options.output}`);
|
|
2899
2918
|
}
|
|
2900
2919
|
}
|
|
2901
|
-
// Handle TTS audio output if --tts-output is provided
|
|
2920
|
+
// Handle TTS audio output/playback if --tts-output or --tts-play is provided
|
|
2902
2921
|
// Note: For streaming, TTS audio is collected during the stream
|
|
2903
2922
|
// and saved at the end if available
|
|
2904
2923
|
const ttsOutputPath = options.ttsOutput;
|
|
2905
|
-
|
|
2924
|
+
const shouldPlay = options.ttsPlay;
|
|
2925
|
+
if (ttsOutputPath || shouldPlay) {
|
|
2906
2926
|
// For now, streaming TTS output is not yet available
|
|
2907
2927
|
// This will be enabled when the TTS streaming infrastructure is complete
|
|
2908
2928
|
if (!options.quiet) {
|
|
2909
|
-
logger.always(chalk.yellow("
|
|
2929
|
+
logger.always(chalk.yellow("TTS audio for streaming is not yet available. Use 'generate' command for TTS output."));
|
|
2910
2930
|
}
|
|
2911
2931
|
}
|
|
2912
2932
|
// Debug output for streaming
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio playback utilities for CLI
|
|
3
|
+
*
|
|
4
|
+
* Provides functionality for playing TTS audio using platform-specific
|
|
5
|
+
* CLI tools with proper cleanup and error handling.
|
|
6
|
+
*
|
|
7
|
+
* @module cli/utils/audioPlayer
|
|
8
|
+
*/
|
|
9
|
+
import type { AudioFormat } from "../../lib/types/index.js";
|
|
10
|
+
/**
|
|
11
|
+
* Get the file extension for an audio format
|
|
12
|
+
*
|
|
13
|
+
* @param format - Audio format
|
|
14
|
+
* @returns File extension string (e.g., "mp3", "wav")
|
|
15
|
+
*/
|
|
16
|
+
export declare function getAudioExtension(format: AudioFormat): string;
|
|
17
|
+
/**
|
|
18
|
+
* Play audio from a buffer using platform-specific CLI tools
|
|
19
|
+
*
|
|
20
|
+
* Writes the buffer to a temporary file, plays it using the appropriate
|
|
21
|
+
* system audio player, and cleans up the temp file afterward.
|
|
22
|
+
*
|
|
23
|
+
* Supported platforms:
|
|
24
|
+
* - macOS: uses `afplay` (built-in, supports mp3/wav/aac/flac)
|
|
25
|
+
* - Linux: uses `paplay` for non-wav, `aplay` for wav
|
|
26
|
+
* - Windows: uses PowerShell SoundPlayer (wav) or WMPlayer.OCX (mp3)
|
|
27
|
+
*
|
|
28
|
+
* @param buffer - Audio data buffer
|
|
29
|
+
* @param format - Audio format (mp3, wav, ogg, opus)
|
|
30
|
+
* @throws Error if playback fails or platform is unsupported
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* await playAudio(audioBuffer, "mp3");
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function playAudio(buffer: Buffer, format: AudioFormat): Promise<void>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audio playback utilities for CLI
|
|
3
|
+
*
|
|
4
|
+
* Provides functionality for playing TTS audio using platform-specific
|
|
5
|
+
* CLI tools with proper cleanup and error handling.
|
|
6
|
+
*
|
|
7
|
+
* @module cli/utils/audioPlayer
|
|
8
|
+
*/
|
|
9
|
+
import { execFile } from "node:child_process";
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import os from "node:os";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { promisify } from "node:util";
|
|
14
|
+
const execFileAsync = promisify(execFile);
|
|
15
|
+
/**
|
|
16
|
+
* Get the file extension for an audio format
|
|
17
|
+
*
|
|
18
|
+
* @param format - Audio format
|
|
19
|
+
* @returns File extension string (e.g., "mp3", "wav")
|
|
20
|
+
*/
|
|
21
|
+
export function getAudioExtension(format) {
|
|
22
|
+
switch (format) {
|
|
23
|
+
case "mp3":
|
|
24
|
+
return "mp3";
|
|
25
|
+
case "wav":
|
|
26
|
+
return "wav";
|
|
27
|
+
case "ogg":
|
|
28
|
+
return "ogg";
|
|
29
|
+
case "opus":
|
|
30
|
+
return "opus";
|
|
31
|
+
default:
|
|
32
|
+
return "mp3";
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get the platform-specific audio player command and arguments
|
|
37
|
+
*
|
|
38
|
+
* @param filePath - Path to the audio file
|
|
39
|
+
* @param format - Audio format
|
|
40
|
+
* @returns Object with command and args for execFile
|
|
41
|
+
*/
|
|
42
|
+
function getPlayerCommand(filePath, format) {
|
|
43
|
+
const platform = process.platform;
|
|
44
|
+
switch (platform) {
|
|
45
|
+
case "darwin":
|
|
46
|
+
return { command: "afplay", args: [filePath] };
|
|
47
|
+
case "linux":
|
|
48
|
+
if (format === "wav") {
|
|
49
|
+
return { command: "aplay", args: [filePath] };
|
|
50
|
+
}
|
|
51
|
+
return { command: "paplay", args: [filePath] };
|
|
52
|
+
case "win32":
|
|
53
|
+
if (format === "wav") {
|
|
54
|
+
return {
|
|
55
|
+
command: "powershell",
|
|
56
|
+
args: [
|
|
57
|
+
"-NoProfile",
|
|
58
|
+
"-Command",
|
|
59
|
+
`(New-Object System.Media.SoundPlayer '${filePath}').PlaySync()`,
|
|
60
|
+
],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
command: "powershell",
|
|
65
|
+
args: [
|
|
66
|
+
"-NoProfile",
|
|
67
|
+
"-Command",
|
|
68
|
+
`$player = New-Object -ComObject WMPlayer.OCX; $player.URL = '${filePath}'; $player.controls.play(); Start-Sleep -Seconds 1; while ($player.playState -eq 3) { Start-Sleep -Milliseconds 100 }; $player.close()`,
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
default:
|
|
72
|
+
throw new Error(`Unsupported platform: ${platform}. Audio playback is supported on macOS, Linux, and Windows.`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Play audio from a buffer using platform-specific CLI tools
|
|
77
|
+
*
|
|
78
|
+
* Writes the buffer to a temporary file, plays it using the appropriate
|
|
79
|
+
* system audio player, and cleans up the temp file afterward.
|
|
80
|
+
*
|
|
81
|
+
* Supported platforms:
|
|
82
|
+
* - macOS: uses `afplay` (built-in, supports mp3/wav/aac/flac)
|
|
83
|
+
* - Linux: uses `paplay` for non-wav, `aplay` for wav
|
|
84
|
+
* - Windows: uses PowerShell SoundPlayer (wav) or WMPlayer.OCX (mp3)
|
|
85
|
+
*
|
|
86
|
+
* @param buffer - Audio data buffer
|
|
87
|
+
* @param format - Audio format (mp3, wav, ogg, opus)
|
|
88
|
+
* @throws Error if playback fails or platform is unsupported
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```typescript
|
|
92
|
+
* await playAudio(audioBuffer, "mp3");
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export async function playAudio(buffer, format) {
|
|
96
|
+
const ext = getAudioExtension(format);
|
|
97
|
+
const tempFile = path.join(os.tmpdir(), `nl-tts-${Date.now()}.${ext}`);
|
|
98
|
+
try {
|
|
99
|
+
// Write audio buffer to temp file
|
|
100
|
+
await fs.promises.writeFile(tempFile, buffer);
|
|
101
|
+
const { command, args } = getPlayerCommand(tempFile, format);
|
|
102
|
+
try {
|
|
103
|
+
await execFileAsync(command, args);
|
|
104
|
+
}
|
|
105
|
+
catch (execError) {
|
|
106
|
+
const err = execError;
|
|
107
|
+
// Handle binary not found
|
|
108
|
+
if (err.code === "ENOENT") {
|
|
109
|
+
if (process.platform === "linux" && command === "paplay") {
|
|
110
|
+
// Fallback to aplay on Linux
|
|
111
|
+
try {
|
|
112
|
+
await execFileAsync("aplay", [tempFile]);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
catch (fallbackError) {
|
|
116
|
+
const fbErr = fallbackError;
|
|
117
|
+
if (fbErr.code === "ENOENT") {
|
|
118
|
+
throw new Error("Neither paplay nor aplay found. Install PulseAudio (paplay) or ALSA (aplay) for audio playback.", { cause: fallbackError });
|
|
119
|
+
}
|
|
120
|
+
throw fallbackError;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
throw new Error(`Audio player '${command}' not found. Ensure it is installed and available in PATH.`, { cause: execError });
|
|
124
|
+
}
|
|
125
|
+
throw execError;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
// Always clean up temp file
|
|
130
|
+
try {
|
|
131
|
+
await fs.promises.unlink(tempFile);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// Ignore cleanup errors
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=audioPlayer.js.map
|
|
@@ -26,6 +26,7 @@ import { coerceJsonToSchema } from "../../utils/json/coerce.js";
|
|
|
26
26
|
import { NoObjectGeneratedError } from "../../utils/generationErrors.js";
|
|
27
27
|
import { Output, stepCountIs } from "../../utils/tool.js";
|
|
28
28
|
import { generateText } from "../../utils/generation.js";
|
|
29
|
+
import { extractSystemMessages } from "../../utils/systemMessages.js";
|
|
29
30
|
const genTracer = tracers.generation;
|
|
30
31
|
/**
|
|
31
32
|
* Safely preview-serialize a value for debug logging.
|
|
@@ -105,9 +106,14 @@ export class GenerationHandler {
|
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
const prepareStep = options.prepareStep;
|
|
109
|
+
// Hoist system-role messages into generateText's top-level `system` option
|
|
110
|
+
// rather than passing them inside `messages` (deprecated by the AI SDK,
|
|
111
|
+
// rejected in v7). See extractSystemMessages for the rationale. (#1024)
|
|
112
|
+
const { system, messages: nonSystemMessages } = extractSystemMessages(messages);
|
|
108
113
|
return await generateText({
|
|
109
114
|
model,
|
|
110
|
-
|
|
115
|
+
...(system && { system }),
|
|
116
|
+
messages: nonSystemMessages,
|
|
111
117
|
...(shouldUseTools &&
|
|
112
118
|
Object.keys(toolsWithCache).length > 0 && { tools: toolsWithCache }),
|
|
113
119
|
stopWhen: stepCountIs(options.maxSteps ?? DEFAULT_MAX_STEPS),
|
package/dist/index.d.ts
CHANGED
|
@@ -35,7 +35,12 @@ import { AIProviderFactory } from "./core/factory.js";
|
|
|
35
35
|
export { AIProviderFactory };
|
|
36
36
|
export { NeuroLinkConfigManager as ConfigManager } from "./config/configManager.js";
|
|
37
37
|
export { BaseFactory, BaseRegistry, NeuroLinkFeatureError, createErrorFactory, withRetry, TypedEventEmitter, } from "./core/infrastructure/index.js";
|
|
38
|
-
export { NeuroLinkClient, createClient, NeuroLinkApiError,
|
|
38
|
+
export { NeuroLinkClient, createClient, NeuroLinkApiError, } from "./client/httpClient.js";
|
|
39
|
+
export { NeuroLinkLanguageModel, NeuroLinkProvider as NeuroLinkAIProvider, createNeuroLinkProvider, createNeuroLinkModel, createStreamingResponse, neurolink as neuroLinkAIInstance, } from "./client/aiSdkAdapter.js";
|
|
40
|
+
export { createApiKeyAuthInterceptor, createBearerAuthInterceptor, createDynamicAuthInterceptor, createLoggingInterceptor, createRetryInterceptor, createRateLimitInterceptor, createRequestTransformInterceptor, createResponseTransformInterceptor, createCacheInterceptor, createTimeoutInterceptor, createErrorHandlerInterceptor, composeMiddleware, conditionalMiddleware, } from "./client/interceptors.js";
|
|
41
|
+
export { SSEClient, WebSocketStreamingClient, createStreamingClient, createAsyncStream, collectStream, } from "./client/streamingClient.js";
|
|
42
|
+
export { OAuth2TokenManager, JWTTokenManager, createApiKeyMiddleware, createBearerTokenMiddleware, createTokenManagerMiddleware, createAuthWithRetryMiddleware, createMultiAuthMiddleware, OAuth2Error, OAuth2AuthenticationError as OAuth2AuthError, TokenRefreshError, decodeJWTPayload, isJWTExpired, getJWTExpiry, getApiKeyFromEnv, } from "./client/auth.js";
|
|
43
|
+
export { ErrorCode as ClientErrorCode, NeuroLinkError as ClientNeuroLinkError, HttpError, ClientRateLimitError, ClientValidationError, ClientAuthenticationError, ClientAuthorizationError, NotFoundError, ClientNetworkError, ClientTimeoutError, ClientConnectionError, AbortError, ClientConfigurationError, StreamError, ClientProviderError, ContextLengthError, ContentFilterError, createErrorFromResponse, createErrorFromNative, mapStatusToErrorCode, isRetryableStatus, isRetryableError, isNeuroLinkError, isApiError, } from "./client/errors.js";
|
|
39
44
|
export { AIProviderName, BedrockModels, OpenAIModels, VertexModels, } from "./constants/enums.js";
|
|
40
45
|
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
41
46
|
export { validateTool } from "./sdk/toolRegistration.js";
|
package/dist/index.js
CHANGED
|
@@ -41,20 +41,28 @@ export { BaseFactory, BaseRegistry, NeuroLinkFeatureError, createErrorFactory, w
|
|
|
41
41
|
// ============================================================================
|
|
42
42
|
// CLIENT SDK EXPORTS - Type-safe API access for browser and Node.js
|
|
43
43
|
// Note: React hooks are NOT re-exported here. Import from '@juspay/neurolink/client'.
|
|
44
|
+
// These re-exports intentionally bypass ./client/index.js: that barrel statically
|
|
45
|
+
// re-exports ./reactHooks.js, so routing through it makes the ROOT import require
|
|
46
|
+
// `react` (an optional peer dep) and crash react-less installs at import time.
|
|
44
47
|
// ============================================================================
|
|
45
48
|
export {
|
|
46
49
|
// HTTP Client
|
|
47
|
-
NeuroLinkClient, createClient, NeuroLinkApiError,
|
|
50
|
+
NeuroLinkClient, createClient, NeuroLinkApiError, } from "./client/httpClient.js";
|
|
51
|
+
export {
|
|
48
52
|
// AI SDK Adapter
|
|
49
|
-
NeuroLinkLanguageModel, NeuroLinkAIProvider, createNeuroLinkProvider, createNeuroLinkModel, createStreamingResponse, neurolink as neuroLinkAIInstance,
|
|
53
|
+
NeuroLinkLanguageModel, NeuroLinkProvider as NeuroLinkAIProvider, createNeuroLinkProvider, createNeuroLinkModel, createStreamingResponse, neurolink as neuroLinkAIInstance, } from "./client/aiSdkAdapter.js";
|
|
54
|
+
export {
|
|
50
55
|
// Interceptors
|
|
51
|
-
createApiKeyAuthInterceptor, createBearerAuthInterceptor, createDynamicAuthInterceptor, createLoggingInterceptor, createRetryInterceptor, createRateLimitInterceptor, createRequestTransformInterceptor, createResponseTransformInterceptor, createCacheInterceptor, createTimeoutInterceptor, createErrorHandlerInterceptor, composeMiddleware, conditionalMiddleware,
|
|
56
|
+
createApiKeyAuthInterceptor, createBearerAuthInterceptor, createDynamicAuthInterceptor, createLoggingInterceptor, createRetryInterceptor, createRateLimitInterceptor, createRequestTransformInterceptor, createResponseTransformInterceptor, createCacheInterceptor, createTimeoutInterceptor, createErrorHandlerInterceptor, composeMiddleware, conditionalMiddleware, } from "./client/interceptors.js";
|
|
57
|
+
export {
|
|
52
58
|
// Streaming Client
|
|
53
|
-
SSEClient, WebSocketStreamingClient, createStreamingClient, createAsyncStream, collectStream,
|
|
59
|
+
SSEClient, WebSocketStreamingClient, createStreamingClient, createAsyncStream, collectStream, } from "./client/streamingClient.js";
|
|
60
|
+
export {
|
|
54
61
|
// Authentication
|
|
55
|
-
OAuth2TokenManager, JWTTokenManager, createApiKeyMiddleware, createBearerTokenMiddleware, createTokenManagerMiddleware, createAuthWithRetryMiddleware, createMultiAuthMiddleware, OAuth2Error, OAuth2AuthError, TokenRefreshError, decodeJWTPayload, isJWTExpired, getJWTExpiry, getApiKeyFromEnv,
|
|
62
|
+
OAuth2TokenManager, JWTTokenManager, createApiKeyMiddleware, createBearerTokenMiddleware, createTokenManagerMiddleware, createAuthWithRetryMiddleware, createMultiAuthMiddleware, OAuth2Error, OAuth2AuthenticationError as OAuth2AuthError, TokenRefreshError, decodeJWTPayload, isJWTExpired, getJWTExpiry, getApiKeyFromEnv, } from "./client/auth.js";
|
|
63
|
+
export {
|
|
56
64
|
// Errors
|
|
57
|
-
ErrorCode as ClientErrorCode, NeuroLinkError as ClientNeuroLinkError, HttpError, ClientRateLimitError, ClientValidationError, ClientAuthenticationError, ClientAuthorizationError, NotFoundError, ClientNetworkError, ClientTimeoutError, ClientConnectionError, AbortError, ClientConfigurationError, StreamError, ClientProviderError, ContextLengthError, ContentFilterError, createErrorFromResponse, createErrorFromNative, mapStatusToErrorCode, isRetryableStatus, isRetryableError, isNeuroLinkError, isApiError, } from "./client/
|
|
65
|
+
ErrorCode as ClientErrorCode, NeuroLinkError as ClientNeuroLinkError, HttpError, ClientRateLimitError, ClientValidationError, ClientAuthenticationError, ClientAuthorizationError, NotFoundError, ClientNetworkError, ClientTimeoutError, ClientConnectionError, AbortError, ClientConfigurationError, StreamError, ClientProviderError, ContextLengthError, ContentFilterError, createErrorFromResponse, createErrorFromNative, mapStatusToErrorCode, isRetryableStatus, isRetryableError, isNeuroLinkError, isApiError, } from "./client/errors.js";
|
|
58
66
|
export { AIProviderName, BedrockModels, OpenAIModels, VertexModels, } from "./constants/enums.js";
|
|
59
67
|
// Dynamic Models exports
|
|
60
68
|
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
@@ -26,6 +26,7 @@ import { coerceJsonToSchema } from "../../utils/json/coerce.js";
|
|
|
26
26
|
import { NoObjectGeneratedError } from "../../utils/generationErrors.js";
|
|
27
27
|
import { Output, stepCountIs } from "../../utils/tool.js";
|
|
28
28
|
import { generateText } from "../../utils/generation.js";
|
|
29
|
+
import { extractSystemMessages } from "../../utils/systemMessages.js";
|
|
29
30
|
const genTracer = tracers.generation;
|
|
30
31
|
/**
|
|
31
32
|
* Safely preview-serialize a value for debug logging.
|
|
@@ -105,9 +106,14 @@ export class GenerationHandler {
|
|
|
105
106
|
}
|
|
106
107
|
}
|
|
107
108
|
const prepareStep = options.prepareStep;
|
|
109
|
+
// Hoist system-role messages into generateText's top-level `system` option
|
|
110
|
+
// rather than passing them inside `messages` (deprecated by the AI SDK,
|
|
111
|
+
// rejected in v7). See extractSystemMessages for the rationale. (#1024)
|
|
112
|
+
const { system, messages: nonSystemMessages } = extractSystemMessages(messages);
|
|
108
113
|
return await generateText({
|
|
109
114
|
model,
|
|
110
|
-
|
|
115
|
+
...(system && { system }),
|
|
116
|
+
messages: nonSystemMessages,
|
|
111
117
|
...(shouldUseTools &&
|
|
112
118
|
Object.keys(toolsWithCache).length > 0 && { tools: toolsWithCache }),
|
|
113
119
|
stopWhen: stepCountIs(options.maxSteps ?? DEFAULT_MAX_STEPS),
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -35,7 +35,12 @@ import { AIProviderFactory } from "./core/factory.js";
|
|
|
35
35
|
export { AIProviderFactory };
|
|
36
36
|
export { NeuroLinkConfigManager as ConfigManager } from "./config/configManager.js";
|
|
37
37
|
export { BaseFactory, BaseRegistry, NeuroLinkFeatureError, createErrorFactory, withRetry, TypedEventEmitter, } from "./core/infrastructure/index.js";
|
|
38
|
-
export { NeuroLinkClient, createClient, NeuroLinkApiError,
|
|
38
|
+
export { NeuroLinkClient, createClient, NeuroLinkApiError, } from "./client/httpClient.js";
|
|
39
|
+
export { NeuroLinkLanguageModel, NeuroLinkProvider as NeuroLinkAIProvider, createNeuroLinkProvider, createNeuroLinkModel, createStreamingResponse, neurolink as neuroLinkAIInstance, } from "./client/aiSdkAdapter.js";
|
|
40
|
+
export { createApiKeyAuthInterceptor, createBearerAuthInterceptor, createDynamicAuthInterceptor, createLoggingInterceptor, createRetryInterceptor, createRateLimitInterceptor, createRequestTransformInterceptor, createResponseTransformInterceptor, createCacheInterceptor, createTimeoutInterceptor, createErrorHandlerInterceptor, composeMiddleware, conditionalMiddleware, } from "./client/interceptors.js";
|
|
41
|
+
export { SSEClient, WebSocketStreamingClient, createStreamingClient, createAsyncStream, collectStream, } from "./client/streamingClient.js";
|
|
42
|
+
export { OAuth2TokenManager, JWTTokenManager, createApiKeyMiddleware, createBearerTokenMiddleware, createTokenManagerMiddleware, createAuthWithRetryMiddleware, createMultiAuthMiddleware, OAuth2Error, OAuth2AuthenticationError as OAuth2AuthError, TokenRefreshError, decodeJWTPayload, isJWTExpired, getJWTExpiry, getApiKeyFromEnv, } from "./client/auth.js";
|
|
43
|
+
export { ErrorCode as ClientErrorCode, NeuroLinkError as ClientNeuroLinkError, HttpError, ClientRateLimitError, ClientValidationError, ClientAuthenticationError, ClientAuthorizationError, NotFoundError, ClientNetworkError, ClientTimeoutError, ClientConnectionError, AbortError, ClientConfigurationError, StreamError, ClientProviderError, ContextLengthError, ContentFilterError, createErrorFromResponse, createErrorFromNative, mapStatusToErrorCode, isRetryableStatus, isRetryableError, isNeuroLinkError, isApiError, } from "./client/errors.js";
|
|
39
44
|
export { AIProviderName, BedrockModels, OpenAIModels, VertexModels, } from "./constants/enums.js";
|
|
40
45
|
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
41
46
|
export { validateTool } from "./sdk/toolRegistration.js";
|
package/dist/lib/index.js
CHANGED
|
@@ -41,20 +41,28 @@ export { BaseFactory, BaseRegistry, NeuroLinkFeatureError, createErrorFactory, w
|
|
|
41
41
|
// ============================================================================
|
|
42
42
|
// CLIENT SDK EXPORTS - Type-safe API access for browser and Node.js
|
|
43
43
|
// Note: React hooks are NOT re-exported here. Import from '@juspay/neurolink/client'.
|
|
44
|
+
// These re-exports intentionally bypass ./client/index.js: that barrel statically
|
|
45
|
+
// re-exports ./reactHooks.js, so routing through it makes the ROOT import require
|
|
46
|
+
// `react` (an optional peer dep) and crash react-less installs at import time.
|
|
44
47
|
// ============================================================================
|
|
45
48
|
export {
|
|
46
49
|
// HTTP Client
|
|
47
|
-
NeuroLinkClient, createClient, NeuroLinkApiError,
|
|
50
|
+
NeuroLinkClient, createClient, NeuroLinkApiError, } from "./client/httpClient.js";
|
|
51
|
+
export {
|
|
48
52
|
// AI SDK Adapter
|
|
49
|
-
NeuroLinkLanguageModel, NeuroLinkAIProvider, createNeuroLinkProvider, createNeuroLinkModel, createStreamingResponse, neurolink as neuroLinkAIInstance,
|
|
53
|
+
NeuroLinkLanguageModel, NeuroLinkProvider as NeuroLinkAIProvider, createNeuroLinkProvider, createNeuroLinkModel, createStreamingResponse, neurolink as neuroLinkAIInstance, } from "./client/aiSdkAdapter.js";
|
|
54
|
+
export {
|
|
50
55
|
// Interceptors
|
|
51
|
-
createApiKeyAuthInterceptor, createBearerAuthInterceptor, createDynamicAuthInterceptor, createLoggingInterceptor, createRetryInterceptor, createRateLimitInterceptor, createRequestTransformInterceptor, createResponseTransformInterceptor, createCacheInterceptor, createTimeoutInterceptor, createErrorHandlerInterceptor, composeMiddleware, conditionalMiddleware,
|
|
56
|
+
createApiKeyAuthInterceptor, createBearerAuthInterceptor, createDynamicAuthInterceptor, createLoggingInterceptor, createRetryInterceptor, createRateLimitInterceptor, createRequestTransformInterceptor, createResponseTransformInterceptor, createCacheInterceptor, createTimeoutInterceptor, createErrorHandlerInterceptor, composeMiddleware, conditionalMiddleware, } from "./client/interceptors.js";
|
|
57
|
+
export {
|
|
52
58
|
// Streaming Client
|
|
53
|
-
SSEClient, WebSocketStreamingClient, createStreamingClient, createAsyncStream, collectStream,
|
|
59
|
+
SSEClient, WebSocketStreamingClient, createStreamingClient, createAsyncStream, collectStream, } from "./client/streamingClient.js";
|
|
60
|
+
export {
|
|
54
61
|
// Authentication
|
|
55
|
-
OAuth2TokenManager, JWTTokenManager, createApiKeyMiddleware, createBearerTokenMiddleware, createTokenManagerMiddleware, createAuthWithRetryMiddleware, createMultiAuthMiddleware, OAuth2Error, OAuth2AuthError, TokenRefreshError, decodeJWTPayload, isJWTExpired, getJWTExpiry, getApiKeyFromEnv,
|
|
62
|
+
OAuth2TokenManager, JWTTokenManager, createApiKeyMiddleware, createBearerTokenMiddleware, createTokenManagerMiddleware, createAuthWithRetryMiddleware, createMultiAuthMiddleware, OAuth2Error, OAuth2AuthenticationError as OAuth2AuthError, TokenRefreshError, decodeJWTPayload, isJWTExpired, getJWTExpiry, getApiKeyFromEnv, } from "./client/auth.js";
|
|
63
|
+
export {
|
|
56
64
|
// Errors
|
|
57
|
-
ErrorCode as ClientErrorCode, NeuroLinkError as ClientNeuroLinkError, HttpError, ClientRateLimitError, ClientValidationError, ClientAuthenticationError, ClientAuthorizationError, NotFoundError, ClientNetworkError, ClientTimeoutError, ClientConnectionError, AbortError, ClientConfigurationError, StreamError, ClientProviderError, ContextLengthError, ContentFilterError, createErrorFromResponse, createErrorFromNative, mapStatusToErrorCode, isRetryableStatus, isRetryableError, isNeuroLinkError, isApiError, } from "./client/
|
|
65
|
+
ErrorCode as ClientErrorCode, NeuroLinkError as ClientNeuroLinkError, HttpError, ClientRateLimitError, ClientValidationError, ClientAuthenticationError, ClientAuthorizationError, NotFoundError, ClientNetworkError, ClientTimeoutError, ClientConnectionError, AbortError, ClientConfigurationError, StreamError, ClientProviderError, ContextLengthError, ContentFilterError, createErrorFromResponse, createErrorFromNative, mapStatusToErrorCode, isRetryableStatus, isRetryableError, isNeuroLinkError, isApiError, } from "./client/errors.js";
|
|
58
66
|
export { AIProviderName, BedrockModels, OpenAIModels, VertexModels, } from "./constants/enums.js";
|
|
59
67
|
// Dynamic Models exports
|
|
60
68
|
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
@@ -584,6 +584,7 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
584
584
|
let lastStepText = "";
|
|
585
585
|
let totalInputTokens = 0;
|
|
586
586
|
let totalOutputTokens = 0;
|
|
587
|
+
let totalCacheReadTokens = 0;
|
|
587
588
|
let step = 0;
|
|
588
589
|
let completedWithFinalAnswer = false;
|
|
589
590
|
const failedTools = new Map();
|
|
@@ -614,6 +615,7 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
614
615
|
const chunkResult = await collectStreamChunksIncremental(rawStream, channel);
|
|
615
616
|
totalInputTokens += chunkResult.inputTokens;
|
|
616
617
|
totalOutputTokens += chunkResult.outputTokens;
|
|
618
|
+
totalCacheReadTokens += chunkResult.cacheReadTokens ?? 0;
|
|
617
619
|
const stepText = extractTextFromParts(chunkResult.rawResponseParts);
|
|
618
620
|
// If no function calls, this was the final step — channel
|
|
619
621
|
// already received all text parts incrementally.
|
|
@@ -698,13 +700,23 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
698
700
|
span.setAttribute(ATTR.GEN_AI_INPUT_TOKENS, totalInputTokens);
|
|
699
701
|
span.setAttribute(ATTR.GEN_AI_OUTPUT_TOKENS, totalOutputTokens);
|
|
700
702
|
span.setAttribute(ATTR.GEN_AI_FINISH_REASON, hitStepLimitWithoutFinalAnswer ? "max_steps" : "stop");
|
|
703
|
+
// Gemini promptTokenCount is OVERLAPPING: it already includes
|
|
704
|
+
// cachedContentTokenCount. Subtract once here so calculateCost
|
|
705
|
+
// bills the cached portion at the cheaper cacheRead rate without
|
|
706
|
+
// double-counting. Total billable tokens are conserved.
|
|
707
|
+
const adjustedInputTokens = Math.max(0, totalInputTokens - totalCacheReadTokens);
|
|
701
708
|
analyticsResolve({
|
|
702
709
|
provider: this.providerName,
|
|
703
710
|
model: modelName,
|
|
704
711
|
tokenUsage: {
|
|
705
|
-
input:
|
|
712
|
+
input: adjustedInputTokens,
|
|
706
713
|
output: totalOutputTokens,
|
|
707
|
-
total:
|
|
714
|
+
total: adjustedInputTokens +
|
|
715
|
+
totalCacheReadTokens +
|
|
716
|
+
totalOutputTokens,
|
|
717
|
+
...(totalCacheReadTokens > 0
|
|
718
|
+
? { cacheReadTokens: totalCacheReadTokens }
|
|
719
|
+
: {}),
|
|
708
720
|
},
|
|
709
721
|
requestDuration: responseTime,
|
|
710
722
|
timestamp: new Date().toISOString(),
|
|
@@ -831,6 +843,7 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
831
843
|
let lastStepText = "";
|
|
832
844
|
let totalInputTokens = 0;
|
|
833
845
|
let totalOutputTokens = 0;
|
|
846
|
+
let totalCacheReadTokens = 0;
|
|
834
847
|
const allToolCalls = [];
|
|
835
848
|
const toolExecutions = [];
|
|
836
849
|
let step = 0;
|
|
@@ -856,6 +869,7 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
856
869
|
const chunkResult = await collectStreamChunks(stream);
|
|
857
870
|
totalInputTokens += chunkResult.inputTokens;
|
|
858
871
|
totalOutputTokens += chunkResult.outputTokens;
|
|
872
|
+
totalCacheReadTokens += chunkResult.cacheReadTokens ?? 0;
|
|
859
873
|
const stepText = extractTextFromParts(chunkResult.rawResponseParts);
|
|
860
874
|
// If no function calls, we're done
|
|
861
875
|
if (chunkResult.stepFunctionCalls.length === 0) {
|
|
@@ -927,14 +941,21 @@ export class GoogleAIStudioProvider extends BaseProvider {
|
|
|
927
941
|
// analytics / evaluation / tracing stay attached. The native AI
|
|
928
942
|
// Studio generate path bypasses BaseProvider.generate(), so
|
|
929
943
|
// skipping enhanceResult would silently drop those features.
|
|
944
|
+
// Gemini promptTokenCount is OVERLAPPING (already includes
|
|
945
|
+
// cachedContentTokenCount). Subtract once so the cached portion is
|
|
946
|
+
// billed at the cheaper cacheRead rate without double-counting.
|
|
947
|
+
const adjustedInputTokens = Math.max(0, totalInputTokens - totalCacheReadTokens);
|
|
930
948
|
const baseResult = {
|
|
931
949
|
content: finalText,
|
|
932
950
|
provider: this.providerName,
|
|
933
951
|
model: modelName,
|
|
934
952
|
usage: {
|
|
935
|
-
input:
|
|
953
|
+
input: adjustedInputTokens,
|
|
936
954
|
output: totalOutputTokens,
|
|
937
|
-
total:
|
|
955
|
+
total: adjustedInputTokens + totalCacheReadTokens + totalOutputTokens,
|
|
956
|
+
...(totalCacheReadTokens > 0
|
|
957
|
+
? { cacheReadTokens: totalCacheReadTokens }
|
|
958
|
+
: {}),
|
|
938
959
|
},
|
|
939
960
|
responseTime,
|
|
940
961
|
toolsUsed: allToolCalls.map((tc) => tc.toolName),
|
|
@@ -514,6 +514,7 @@ export async function collectStreamChunks(stream) {
|
|
|
514
514
|
const stepFunctionCalls = [];
|
|
515
515
|
let inputTokens = 0;
|
|
516
516
|
let outputTokens = 0;
|
|
517
|
+
let cacheReadTokens = 0;
|
|
517
518
|
for await (const chunk of stream) {
|
|
518
519
|
// Extract raw parts from candidates FIRST
|
|
519
520
|
// This avoids using chunk.text which triggers SDK warning when
|
|
@@ -533,9 +534,18 @@ export async function collectStreamChunks(stream) {
|
|
|
533
534
|
if (usage) {
|
|
534
535
|
inputTokens = Math.max(inputTokens, usage.promptTokenCount || 0);
|
|
535
536
|
outputTokens = Math.max(outputTokens, usage.candidatesTokenCount || 0);
|
|
537
|
+
// cachedContentTokenCount is OVERLAPPING (a subset already inside
|
|
538
|
+
// promptTokenCount). Surface it so the call site subtracts once.
|
|
539
|
+
cacheReadTokens = Math.max(cacheReadTokens, usage.cachedContentTokenCount || 0);
|
|
536
540
|
}
|
|
537
541
|
}
|
|
538
|
-
return {
|
|
542
|
+
return {
|
|
543
|
+
rawResponseParts,
|
|
544
|
+
stepFunctionCalls,
|
|
545
|
+
inputTokens,
|
|
546
|
+
outputTokens,
|
|
547
|
+
cacheReadTokens,
|
|
548
|
+
};
|
|
539
549
|
}
|
|
540
550
|
/**
|
|
541
551
|
* Create a push-based text channel that bridges a background producer
|
|
@@ -627,6 +637,7 @@ export async function collectStreamChunksIncremental(stream, channel) {
|
|
|
627
637
|
const stepFunctionCalls = [];
|
|
628
638
|
let inputTokens = 0;
|
|
629
639
|
let outputTokens = 0;
|
|
640
|
+
let cacheReadTokens = 0;
|
|
630
641
|
for await (const chunk of stream) {
|
|
631
642
|
const chunkRecord = chunk;
|
|
632
643
|
const candidates = chunkRecord.candidates;
|
|
@@ -648,9 +659,18 @@ export async function collectStreamChunksIncremental(stream, channel) {
|
|
|
648
659
|
if (usage) {
|
|
649
660
|
inputTokens = Math.max(inputTokens, usage.promptTokenCount || 0);
|
|
650
661
|
outputTokens = Math.max(outputTokens, usage.candidatesTokenCount || 0);
|
|
662
|
+
// cachedContentTokenCount is OVERLAPPING (a subset already inside
|
|
663
|
+
// promptTokenCount). Surface it so the call site subtracts once.
|
|
664
|
+
cacheReadTokens = Math.max(cacheReadTokens, usage.cachedContentTokenCount || 0);
|
|
651
665
|
}
|
|
652
666
|
}
|
|
653
|
-
return {
|
|
667
|
+
return {
|
|
668
|
+
rawResponseParts,
|
|
669
|
+
stepFunctionCalls,
|
|
670
|
+
inputTokens,
|
|
671
|
+
outputTokens,
|
|
672
|
+
cacheReadTokens,
|
|
673
|
+
};
|
|
654
674
|
}
|
|
655
675
|
/**
|
|
656
676
|
* Extract the thoughtSignature token from raw response parts.
|