@juspay/neurolink 9.63.0 → 9.64.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 +12 -0
- package/dist/adapters/video/vertexVideoHandler.js +9 -2
- package/dist/browser/neurolink.min.js +1015 -1019
- package/dist/cli/factories/commandFactory.d.ts +14 -0
- package/dist/cli/factories/commandFactory.js +50 -25
- package/dist/cli/loop/optionsSchema.d.ts +1 -1
- package/dist/cli/loop/optionsSchema.js +12 -0
- package/dist/core/baseProvider.d.ts +1 -1
- package/dist/core/modules/MessageBuilder.js +20 -0
- package/dist/core/redisConversationMemoryManager.js +0 -3
- package/dist/factories/providerRegistry.js +5 -1
- package/dist/lib/adapters/video/vertexVideoHandler.js +9 -2
- package/dist/lib/core/baseProvider.d.ts +1 -1
- package/dist/lib/core/modules/MessageBuilder.js +20 -0
- package/dist/lib/core/redisConversationMemoryManager.js +0 -3
- package/dist/lib/factories/providerRegistry.js +5 -1
- package/dist/lib/memory/hippocampusInitializer.d.ts +2 -2
- package/dist/lib/memory/hippocampusInitializer.js +32 -2
- package/dist/lib/middleware/builtin/lifecycle.js +19 -48
- package/dist/lib/neurolink.js +49 -2
- package/dist/lib/providers/googleAiStudio.d.ts +11 -3
- package/dist/lib/providers/googleAiStudio.js +292 -339
- package/dist/lib/providers/googleNativeGemini3.d.ts +83 -1
- package/dist/lib/providers/googleNativeGemini3.js +208 -4
- package/dist/lib/providers/googleVertex.d.ts +116 -129
- package/dist/lib/providers/googleVertex.js +2826 -1968
- package/dist/lib/providers/openRouter.js +7 -3
- package/dist/lib/types/aliases.d.ts +14 -0
- package/dist/lib/types/common.d.ts +0 -3
- package/dist/lib/types/conversation.d.ts +10 -3
- package/dist/lib/types/generate.d.ts +14 -0
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/index.js +1 -0
- package/dist/lib/types/memory.d.ts +96 -0
- package/dist/lib/types/memory.js +23 -0
- package/dist/lib/types/providers.d.ts +140 -2
- package/dist/lib/types/stream.d.ts +6 -0
- package/dist/lib/utils/lifecycleCallbacks.d.ts +13 -0
- package/dist/lib/utils/lifecycleCallbacks.js +44 -0
- package/dist/lib/utils/messageBuilder.d.ts +10 -0
- package/dist/lib/utils/messageBuilder.js +40 -5
- package/dist/lib/utils/modelDetection.d.ts +11 -0
- package/dist/lib/utils/modelDetection.js +27 -0
- package/dist/lib/utils/providerHealth.js +7 -7
- package/dist/lib/utils/schemaConversion.d.ts +1 -1
- package/dist/lib/utils/schemaConversion.js +59 -4
- package/dist/lib/utils/tokenLimits.js +23 -32
- package/dist/memory/hippocampusInitializer.d.ts +2 -2
- package/dist/memory/hippocampusInitializer.js +32 -2
- package/dist/middleware/builtin/lifecycle.js +19 -48
- package/dist/neurolink.js +49 -2
- package/dist/providers/googleAiStudio.d.ts +11 -3
- package/dist/providers/googleAiStudio.js +291 -339
- package/dist/providers/googleNativeGemini3.d.ts +83 -1
- package/dist/providers/googleNativeGemini3.js +208 -4
- package/dist/providers/googleVertex.d.ts +116 -129
- package/dist/providers/googleVertex.js +2824 -1967
- package/dist/providers/openRouter.js +7 -3
- package/dist/types/aliases.d.ts +14 -0
- package/dist/types/common.d.ts +0 -3
- package/dist/types/conversation.d.ts +10 -3
- package/dist/types/generate.d.ts +14 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/memory.d.ts +96 -0
- package/dist/types/memory.js +22 -0
- package/dist/types/providers.d.ts +140 -2
- package/dist/types/stream.d.ts +6 -0
- package/dist/utils/lifecycleCallbacks.d.ts +13 -0
- package/dist/utils/lifecycleCallbacks.js +43 -0
- package/dist/utils/messageBuilder.d.ts +10 -0
- package/dist/utils/messageBuilder.js +40 -5
- package/dist/utils/modelDetection.d.ts +11 -0
- package/dist/utils/modelDetection.js +27 -0
- package/dist/utils/providerHealth.js +7 -7
- package/dist/utils/schemaConversion.d.ts +1 -1
- package/dist/utils/schemaConversion.js +59 -4
- package/dist/utils/tokenLimits.js +23 -32
- package/package.json +11 -4
|
@@ -3,6 +3,20 @@ import type { CommandModule } from "yargs";
|
|
|
3
3
|
* CLI Command Factory for generate commands
|
|
4
4
|
*/
|
|
5
5
|
export declare class CLICommandFactory {
|
|
6
|
+
/**
|
|
7
|
+
* Normalize loop session variables before merging them into provider options.
|
|
8
|
+
*
|
|
9
|
+
* The CLI loop schema models some fields (e.g. `stopSequences`,
|
|
10
|
+
* `enabledToolNames`) as a single comma-separated string for ergonomic
|
|
11
|
+
* input, but providers expect `string[]`. Without conversion,
|
|
12
|
+
* `set stopSequences a,b` would be sent as one stop token "a,b" instead
|
|
13
|
+
* of two ("a", "b"); `set enabledToolNames read,write` would be cast to
|
|
14
|
+
* a `string[]` containing the single literal "read,write" and silently
|
|
15
|
+
* filter out every tool. This helper splits and trims those fields so
|
|
16
|
+
* the spread into `enhancedOptions` produces the correct shape across
|
|
17
|
+
* generate / batch / stream paths.
|
|
18
|
+
*/
|
|
19
|
+
private static normalizeLoopSessionVariables;
|
|
6
20
|
private static readonly commonOptions;
|
|
7
21
|
private static buildOptions;
|
|
8
22
|
private static processCliImages;
|
|
@@ -28,6 +28,35 @@ import { SageMakerCommandFactory } from "./sagemakerCommandFactory.js";
|
|
|
28
28
|
* CLI Command Factory for generate commands
|
|
29
29
|
*/
|
|
30
30
|
export class CLICommandFactory {
|
|
31
|
+
/**
|
|
32
|
+
* Normalize loop session variables before merging them into provider options.
|
|
33
|
+
*
|
|
34
|
+
* The CLI loop schema models some fields (e.g. `stopSequences`,
|
|
35
|
+
* `enabledToolNames`) as a single comma-separated string for ergonomic
|
|
36
|
+
* input, but providers expect `string[]`. Without conversion,
|
|
37
|
+
* `set stopSequences a,b` would be sent as one stop token "a,b" instead
|
|
38
|
+
* of two ("a", "b"); `set enabledToolNames read,write` would be cast to
|
|
39
|
+
* a `string[]` containing the single literal "read,write" and silently
|
|
40
|
+
* filter out every tool. This helper splits and trims those fields so
|
|
41
|
+
* the spread into `enhancedOptions` produces the correct shape across
|
|
42
|
+
* generate / batch / stream paths.
|
|
43
|
+
*/
|
|
44
|
+
static normalizeLoopSessionVariables(vars) {
|
|
45
|
+
const normalized = { ...vars };
|
|
46
|
+
if (typeof normalized.stopSequences === "string") {
|
|
47
|
+
normalized.stopSequences = normalized.stopSequences
|
|
48
|
+
.split(",")
|
|
49
|
+
.map((s) => s.trim())
|
|
50
|
+
.filter(Boolean);
|
|
51
|
+
}
|
|
52
|
+
if (typeof normalized.enabledToolNames === "string") {
|
|
53
|
+
normalized.enabledToolNames = normalized.enabledToolNames
|
|
54
|
+
.split(",")
|
|
55
|
+
.map((s) => s.trim())
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
}
|
|
58
|
+
return normalized;
|
|
59
|
+
}
|
|
31
60
|
// Common options available on all commands
|
|
32
61
|
static commonOptions = {
|
|
33
62
|
// Core generation options
|
|
@@ -621,6 +650,13 @@ export class CLICommandFactory {
|
|
|
621
650
|
model: argv.model,
|
|
622
651
|
temperature: argv.temperature,
|
|
623
652
|
maxTokens: argv.maxTokens,
|
|
653
|
+
// Sampling controls — surfaced here so all three command paths
|
|
654
|
+
// (generate / stream / batch) get them consistently typed instead
|
|
655
|
+
// of relying on an ad-hoc cast at each sdk call site.
|
|
656
|
+
topP: argv.topP,
|
|
657
|
+
topK: argv.topK,
|
|
658
|
+
stopSequences: argv.stopSequences,
|
|
659
|
+
enabledToolNames: argv.enabledToolNames,
|
|
624
660
|
systemPrompt: argv.system,
|
|
625
661
|
timeout: argv.timeout,
|
|
626
662
|
disableTools: argv.disableTools,
|
|
@@ -1930,18 +1966,8 @@ export class CLICommandFactory {
|
|
|
1930
1966
|
}
|
|
1931
1967
|
// Initialize SDK and session
|
|
1932
1968
|
const sdk = globalSession.getOrCreateNeuroLink();
|
|
1933
|
-
const sessionVariables = globalSession.getSessionVariables();
|
|
1934
|
-
const enhancedOptions = {
|
|
1935
|
-
...options,
|
|
1936
|
-
...sessionVariables,
|
|
1937
|
-
// enabledToolNames must be string[] for the SDK — normalize from CSV string
|
|
1938
|
-
...(typeof sessionVariables.enabledToolNames === "string" && {
|
|
1939
|
-
enabledToolNames: sessionVariables.enabledToolNames
|
|
1940
|
-
.split(",")
|
|
1941
|
-
.map((t) => t.trim())
|
|
1942
|
-
.filter(Boolean),
|
|
1943
|
-
}),
|
|
1944
|
-
};
|
|
1969
|
+
const sessionVariables = CLICommandFactory.normalizeLoopSessionVariables(globalSession.getSessionVariables());
|
|
1970
|
+
const enhancedOptions = { ...options, ...sessionVariables };
|
|
1945
1971
|
const sessionId = globalSession.getCurrentSessionId();
|
|
1946
1972
|
const context = sessionId
|
|
1947
1973
|
? { ...options.context, sessionId }
|
|
@@ -1993,6 +2019,9 @@ export class CLICommandFactory {
|
|
|
1993
2019
|
model: enhancedOptions.model,
|
|
1994
2020
|
temperature: enhancedOptions.temperature,
|
|
1995
2021
|
maxTokens: enhancedOptions.maxTokens,
|
|
2022
|
+
topP: enhancedOptions.topP,
|
|
2023
|
+
topK: enhancedOptions.topK,
|
|
2024
|
+
stopSequences: enhancedOptions.stopSequences,
|
|
1996
2025
|
systemPrompt: enhancedOptions.systemPrompt,
|
|
1997
2026
|
timeout: enhancedOptions.timeout
|
|
1998
2027
|
? enhancedOptions.timeout * 1000
|
|
@@ -2166,7 +2195,7 @@ export class CLICommandFactory {
|
|
|
2166
2195
|
*/
|
|
2167
2196
|
static async executeRealStream(argv, options, inputText, contextMetadata) {
|
|
2168
2197
|
const sdk = globalSession.getOrCreateNeuroLink();
|
|
2169
|
-
const sessionVariables = globalSession.getSessionVariables();
|
|
2198
|
+
const sessionVariables = CLICommandFactory.normalizeLoopSessionVariables(globalSession.getSessionVariables());
|
|
2170
2199
|
const enhancedOptions = { ...options, ...sessionVariables };
|
|
2171
2200
|
const sessionId = globalSession.getCurrentSessionId();
|
|
2172
2201
|
const context = sessionId
|
|
@@ -2201,6 +2230,9 @@ export class CLICommandFactory {
|
|
|
2201
2230
|
model: enhancedOptions.model,
|
|
2202
2231
|
temperature: enhancedOptions.temperature,
|
|
2203
2232
|
maxTokens: enhancedOptions.maxTokens,
|
|
2233
|
+
topP: enhancedOptions.topP,
|
|
2234
|
+
topK: enhancedOptions.topK,
|
|
2235
|
+
stopSequences: enhancedOptions.stopSequences,
|
|
2204
2236
|
systemPrompt: enhancedOptions.systemPrompt,
|
|
2205
2237
|
timeout: enhancedOptions.timeout
|
|
2206
2238
|
? enhancedOptions.timeout * 1000
|
|
@@ -2639,18 +2671,8 @@ export class CLICommandFactory {
|
|
|
2639
2671
|
}
|
|
2640
2672
|
const results = [];
|
|
2641
2673
|
const sdk = globalSession.getOrCreateNeuroLink();
|
|
2642
|
-
const sessionVariables = globalSession.getSessionVariables();
|
|
2643
|
-
const enhancedOptions = {
|
|
2644
|
-
...options,
|
|
2645
|
-
...sessionVariables,
|
|
2646
|
-
// enabledToolNames must be string[] for the SDK — normalize from CSV string
|
|
2647
|
-
...(typeof sessionVariables.enabledToolNames === "string" && {
|
|
2648
|
-
enabledToolNames: sessionVariables.enabledToolNames
|
|
2649
|
-
.split(",")
|
|
2650
|
-
.map((t) => t.trim())
|
|
2651
|
-
.filter(Boolean),
|
|
2652
|
-
}),
|
|
2653
|
-
};
|
|
2674
|
+
const sessionVariables = CLICommandFactory.normalizeLoopSessionVariables(globalSession.getSessionVariables());
|
|
2675
|
+
const enhancedOptions = { ...options, ...sessionVariables };
|
|
2654
2676
|
const sessionId = globalSession.getCurrentSessionId();
|
|
2655
2677
|
for (let i = 0; i < prompts.length; i++) {
|
|
2656
2678
|
if (spinner) {
|
|
@@ -2692,6 +2714,9 @@ export class CLICommandFactory {
|
|
|
2692
2714
|
model: enhancedOptions.model,
|
|
2693
2715
|
temperature: enhancedOptions.temperature,
|
|
2694
2716
|
maxTokens: enhancedOptions.maxTokens,
|
|
2717
|
+
topP: enhancedOptions.topP,
|
|
2718
|
+
topK: enhancedOptions.topK,
|
|
2719
|
+
stopSequences: enhancedOptions.stopSequences,
|
|
2695
2720
|
systemPrompt: enhancedOptions.systemPrompt,
|
|
2696
2721
|
timeout: enhancedOptions.timeout
|
|
2697
2722
|
? enhancedOptions.timeout * 1000
|
|
@@ -4,4 +4,4 @@ import type { OptionSchema, TextGenerationOptions } from "../../lib/types/index.
|
|
|
4
4
|
* This object provides metadata for validation and help text in the CLI loop.
|
|
5
5
|
* It is derived from the main TextGenerationOptions interface to ensure consistency.
|
|
6
6
|
*/
|
|
7
|
-
export declare const textGenerationOptionsSchema: Record<keyof Omit<TextGenerationOptions, "prompt" | "input" | "schema" | "tools" | "context" | "conversationHistory" | "conversationMessages" | "conversationMemoryConfig" | "originalPrompt" | "middleware" | "expectedOutcome" | "evaluationCriteria" | "region" | "csvOptions" | "tts" | "stt" | "thinkingConfig" | "requestId" | "fileRegistry" | "abortSignal" | "toolFilter" | "excludeTools" | "toolChoice" | "prepareStep" | "credentials">, OptionSchema>;
|
|
7
|
+
export declare const textGenerationOptionsSchema: Record<keyof Omit<TextGenerationOptions, "prompt" | "input" | "schema" | "tools" | "context" | "conversationHistory" | "conversationMessages" | "conversationMemoryConfig" | "originalPrompt" | "middleware" | "expectedOutcome" | "evaluationCriteria" | "region" | "csvOptions" | "tts" | "stt" | "thinkingConfig" | "requestId" | "fileRegistry" | "abortSignal" | "toolFilter" | "excludeTools" | "toolChoice" | "prepareStep" | "credentials" | "onFinish" | "onError">, OptionSchema>;
|
|
@@ -24,6 +24,18 @@ export const textGenerationOptionsSchema = {
|
|
|
24
24
|
type: "number",
|
|
25
25
|
description: "The maximum number of tokens to generate.",
|
|
26
26
|
},
|
|
27
|
+
topP: {
|
|
28
|
+
type: "number",
|
|
29
|
+
description: "Top-p (nucleus) sampling parameter. Controls diversity of generated tokens (0.0-1.0).",
|
|
30
|
+
},
|
|
31
|
+
topK: {
|
|
32
|
+
type: "number",
|
|
33
|
+
description: "Top-k sampling parameter. Limits the number of tokens considered (Google/Gemini models only).",
|
|
34
|
+
},
|
|
35
|
+
stopSequences: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "Stop sequences that will halt generation when encountered (comma-separated).",
|
|
38
|
+
},
|
|
27
39
|
output: {
|
|
28
40
|
type: "string",
|
|
29
41
|
description: "AI response format - specify just the format value (e.g., 'json', 'structured'). Note: This is automatically transformed to { format: value } for the API.",
|
|
@@ -352,7 +352,7 @@ export declare abstract class BaseProvider implements AIProvider {
|
|
|
352
352
|
* // result.video contains the generated video
|
|
353
353
|
* ```
|
|
354
354
|
*/
|
|
355
|
-
|
|
355
|
+
protected handleVideoGeneration(options: TextGenerationOptions, startTime: number): Promise<EnhancedGenerateResult>;
|
|
356
356
|
/**
|
|
357
357
|
* Create analytics - delegated to TelemetryHandler
|
|
358
358
|
*/
|
|
@@ -106,6 +106,16 @@ export class MessageBuilder {
|
|
|
106
106
|
fileRegistry: options.fileRegistry,
|
|
107
107
|
};
|
|
108
108
|
messages = await buildMultimodalMessagesArray(multimodalOptions, this.providerName, this.modelName);
|
|
109
|
+
// Propagate any systemPrompt augmentation (e.g. inline-file
|
|
110
|
+
// handling guidance from processUnifiedFilesArray) back to the
|
|
111
|
+
// caller's options. Providers like GoogleVertex's native
|
|
112
|
+
// @google/genai stream path read `options.systemPrompt` directly
|
|
113
|
+
// — without this propagation the augmentation lives only on the
|
|
114
|
+
// local `multimodalOptions` clone and never reaches the model.
|
|
115
|
+
if (multimodalOptions.systemPrompt &&
|
|
116
|
+
multimodalOptions.systemPrompt !== options.systemPrompt) {
|
|
117
|
+
options.systemPrompt = multimodalOptions.systemPrompt;
|
|
118
|
+
}
|
|
109
119
|
}
|
|
110
120
|
else {
|
|
111
121
|
if (process.env.NEUROLINK_DEBUG === "true") {
|
|
@@ -214,6 +224,16 @@ export class MessageBuilder {
|
|
|
214
224
|
fileRegistry: options.fileRegistry,
|
|
215
225
|
};
|
|
216
226
|
messages = await buildMultimodalMessagesArray(multimodalOptions, this.providerName, this.modelName);
|
|
227
|
+
// Propagate any systemPrompt augmentation (e.g. inline-file
|
|
228
|
+
// handling guidance from processUnifiedFilesArray) back to the
|
|
229
|
+
// caller's options. Providers like GoogleVertex's native
|
|
230
|
+
// @google/genai stream path read `options.systemPrompt` directly
|
|
231
|
+
// — without this propagation the augmentation lives only on the
|
|
232
|
+
// local `multimodalOptions` clone and never reaches the model.
|
|
233
|
+
if (multimodalOptions.systemPrompt &&
|
|
234
|
+
multimodalOptions.systemPrompt !== options.systemPrompt) {
|
|
235
|
+
options.systemPrompt = multimodalOptions.systemPrompt;
|
|
236
|
+
}
|
|
217
237
|
}
|
|
218
238
|
else {
|
|
219
239
|
if (process.env.NEUROLINK_DEBUG === "true") {
|
|
@@ -958,9 +958,6 @@ User message: "${userMessage}"`;
|
|
|
958
958
|
title = title.replace(/^(Title:|Here's a title:|The title is:)\s*/i, "");
|
|
959
959
|
title = title.replace(/['"]/g, ""); // Remove quotes
|
|
960
960
|
title = title.replace(/\.$/, ""); // Remove trailing period
|
|
961
|
-
if (title.length > 60) {
|
|
962
|
-
title = title.substring(0, 57) + "...";
|
|
963
|
-
}
|
|
964
961
|
if (title.length < 3) {
|
|
965
962
|
title = "New Conversation";
|
|
966
963
|
}
|
|
@@ -135,7 +135,11 @@ export class ProviderRegistry {
|
|
|
135
135
|
const openrouterCreds = credentials;
|
|
136
136
|
const { OpenRouterProvider } = await import("../providers/openRouter.js");
|
|
137
137
|
return new OpenRouterProvider(modelName, sdk, undefined, openrouterCreds);
|
|
138
|
-
},
|
|
138
|
+
},
|
|
139
|
+
// Default updated from claude-3-5-sonnet (sunset by OpenRouter)
|
|
140
|
+
// to claude-sonnet-4.5. Must match getDefaultOpenRouterModel()
|
|
141
|
+
// in src/lib/providers/openRouter.ts.
|
|
142
|
+
process.env.OPENROUTER_MODEL || "anthropic/claude-sonnet-4.5", ["openrouter", "or"]);
|
|
139
143
|
// Register Amazon SageMaker provider
|
|
140
144
|
ProviderFactory.registerProvider(AIProviderName.SAGEMAKER, async (modelName, _providerName, _sdk, region, credentials) => {
|
|
141
145
|
const sagemakerCreds = credentials;
|
|
@@ -89,8 +89,15 @@ export function isVertexVideoConfigured() {
|
|
|
89
89
|
* @throws VideoError if project cannot be determined
|
|
90
90
|
*/
|
|
91
91
|
async function getVertexConfig() {
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
// Veo 3.1 is only published in us-central1 (and the synthetic
|
|
93
|
+
// `global` endpoint). When the operator's environment defaults to
|
|
94
|
+
// a region where Veo 3.1 isn't available (e.g. us-east5 set for
|
|
95
|
+
// Gemini chat traffic), the regional endpoint returns a 404
|
|
96
|
+
// "Publisher Model … was not found". Allow `GOOGLE_VEO_LOCATION` as
|
|
97
|
+
// a Veo-specific override and fall through to us-central1 instead
|
|
98
|
+
// of inheriting the default Vertex region.
|
|
99
|
+
const location = process.env.GOOGLE_VEO_LOCATION ||
|
|
100
|
+
process.env.GOOGLE_VERTEX_VIDEO_LOCATION ||
|
|
94
101
|
DEFAULT_LOCATION;
|
|
95
102
|
// Try environment variables first
|
|
96
103
|
let project = process.env.GOOGLE_VERTEX_PROJECT ||
|
|
@@ -352,7 +352,7 @@ export declare abstract class BaseProvider implements AIProvider {
|
|
|
352
352
|
* // result.video contains the generated video
|
|
353
353
|
* ```
|
|
354
354
|
*/
|
|
355
|
-
|
|
355
|
+
protected handleVideoGeneration(options: TextGenerationOptions, startTime: number): Promise<EnhancedGenerateResult>;
|
|
356
356
|
/**
|
|
357
357
|
* Create analytics - delegated to TelemetryHandler
|
|
358
358
|
*/
|
|
@@ -106,6 +106,16 @@ export class MessageBuilder {
|
|
|
106
106
|
fileRegistry: options.fileRegistry,
|
|
107
107
|
};
|
|
108
108
|
messages = await buildMultimodalMessagesArray(multimodalOptions, this.providerName, this.modelName);
|
|
109
|
+
// Propagate any systemPrompt augmentation (e.g. inline-file
|
|
110
|
+
// handling guidance from processUnifiedFilesArray) back to the
|
|
111
|
+
// caller's options. Providers like GoogleVertex's native
|
|
112
|
+
// @google/genai stream path read `options.systemPrompt` directly
|
|
113
|
+
// — without this propagation the augmentation lives only on the
|
|
114
|
+
// local `multimodalOptions` clone and never reaches the model.
|
|
115
|
+
if (multimodalOptions.systemPrompt &&
|
|
116
|
+
multimodalOptions.systemPrompt !== options.systemPrompt) {
|
|
117
|
+
options.systemPrompt = multimodalOptions.systemPrompt;
|
|
118
|
+
}
|
|
109
119
|
}
|
|
110
120
|
else {
|
|
111
121
|
if (process.env.NEUROLINK_DEBUG === "true") {
|
|
@@ -214,6 +224,16 @@ export class MessageBuilder {
|
|
|
214
224
|
fileRegistry: options.fileRegistry,
|
|
215
225
|
};
|
|
216
226
|
messages = await buildMultimodalMessagesArray(multimodalOptions, this.providerName, this.modelName);
|
|
227
|
+
// Propagate any systemPrompt augmentation (e.g. inline-file
|
|
228
|
+
// handling guidance from processUnifiedFilesArray) back to the
|
|
229
|
+
// caller's options. Providers like GoogleVertex's native
|
|
230
|
+
// @google/genai stream path read `options.systemPrompt` directly
|
|
231
|
+
// — without this propagation the augmentation lives only on the
|
|
232
|
+
// local `multimodalOptions` clone and never reaches the model.
|
|
233
|
+
if (multimodalOptions.systemPrompt &&
|
|
234
|
+
multimodalOptions.systemPrompt !== options.systemPrompt) {
|
|
235
|
+
options.systemPrompt = multimodalOptions.systemPrompt;
|
|
236
|
+
}
|
|
217
237
|
}
|
|
218
238
|
else {
|
|
219
239
|
if (process.env.NEUROLINK_DEBUG === "true") {
|
|
@@ -958,9 +958,6 @@ User message: "${userMessage}"`;
|
|
|
958
958
|
title = title.replace(/^(Title:|Here's a title:|The title is:)\s*/i, "");
|
|
959
959
|
title = title.replace(/['"]/g, ""); // Remove quotes
|
|
960
960
|
title = title.replace(/\.$/, ""); // Remove trailing period
|
|
961
|
-
if (title.length > 60) {
|
|
962
|
-
title = title.substring(0, 57) + "...";
|
|
963
|
-
}
|
|
964
961
|
if (title.length < 3) {
|
|
965
962
|
title = "New Conversation";
|
|
966
963
|
}
|
|
@@ -135,7 +135,11 @@ export class ProviderRegistry {
|
|
|
135
135
|
const openrouterCreds = credentials;
|
|
136
136
|
const { OpenRouterProvider } = await import("../providers/openRouter.js");
|
|
137
137
|
return new OpenRouterProvider(modelName, sdk, undefined, openrouterCreds);
|
|
138
|
-
},
|
|
138
|
+
},
|
|
139
|
+
// Default updated from claude-3-5-sonnet (sunset by OpenRouter)
|
|
140
|
+
// to claude-sonnet-4.5. Must match getDefaultOpenRouterModel()
|
|
141
|
+
// in src/lib/providers/openRouter.ts.
|
|
142
|
+
process.env.OPENROUTER_MODEL || "anthropic/claude-sonnet-4.5", ["openrouter", "or"]);
|
|
139
143
|
// Register Amazon SageMaker provider
|
|
140
144
|
ProviderFactory.registerProvider(AIProviderName.SAGEMAKER, async (modelName, _providerName, _sdk, region, credentials) => {
|
|
141
145
|
const sagemakerCreds = credentials;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function initializeHippocampus(config: HippocampusConfig):
|
|
1
|
+
import type { HippocampusConfig, HippocampusLike } from "../types/index.js";
|
|
2
|
+
export declare function initializeHippocampus(config: HippocampusConfig): HippocampusLike | null;
|
|
@@ -1,8 +1,38 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
2
|
import { logger } from "../utils/logger.js";
|
|
3
|
+
// Lazy require so importing NeuroLink core does not fail when the optional
|
|
4
|
+
// peer @juspay/hippocampus is not installed. The package was previously a
|
|
5
|
+
// hard runtime dependency, but Hippocampus declares a peer on
|
|
6
|
+
// @juspay/neurolink which made pnpm pull a registry NeuroLink that
|
|
7
|
+
// transitively required @ai-sdk/google + @ai-sdk/google-vertex into the
|
|
8
|
+
// production graph. Making memory optional breaks that cycle while keeping
|
|
9
|
+
// the same runtime behavior whenever the package is installed.
|
|
10
|
+
const lazyRequire = createRequire(import.meta.url);
|
|
11
|
+
let cachedModule;
|
|
12
|
+
function loadHippocampusModule() {
|
|
13
|
+
if (cachedModule !== undefined) {
|
|
14
|
+
return cachedModule;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
cachedModule = lazyRequire("@juspay/hippocampus");
|
|
18
|
+
return cachedModule;
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
cachedModule = null;
|
|
22
|
+
logger.debug("[memoryInitializer] @juspay/hippocampus is not installed; memory features disabled.", {
|
|
23
|
+
error: error instanceof Error ? error.message : String(error),
|
|
24
|
+
});
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
3
28
|
export function initializeHippocampus(config) {
|
|
29
|
+
const mod = loadHippocampusModule();
|
|
30
|
+
if (!mod) {
|
|
31
|
+
logger.warn("[memoryInitializer] Memory configuration provided but @juspay/hippocampus is not installed. Run `pnpm add @juspay/hippocampus` (or your package manager equivalent) to enable memory.");
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
4
34
|
try {
|
|
5
|
-
const instance = new Hippocampus(config);
|
|
35
|
+
const instance = new mod.Hippocampus(config);
|
|
6
36
|
logger.info("[memoryInitializer] Memory initialized successfully", {
|
|
7
37
|
storageType: config.storage?.type || "sqlite",
|
|
8
38
|
maxWords: config.maxWords || 50,
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { logger } from "../../utils/logger.js";
|
|
11
11
|
import { isRecoverableError } from "../../utils/errorHandling.js";
|
|
12
|
+
import { fireOnErrorOnce } from "../../utils/lifecycleCallbacks.js";
|
|
12
13
|
export function createLifecycleMiddleware(config = {}) {
|
|
13
14
|
const metadata = {
|
|
14
15
|
id: "lifecycle",
|
|
@@ -50,22 +51,12 @@ export function createLifecycleMiddleware(config = {}) {
|
|
|
50
51
|
return result;
|
|
51
52
|
}
|
|
52
53
|
catch (error) {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
recoverable: isRecoverableError(err),
|
|
60
|
-
});
|
|
61
|
-
Promise.resolve(callbackResult).catch((e) => {
|
|
62
|
-
logger.warn("[LifecycleMiddleware] onError callback error:", e);
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
catch (e) {
|
|
66
|
-
logger.warn("[LifecycleMiddleware] onError callback error:", e);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
54
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
55
|
+
fireOnErrorOnce(config.onError, error, {
|
|
56
|
+
error: err,
|
|
57
|
+
duration: Date.now() - startTime,
|
|
58
|
+
recoverable: isRecoverableError(err),
|
|
59
|
+
});
|
|
69
60
|
throw error;
|
|
70
61
|
}
|
|
71
62
|
},
|
|
@@ -102,22 +93,12 @@ export function createLifecycleMiddleware(config = {}) {
|
|
|
102
93
|
controller.enqueue(chunk);
|
|
103
94
|
}
|
|
104
95
|
catch (error) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
recoverable: isRecoverableError(err),
|
|
112
|
-
});
|
|
113
|
-
Promise.resolve(callbackResult).catch((e) => {
|
|
114
|
-
logger.warn("[LifecycleMiddleware] onError callback error:", e);
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
catch (e) {
|
|
118
|
-
logger.warn("[LifecycleMiddleware] onError callback error:", e);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
96
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
97
|
+
fireOnErrorOnce(config.onError, error, {
|
|
98
|
+
error: err,
|
|
99
|
+
duration: Date.now() - startTime,
|
|
100
|
+
recoverable: isRecoverableError(err),
|
|
101
|
+
});
|
|
121
102
|
throw error;
|
|
122
103
|
}
|
|
123
104
|
},
|
|
@@ -144,22 +125,12 @@ export function createLifecycleMiddleware(config = {}) {
|
|
|
144
125
|
};
|
|
145
126
|
}
|
|
146
127
|
catch (error) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
recoverable: isRecoverableError(err),
|
|
154
|
-
});
|
|
155
|
-
Promise.resolve(callbackResult).catch((e) => {
|
|
156
|
-
logger.warn("[LifecycleMiddleware] onError callback error:", e);
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
catch (e) {
|
|
160
|
-
logger.warn("[LifecycleMiddleware] onError callback error:", e);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
128
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
129
|
+
fireOnErrorOnce(config.onError, error, {
|
|
130
|
+
error: err,
|
|
131
|
+
duration: Date.now() - startTime,
|
|
132
|
+
recoverable: isRecoverableError(err),
|
|
133
|
+
});
|
|
163
134
|
throw error;
|
|
164
135
|
}
|
|
165
136
|
},
|
package/dist/lib/neurolink.js
CHANGED
|
@@ -64,6 +64,7 @@ import { getConversationMessages, storeConversationTurn, } from "./utils/convers
|
|
|
64
64
|
import { CircuitBreaker, ERROR_CODES, ErrorFactory, isAbortError, isRetriableError, logStructuredError, NeuroLinkError, withRetry, withTimeout, } from "./utils/errorHandling.js";
|
|
65
65
|
// Factory processing imports
|
|
66
66
|
import { createCleanStreamOptions, enhanceTextGenerationOptions, processFactoryOptions, processStreamingFactoryOptions, validateFactoryConfig, } from "./utils/factoryProcessing.js";
|
|
67
|
+
import { fireOnErrorOnce } from "./utils/lifecycleCallbacks.js";
|
|
67
68
|
import { logger, mcpLogger } from "./utils/logger.js";
|
|
68
69
|
import { extractMcpErrorText } from "./utils/mcpErrorText.js";
|
|
69
70
|
import { createCustomToolServerInfo, detectCategory, } from "./utils/mcpDefaults.js";
|
|
@@ -2753,7 +2754,29 @@ Current user's request: ${currentInput}`;
|
|
|
2753
2754
|
* @since 1.0.0
|
|
2754
2755
|
*/
|
|
2755
2756
|
async generate(optionsOrPrompt) {
|
|
2756
|
-
|
|
2757
|
+
const startTime = Date.now();
|
|
2758
|
+
try {
|
|
2759
|
+
return await this.runWithFallbackOrchestration(optionsOrPrompt, "generate", (opts) => tracers.sdk.startActiveSpan("neurolink.generate", { kind: SpanKind.INTERNAL }, (generateSpan) => this.executeGenerateWithMetricsContext(opts, generateSpan)));
|
|
2760
|
+
}
|
|
2761
|
+
catch (error) {
|
|
2762
|
+
// Fire `onError` lifecycle callback for ANY thrown error — including
|
|
2763
|
+
// ones raised before the provider is even instantiated (invalid
|
|
2764
|
+
// provider name, missing credentials, etc.). The downstream
|
|
2765
|
+
// LifecycleMiddleware only fires `onError` once it has wrapped the
|
|
2766
|
+
// AI SDK doGenerate, which is too late for early-resolution failures.
|
|
2767
|
+
// `fireOnErrorOnce` dedupes against the middleware path so the
|
|
2768
|
+
// consumer callback fires at most once per logical failure.
|
|
2769
|
+
const onError = typeof optionsOrPrompt === "object" && optionsOrPrompt !== null
|
|
2770
|
+
? optionsOrPrompt.onError
|
|
2771
|
+
: undefined;
|
|
2772
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
2773
|
+
fireOnErrorOnce(onError, error, {
|
|
2774
|
+
error: err,
|
|
2775
|
+
duration: Date.now() - startTime,
|
|
2776
|
+
recoverable: false,
|
|
2777
|
+
});
|
|
2778
|
+
throw error;
|
|
2779
|
+
}
|
|
2757
2780
|
}
|
|
2758
2781
|
/**
|
|
2759
2782
|
* Curator P2-3: wraps a generate/stream call with the fallback
|
|
@@ -3167,6 +3190,12 @@ Current user's request: ${currentInput}`;
|
|
|
3167
3190
|
middleware: options.middleware,
|
|
3168
3191
|
conversationMessages: options.conversationMessages,
|
|
3169
3192
|
credentials: options.credentials,
|
|
3193
|
+
// Lifecycle callbacks must reach the provider so non-AI-SDK paths
|
|
3194
|
+
// (Vertex's native @google/genai, native Bedrock, Ollama, etc.) can
|
|
3195
|
+
// invoke them directly. Pipeline A also still receives them via the
|
|
3196
|
+
// wrapped middleware config set by applyGenerateLifecycleMiddleware.
|
|
3197
|
+
onFinish: options.onFinish,
|
|
3198
|
+
onError: options.onError,
|
|
3170
3199
|
};
|
|
3171
3200
|
const extraContext = options;
|
|
3172
3201
|
if (extraContext.sessionId || extraContext.userId) {
|
|
@@ -5032,7 +5061,25 @@ Current user's request: ${currentInput}`;
|
|
|
5032
5061
|
: [],
|
|
5033
5062
|
optionKeys: Object.keys(options),
|
|
5034
5063
|
});
|
|
5035
|
-
|
|
5064
|
+
const startTime = Date.now();
|
|
5065
|
+
try {
|
|
5066
|
+
return await this.streamWithIterationFallback(options);
|
|
5067
|
+
}
|
|
5068
|
+
catch (error) {
|
|
5069
|
+
// Fire `onError` for early-resolution failures (invalid provider,
|
|
5070
|
+
// missing credentials, etc.) that surface before the per-chunk
|
|
5071
|
+
// wrapper installed by GoogleVertex / LifecycleMiddleware can run.
|
|
5072
|
+
// `fireOnErrorOnce` dedupes against the middleware path so the
|
|
5073
|
+
// consumer callback fires at most once per logical failure.
|
|
5074
|
+
const onError = options.onError;
|
|
5075
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
5076
|
+
fireOnErrorOnce(onError, error, {
|
|
5077
|
+
error: err,
|
|
5078
|
+
duration: Date.now() - startTime,
|
|
5079
|
+
recoverable: false,
|
|
5080
|
+
});
|
|
5081
|
+
throw error;
|
|
5082
|
+
}
|
|
5036
5083
|
}
|
|
5037
5084
|
/**
|
|
5038
5085
|
* Curator P2-3 / Reviewer Finding #2: stream-fallback that also covers
|
|
@@ -41,7 +41,8 @@ export declare class GoogleAIStudioProvider extends BaseProvider {
|
|
|
41
41
|
getProviderName(): AIProviderName;
|
|
42
42
|
getDefaultModel(): string;
|
|
43
43
|
/**
|
|
44
|
-
*
|
|
44
|
+
* AI SDK model instance — no longer used.
|
|
45
|
+
* All models are routed through native @google/genai SDK directly.
|
|
45
46
|
*/
|
|
46
47
|
getAISDKModel(): LanguageModel;
|
|
47
48
|
protected formatProviderError(error: unknown): Error;
|
|
@@ -62,8 +63,8 @@ export declare class GoogleAIStudioProvider extends BaseProvider {
|
|
|
62
63
|
private estimateTokenCount;
|
|
63
64
|
protected executeStream(options: StreamOptions, analysisSchema?: ZodUnknownSchema | Schema<unknown>): Promise<StreamResult>;
|
|
64
65
|
/**
|
|
65
|
-
* Execute stream using native @google/genai SDK
|
|
66
|
-
*
|
|
66
|
+
* Execute stream using native @google/genai SDK
|
|
67
|
+
* Uses @google/genai directly for all Gemini models (2.0, 2.5, 3.x)
|
|
67
68
|
*/
|
|
68
69
|
private executeNativeGemini3Stream;
|
|
69
70
|
/**
|
|
@@ -75,6 +76,13 @@ export declare class GoogleAIStudioProvider extends BaseProvider {
|
|
|
75
76
|
* Override generate to route Gemini 3 models with tools to native SDK
|
|
76
77
|
*/
|
|
77
78
|
generate(optionsOrPrompt: TextGenerationOptions | string): Promise<EnhancedGenerateResult | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Emit `generation:end` so the Pipeline B observability listener creates
|
|
81
|
+
* a `model.generation` span for native Google AI Studio generate calls.
|
|
82
|
+
* Without this hand-off the native path silently disappears from
|
|
83
|
+
* Pipeline B exporters (Langfuse, custom OTEL collectors).
|
|
84
|
+
*/
|
|
85
|
+
private emitPipelineBGenerationEvent;
|
|
78
86
|
private executeAudioStreamViaGeminiLive;
|
|
79
87
|
protected getDefaultEmbeddingModel(): string;
|
|
80
88
|
/**
|