@juspay/neurolink 7.29.3 → 7.30.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/config/conversationMemoryConfig.js +5 -0
- package/dist/core/conversationMemoryManager.d.ts +9 -15
- package/dist/core/conversationMemoryManager.js +103 -56
- package/dist/core/types.d.ts +3 -1
- package/dist/factories/providerRegistry.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/lib/config/conversationMemoryConfig.js +5 -0
- package/dist/lib/core/conversationMemoryManager.d.ts +9 -15
- package/dist/lib/core/conversationMemoryManager.js +103 -56
- package/dist/lib/core/types.d.ts +3 -1
- package/dist/lib/factories/providerRegistry.js +1 -1
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.js +2 -0
- package/dist/lib/neurolink.d.ts +0 -9
- package/dist/lib/neurolink.js +7 -39
- package/dist/lib/providers/amazonBedrock.d.ts +28 -59
- package/dist/lib/providers/amazonBedrock.js +913 -330
- package/dist/lib/types/conversationTypes.d.ts +10 -0
- package/dist/lib/types/generateTypes.d.ts +1 -2
- package/dist/lib/utils/conversationMemoryUtils.d.ts +1 -2
- package/dist/lib/utils/conversationMemoryUtils.js +5 -6
- package/dist/lib/utils/logger.d.ts +164 -4
- package/dist/lib/utils/logger.js +163 -10
- package/dist/lib/utils/providerUtils.js +9 -6
- package/dist/neurolink.d.ts +0 -9
- package/dist/neurolink.js +7 -39
- package/dist/providers/amazonBedrock.d.ts +28 -59
- package/dist/providers/amazonBedrock.js +913 -330
- package/dist/types/conversationTypes.d.ts +10 -0
- package/dist/types/generateTypes.d.ts +1 -2
- package/dist/utils/conversationMemoryUtils.d.ts +1 -2
- package/dist/utils/conversationMemoryUtils.js +5 -6
- package/dist/utils/logger.d.ts +164 -4
- package/dist/utils/logger.js +163 -10
- package/dist/utils/providerUtils.js +9 -6
- package/package.json +2 -3
- package/dist/context/ContextManager.d.ts +0 -28
- package/dist/context/ContextManager.js +0 -113
- package/dist/context/config.d.ts +0 -5
- package/dist/context/config.js +0 -42
- package/dist/context/types.d.ts +0 -20
- package/dist/context/types.js +0 -1
- package/dist/context/utils.d.ts +0 -7
- package/dist/context/utils.js +0 -8
- package/dist/lib/context/ContextManager.d.ts +0 -28
- package/dist/lib/context/ContextManager.js +0 -113
- package/dist/lib/context/config.d.ts +0 -5
- package/dist/lib/context/config.js +0 -42
- package/dist/lib/context/types.d.ts +0 -20
- package/dist/lib/context/types.js +0 -1
- package/dist/lib/context/utils.d.ts +0 -7
- package/dist/lib/context/utils.js +0 -8
- package/dist/lib/providers/aws/credentialProvider.d.ts +0 -58
- package/dist/lib/providers/aws/credentialProvider.js +0 -267
- package/dist/lib/providers/aws/credentialTester.d.ts +0 -49
- package/dist/lib/providers/aws/credentialTester.js +0 -394
- package/dist/providers/aws/credentialProvider.d.ts +0 -58
- package/dist/providers/aws/credentialProvider.js +0 -267
- package/dist/providers/aws/credentialTester.d.ts +0 -49
- package/dist/providers/aws/credentialTester.js +0 -394
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [7.30.1](https://github.com/juspay/neurolink/compare/v7.30.0...v7.30.1) (2025-08-31)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- **(bedrock):** migrate from ai-sdk to native AWS SDK implementation ([e5d8a4c](https://github.com/juspay/neurolink/commit/e5d8a4c85144ed558167f5083abd89d125576ab0))
|
|
6
|
+
|
|
7
|
+
## [7.30.0](https://github.com/juspay/neurolink/compare/v7.29.3...v7.30.0) (2025-08-29)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
- **(SDK):** Integrate context summarization with conversation memory BZ-43344 ([a2316ff](https://github.com/juspay/neurolink/commit/a2316ff6df55107316892d33365455e6ebdcbbd9))
|
|
12
|
+
|
|
1
13
|
## [7.29.3](https://github.com/juspay/neurolink/compare/v7.29.2...v7.29.3) (2025-08-29)
|
|
2
14
|
|
|
3
15
|
### Bug Fixes
|
|
@@ -36,5 +36,10 @@ export function getConversationMemoryDefaults() {
|
|
|
36
36
|
maxSessions: Number(process.env.NEUROLINK_MEMORY_MAX_SESSIONS) || DEFAULT_MAX_SESSIONS,
|
|
37
37
|
maxTurnsPerSession: Number(process.env.NEUROLINK_MEMORY_MAX_TURNS_PER_SESSION) ||
|
|
38
38
|
DEFAULT_MAX_TURNS_PER_SESSION,
|
|
39
|
+
enableSummarization: process.env.NEUROLINK_SUMMARIZATION_ENABLED === "true",
|
|
40
|
+
summarizationThresholdTurns: Number(process.env.NEUROLINK_SUMMARIZATION_THRESHOLD_TURNS) || 20,
|
|
41
|
+
summarizationTargetTurns: Number(process.env.NEUROLINK_SUMMARIZATION_TARGET_TURNS) || 10,
|
|
42
|
+
summarizationProvider: process.env.NEUROLINK_SUMMARIZATION_PROVIDER || "vertex",
|
|
43
|
+
summarizationModel: process.env.NEUROLINK_SUMMARIZATION_MODEL || "gemini-2.5-flash",
|
|
39
44
|
};
|
|
40
45
|
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Conversation Memory Manager for NeuroLink
|
|
3
3
|
* Handles in-memory conversation storage, session management, and context injection
|
|
4
4
|
*/
|
|
5
|
-
import type { ConversationMemoryConfig, ConversationMemoryStats, ChatMessage } from "../types/conversationTypes.js";
|
|
5
|
+
import type { ConversationMemoryConfig, SessionMemory, ConversationMemoryStats, ChatMessage } from "../types/conversationTypes.js";
|
|
6
6
|
export declare class ConversationMemoryManager {
|
|
7
7
|
private sessions;
|
|
8
|
-
|
|
8
|
+
config: ConversationMemoryConfig;
|
|
9
9
|
private isInitialized;
|
|
10
10
|
constructor(config: ConversationMemoryConfig);
|
|
11
11
|
/**
|
|
@@ -22,20 +22,14 @@ export declare class ConversationMemoryManager {
|
|
|
22
22
|
* Returns pre-stored message array with zero conversion overhead
|
|
23
23
|
*/
|
|
24
24
|
buildContextMessages(sessionId: string): ChatMessage[];
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
getStats(): Promise<ConversationMemoryStats>;
|
|
30
|
-
/**
|
|
31
|
-
* Clear all conversations for a specific session
|
|
32
|
-
*/
|
|
33
|
-
clearSession(sessionId: string): Promise<boolean>;
|
|
34
|
-
/**
|
|
35
|
-
* Clear all conversations (reset memory)
|
|
36
|
-
*/
|
|
37
|
-
clearAllSessions(): Promise<void>;
|
|
25
|
+
getSession(sessionId: string): SessionMemory | undefined;
|
|
26
|
+
createSummarySystemMessage(content: string): ChatMessage;
|
|
27
|
+
private _summarizeSession;
|
|
28
|
+
private _createSummarizationPrompt;
|
|
38
29
|
private ensureInitialized;
|
|
39
30
|
private createNewSession;
|
|
40
31
|
private enforceSessionLimit;
|
|
32
|
+
getStats(): Promise<ConversationMemoryStats>;
|
|
33
|
+
clearSession(sessionId: string): Promise<boolean>;
|
|
34
|
+
clearAllSessions(): Promise<void>;
|
|
41
35
|
}
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
import { ConversationMemoryError } from "../types/conversationTypes.js";
|
|
6
6
|
import { DEFAULT_MAX_TURNS_PER_SESSION, DEFAULT_MAX_SESSIONS, MESSAGES_PER_TURN, } from "../config/conversationMemoryConfig.js";
|
|
7
7
|
import { logger } from "../utils/logger.js";
|
|
8
|
+
import { NeuroLink } from "../neurolink.js";
|
|
8
9
|
export class ConversationMemoryManager {
|
|
9
10
|
sessions = new Map();
|
|
10
11
|
config;
|
|
11
12
|
isInitialized = false;
|
|
12
13
|
constructor(config) {
|
|
13
|
-
// Trust that config is already complete from applyConversationMemoryDefaults()
|
|
14
14
|
this.config = config;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
@@ -48,21 +48,21 @@ export class ConversationMemoryManager {
|
|
|
48
48
|
// ULTRA-OPTIMIZED: Direct message storage - no intermediate objects
|
|
49
49
|
session.messages.push({ role: "user", content: userMessage }, { role: "assistant", content: aiResponse });
|
|
50
50
|
session.lastActivity = Date.now();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
MESSAGES_PER_TURN;
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
if (this.config.enableSummarization) {
|
|
52
|
+
const userAssistantCount = session.messages.filter((msg) => msg.role === "user" || msg.role === "assistant").length;
|
|
53
|
+
const currentTurnCount = Math.floor(userAssistantCount / MESSAGES_PER_TURN);
|
|
54
|
+
if (currentTurnCount >= (this.config.summarizationThresholdTurns || 20)) {
|
|
55
|
+
await this._summarizeSession(session);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
const maxMessages = (this.config.maxTurnsPerSession || DEFAULT_MAX_TURNS_PER_SESSION) *
|
|
60
|
+
MESSAGES_PER_TURN;
|
|
61
|
+
if (session.messages.length > maxMessages) {
|
|
62
|
+
session.messages = session.messages.slice(-maxMessages);
|
|
63
|
+
}
|
|
56
64
|
}
|
|
57
|
-
// Enforce global session limit
|
|
58
65
|
this.enforceSessionLimit();
|
|
59
|
-
logger.debug("Conversation turn stored", {
|
|
60
|
-
sessionId,
|
|
61
|
-
messageCount: session.messages.length,
|
|
62
|
-
turnCount: session.messages.length / MESSAGES_PER_TURN, // Each turn = MESSAGES_PER_TURN messages
|
|
63
|
-
userMessageLength: userMessage.length,
|
|
64
|
-
aiResponseLength: aiResponse.length,
|
|
65
|
-
});
|
|
66
66
|
}
|
|
67
67
|
catch (error) {
|
|
68
68
|
throw new ConversationMemoryError(`Failed to store conversation turn for session ${sessionId}`, "STORAGE_ERROR", {
|
|
@@ -77,48 +77,78 @@ export class ConversationMemoryManager {
|
|
|
77
77
|
*/
|
|
78
78
|
buildContextMessages(sessionId) {
|
|
79
79
|
const session = this.sessions.get(sessionId);
|
|
80
|
-
|
|
81
|
-
return [];
|
|
82
|
-
}
|
|
83
|
-
// ULTRA-OPTIMIZED: Direct return - no processing needed!
|
|
84
|
-
return session.messages;
|
|
80
|
+
return session ? session.messages : [];
|
|
85
81
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
async getStats() {
|
|
91
|
-
await this.ensureInitialized();
|
|
92
|
-
const sessions = Array.from(this.sessions.values());
|
|
93
|
-
const totalTurns = sessions.reduce((sum, session) => sum + session.messages.length / MESSAGES_PER_TURN, 0);
|
|
82
|
+
getSession(sessionId) {
|
|
83
|
+
return this.sessions.get(sessionId);
|
|
84
|
+
}
|
|
85
|
+
createSummarySystemMessage(content) {
|
|
94
86
|
return {
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
role: "system",
|
|
88
|
+
content: `Summary of previous conversation turns:\n\n${content}`,
|
|
97
89
|
};
|
|
98
90
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
91
|
+
async _summarizeSession(session) {
|
|
92
|
+
logger.info(`[ConversationMemory] Summarizing session ${session.sessionId}...`);
|
|
93
|
+
const targetTurns = this.config.summarizationTargetTurns || 10;
|
|
94
|
+
const splitIndex = Math.max(0, session.messages.length - targetTurns * MESSAGES_PER_TURN);
|
|
95
|
+
const messagesToSummarize = session.messages.slice(0, splitIndex);
|
|
96
|
+
const recentMessages = session.messages.slice(splitIndex);
|
|
97
|
+
if (messagesToSummarize.length === 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const summarizationPrompt = this._createSummarizationPrompt(messagesToSummarize);
|
|
101
|
+
const summarizer = new NeuroLink({
|
|
102
|
+
conversationMemory: { enabled: false },
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
const providerName = this.config.summarizationProvider;
|
|
106
|
+
// Map provider names to correct format
|
|
107
|
+
let mappedProvider = providerName;
|
|
108
|
+
if (providerName === "vertex") {
|
|
109
|
+
mappedProvider = "googlevertex";
|
|
110
|
+
}
|
|
111
|
+
if (!mappedProvider) {
|
|
112
|
+
logger.error(`[ConversationMemory] Missing summarization provider`);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
logger.debug(`[ConversationMemory] Using provider: ${mappedProvider} for summarization`);
|
|
116
|
+
const summaryResult = await summarizer.generate({
|
|
117
|
+
input: { text: summarizationPrompt },
|
|
118
|
+
provider: mappedProvider,
|
|
119
|
+
model: this.config.summarizationModel,
|
|
120
|
+
disableTools: true,
|
|
121
|
+
});
|
|
122
|
+
if (summaryResult.content) {
|
|
123
|
+
session.messages = [
|
|
124
|
+
this.createSummarySystemMessage(summaryResult.content),
|
|
125
|
+
...recentMessages,
|
|
126
|
+
];
|
|
127
|
+
logger.info(`[ConversationMemory] Summarization complete for session ${session.sessionId}.`);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
logger.warn(`[ConversationMemory] Summarization failed for session ${session.sessionId}. History not modified.`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
logger.error(`[ConversationMemory] Error during summarization for session ${session.sessionId}`, { error });
|
|
106
135
|
}
|
|
107
|
-
// Remove from memory
|
|
108
|
-
this.sessions.delete(sessionId);
|
|
109
|
-
logger.info("Session cleared", { sessionId });
|
|
110
|
-
return true;
|
|
111
136
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
137
|
+
_createSummarizationPrompt(history) {
|
|
138
|
+
const formattedHistory = history
|
|
139
|
+
.map((msg) => `${msg.role}: ${msg.content}`)
|
|
140
|
+
.join("\n\n");
|
|
141
|
+
return `
|
|
142
|
+
You are a context summarization AI. Your task is to condense the following conversation history for another AI assistant.
|
|
143
|
+
The summary must be a concise, third-person narrative that retains all critical information, including key entities, technical details, decisions made, and any specific dates or times mentioned.
|
|
144
|
+
Ensure the summary flows logically and is ready to be used as context for the next turn in the conversation.
|
|
145
|
+
|
|
146
|
+
Conversation History to Summarize:
|
|
147
|
+
---
|
|
148
|
+
${formattedHistory}
|
|
149
|
+
---
|
|
150
|
+
`.trim();
|
|
120
151
|
}
|
|
121
|
-
// Private methods
|
|
122
152
|
async ensureInitialized() {
|
|
123
153
|
if (!this.isInitialized) {
|
|
124
154
|
await this.initialize();
|
|
@@ -138,16 +168,33 @@ export class ConversationMemoryManager {
|
|
|
138
168
|
if (this.sessions.size <= maxSessions) {
|
|
139
169
|
return;
|
|
140
170
|
}
|
|
141
|
-
// Sort sessions by last activity (oldest first)
|
|
142
171
|
const sessions = Array.from(this.sessions.entries()).sort(([, a], [, b]) => a.lastActivity - b.lastActivity);
|
|
143
|
-
|
|
144
|
-
const sessionsToRemove = sessions.slice(0, sessions.length - maxSessions);
|
|
172
|
+
const sessionsToRemove = sessions.slice(0, this.sessions.size - maxSessions);
|
|
145
173
|
for (const [sessionId] of sessionsToRemove) {
|
|
146
174
|
this.sessions.delete(sessionId);
|
|
147
175
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
176
|
+
}
|
|
177
|
+
async getStats() {
|
|
178
|
+
await this.ensureInitialized();
|
|
179
|
+
const sessions = Array.from(this.sessions.values());
|
|
180
|
+
const totalTurns = sessions.reduce((sum, session) => sum + session.messages.length / MESSAGES_PER_TURN, 0);
|
|
181
|
+
return {
|
|
182
|
+
totalSessions: sessions.length,
|
|
183
|
+
totalTurns,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
async clearSession(sessionId) {
|
|
187
|
+
const session = this.sessions.get(sessionId);
|
|
188
|
+
if (!session) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
this.sessions.delete(sessionId);
|
|
192
|
+
logger.info("Session cleared", { sessionId });
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
async clearAllSessions() {
|
|
196
|
+
const sessionIds = Array.from(this.sessions.keys());
|
|
197
|
+
this.sessions.clear();
|
|
198
|
+
logger.info("All sessions cleared", { clearedCount: sessionIds.length });
|
|
152
199
|
}
|
|
153
200
|
}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ZodUnknownSchema, ValidationSchema } from "../types/typeAliases.js
|
|
|
3
3
|
import type { GenerateResult } from "../types/generateTypes.js";
|
|
4
4
|
import type { StreamOptions, StreamResult } from "../types/streamTypes.js";
|
|
5
5
|
import type { JsonValue } from "../types/common.js";
|
|
6
|
-
import type { ChatMessage } from "../types/conversationTypes.js";
|
|
6
|
+
import type { ChatMessage, ConversationMemoryConfig } from "../types/conversationTypes.js";
|
|
7
7
|
import type { TokenUsage, AnalyticsData } from "../types/providers.js";
|
|
8
8
|
import type { EvaluationData } from "../index.js";
|
|
9
9
|
export type { EvaluationData };
|
|
@@ -155,6 +155,8 @@ export interface TextGenerationOptions {
|
|
|
155
155
|
content: string;
|
|
156
156
|
}>;
|
|
157
157
|
conversationMessages?: ChatMessage[];
|
|
158
|
+
conversationMemoryConfig?: Partial<ConversationMemoryConfig>;
|
|
159
|
+
originalPrompt?: string;
|
|
158
160
|
expectedOutcome?: string;
|
|
159
161
|
evaluationCriteria?: string[];
|
|
160
162
|
}
|
|
@@ -41,7 +41,7 @@ export class ProviderRegistry {
|
|
|
41
41
|
// Register Amazon Bedrock provider
|
|
42
42
|
ProviderFactory.registerProvider(AIProviderName.BEDROCK, async (modelName, _providerName, sdk) => {
|
|
43
43
|
const { AmazonBedrockProvider } = await import("../providers/amazonBedrock.js");
|
|
44
|
-
return new AmazonBedrockProvider(modelName,
|
|
44
|
+
return new AmazonBedrockProvider(modelName, sdk);
|
|
45
45
|
}, undefined, // Let provider read BEDROCK_MODEL from .env
|
|
46
46
|
["bedrock", "aws"]);
|
|
47
47
|
// Register Azure OpenAI provider
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export { validateTool } from "./sdk/toolRegistration.js";
|
|
|
15
15
|
export type { ToolResult, ToolDefinition } from "./types/tools.js";
|
|
16
16
|
export { BedrockModels, OpenAIModels, VertexModels, DEFAULT_PROVIDER_CONFIGS, } from "./core/types.js";
|
|
17
17
|
export { getBestProvider, getAvailableProviders, isValidProvider, } from "./utils/providerUtils.js";
|
|
18
|
+
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
19
|
+
export type { ModelConfig, ModelRegistry } from "./core/dynamicModels.js";
|
|
18
20
|
export { NeuroLink } from "./neurolink.js";
|
|
19
21
|
export type { ProviderStatus, MCPStatus } from "./neurolink.js";
|
|
20
22
|
export type { MCPServerInfo } from "./types/mcpTypes.js";
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,8 @@ export { validateTool } from "./sdk/toolRegistration.js";
|
|
|
14
14
|
export { BedrockModels, OpenAIModels, VertexModels, DEFAULT_PROVIDER_CONFIGS, } from "./core/types.js";
|
|
15
15
|
// Utility exports
|
|
16
16
|
export { getBestProvider, getAvailableProviders, isValidProvider, } from "./utils/providerUtils.js";
|
|
17
|
+
// Dynamic Models exports
|
|
18
|
+
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
17
19
|
// Main NeuroLink wrapper class and diagnostic types
|
|
18
20
|
export { NeuroLink } from "./neurolink.js";
|
|
19
21
|
export { MiddlewareFactory } from "./middleware/factory.js";
|
|
@@ -36,5 +36,10 @@ export function getConversationMemoryDefaults() {
|
|
|
36
36
|
maxSessions: Number(process.env.NEUROLINK_MEMORY_MAX_SESSIONS) || DEFAULT_MAX_SESSIONS,
|
|
37
37
|
maxTurnsPerSession: Number(process.env.NEUROLINK_MEMORY_MAX_TURNS_PER_SESSION) ||
|
|
38
38
|
DEFAULT_MAX_TURNS_PER_SESSION,
|
|
39
|
+
enableSummarization: process.env.NEUROLINK_SUMMARIZATION_ENABLED === "true",
|
|
40
|
+
summarizationThresholdTurns: Number(process.env.NEUROLINK_SUMMARIZATION_THRESHOLD_TURNS) || 20,
|
|
41
|
+
summarizationTargetTurns: Number(process.env.NEUROLINK_SUMMARIZATION_TARGET_TURNS) || 10,
|
|
42
|
+
summarizationProvider: process.env.NEUROLINK_SUMMARIZATION_PROVIDER || "vertex",
|
|
43
|
+
summarizationModel: process.env.NEUROLINK_SUMMARIZATION_MODEL || "gemini-2.5-flash",
|
|
39
44
|
};
|
|
40
45
|
}
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Conversation Memory Manager for NeuroLink
|
|
3
3
|
* Handles in-memory conversation storage, session management, and context injection
|
|
4
4
|
*/
|
|
5
|
-
import type { ConversationMemoryConfig, ConversationMemoryStats, ChatMessage } from "../types/conversationTypes.js";
|
|
5
|
+
import type { ConversationMemoryConfig, SessionMemory, ConversationMemoryStats, ChatMessage } from "../types/conversationTypes.js";
|
|
6
6
|
export declare class ConversationMemoryManager {
|
|
7
7
|
private sessions;
|
|
8
|
-
|
|
8
|
+
config: ConversationMemoryConfig;
|
|
9
9
|
private isInitialized;
|
|
10
10
|
constructor(config: ConversationMemoryConfig);
|
|
11
11
|
/**
|
|
@@ -22,20 +22,14 @@ export declare class ConversationMemoryManager {
|
|
|
22
22
|
* Returns pre-stored message array with zero conversion overhead
|
|
23
23
|
*/
|
|
24
24
|
buildContextMessages(sessionId: string): ChatMessage[];
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
getStats(): Promise<ConversationMemoryStats>;
|
|
30
|
-
/**
|
|
31
|
-
* Clear all conversations for a specific session
|
|
32
|
-
*/
|
|
33
|
-
clearSession(sessionId: string): Promise<boolean>;
|
|
34
|
-
/**
|
|
35
|
-
* Clear all conversations (reset memory)
|
|
36
|
-
*/
|
|
37
|
-
clearAllSessions(): Promise<void>;
|
|
25
|
+
getSession(sessionId: string): SessionMemory | undefined;
|
|
26
|
+
createSummarySystemMessage(content: string): ChatMessage;
|
|
27
|
+
private _summarizeSession;
|
|
28
|
+
private _createSummarizationPrompt;
|
|
38
29
|
private ensureInitialized;
|
|
39
30
|
private createNewSession;
|
|
40
31
|
private enforceSessionLimit;
|
|
32
|
+
getStats(): Promise<ConversationMemoryStats>;
|
|
33
|
+
clearSession(sessionId: string): Promise<boolean>;
|
|
34
|
+
clearAllSessions(): Promise<void>;
|
|
41
35
|
}
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
import { ConversationMemoryError } from "../types/conversationTypes.js";
|
|
6
6
|
import { DEFAULT_MAX_TURNS_PER_SESSION, DEFAULT_MAX_SESSIONS, MESSAGES_PER_TURN, } from "../config/conversationMemoryConfig.js";
|
|
7
7
|
import { logger } from "../utils/logger.js";
|
|
8
|
+
import { NeuroLink } from "../neurolink.js";
|
|
8
9
|
export class ConversationMemoryManager {
|
|
9
10
|
sessions = new Map();
|
|
10
11
|
config;
|
|
11
12
|
isInitialized = false;
|
|
12
13
|
constructor(config) {
|
|
13
|
-
// Trust that config is already complete from applyConversationMemoryDefaults()
|
|
14
14
|
this.config = config;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
@@ -48,21 +48,21 @@ export class ConversationMemoryManager {
|
|
|
48
48
|
// ULTRA-OPTIMIZED: Direct message storage - no intermediate objects
|
|
49
49
|
session.messages.push({ role: "user", content: userMessage }, { role: "assistant", content: aiResponse });
|
|
50
50
|
session.lastActivity = Date.now();
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
MESSAGES_PER_TURN;
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
if (this.config.enableSummarization) {
|
|
52
|
+
const userAssistantCount = session.messages.filter((msg) => msg.role === "user" || msg.role === "assistant").length;
|
|
53
|
+
const currentTurnCount = Math.floor(userAssistantCount / MESSAGES_PER_TURN);
|
|
54
|
+
if (currentTurnCount >= (this.config.summarizationThresholdTurns || 20)) {
|
|
55
|
+
await this._summarizeSession(session);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
const maxMessages = (this.config.maxTurnsPerSession || DEFAULT_MAX_TURNS_PER_SESSION) *
|
|
60
|
+
MESSAGES_PER_TURN;
|
|
61
|
+
if (session.messages.length > maxMessages) {
|
|
62
|
+
session.messages = session.messages.slice(-maxMessages);
|
|
63
|
+
}
|
|
56
64
|
}
|
|
57
|
-
// Enforce global session limit
|
|
58
65
|
this.enforceSessionLimit();
|
|
59
|
-
logger.debug("Conversation turn stored", {
|
|
60
|
-
sessionId,
|
|
61
|
-
messageCount: session.messages.length,
|
|
62
|
-
turnCount: session.messages.length / MESSAGES_PER_TURN, // Each turn = MESSAGES_PER_TURN messages
|
|
63
|
-
userMessageLength: userMessage.length,
|
|
64
|
-
aiResponseLength: aiResponse.length,
|
|
65
|
-
});
|
|
66
66
|
}
|
|
67
67
|
catch (error) {
|
|
68
68
|
throw new ConversationMemoryError(`Failed to store conversation turn for session ${sessionId}`, "STORAGE_ERROR", {
|
|
@@ -77,48 +77,78 @@ export class ConversationMemoryManager {
|
|
|
77
77
|
*/
|
|
78
78
|
buildContextMessages(sessionId) {
|
|
79
79
|
const session = this.sessions.get(sessionId);
|
|
80
|
-
|
|
81
|
-
return [];
|
|
82
|
-
}
|
|
83
|
-
// ULTRA-OPTIMIZED: Direct return - no processing needed!
|
|
84
|
-
return session.messages;
|
|
80
|
+
return session ? session.messages : [];
|
|
85
81
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
async getStats() {
|
|
91
|
-
await this.ensureInitialized();
|
|
92
|
-
const sessions = Array.from(this.sessions.values());
|
|
93
|
-
const totalTurns = sessions.reduce((sum, session) => sum + session.messages.length / MESSAGES_PER_TURN, 0);
|
|
82
|
+
getSession(sessionId) {
|
|
83
|
+
return this.sessions.get(sessionId);
|
|
84
|
+
}
|
|
85
|
+
createSummarySystemMessage(content) {
|
|
94
86
|
return {
|
|
95
|
-
|
|
96
|
-
|
|
87
|
+
role: "system",
|
|
88
|
+
content: `Summary of previous conversation turns:\n\n${content}`,
|
|
97
89
|
};
|
|
98
90
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
91
|
+
async _summarizeSession(session) {
|
|
92
|
+
logger.info(`[ConversationMemory] Summarizing session ${session.sessionId}...`);
|
|
93
|
+
const targetTurns = this.config.summarizationTargetTurns || 10;
|
|
94
|
+
const splitIndex = Math.max(0, session.messages.length - targetTurns * MESSAGES_PER_TURN);
|
|
95
|
+
const messagesToSummarize = session.messages.slice(0, splitIndex);
|
|
96
|
+
const recentMessages = session.messages.slice(splitIndex);
|
|
97
|
+
if (messagesToSummarize.length === 0) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
const summarizationPrompt = this._createSummarizationPrompt(messagesToSummarize);
|
|
101
|
+
const summarizer = new NeuroLink({
|
|
102
|
+
conversationMemory: { enabled: false },
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
const providerName = this.config.summarizationProvider;
|
|
106
|
+
// Map provider names to correct format
|
|
107
|
+
let mappedProvider = providerName;
|
|
108
|
+
if (providerName === "vertex") {
|
|
109
|
+
mappedProvider = "googlevertex";
|
|
110
|
+
}
|
|
111
|
+
if (!mappedProvider) {
|
|
112
|
+
logger.error(`[ConversationMemory] Missing summarization provider`);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
logger.debug(`[ConversationMemory] Using provider: ${mappedProvider} for summarization`);
|
|
116
|
+
const summaryResult = await summarizer.generate({
|
|
117
|
+
input: { text: summarizationPrompt },
|
|
118
|
+
provider: mappedProvider,
|
|
119
|
+
model: this.config.summarizationModel,
|
|
120
|
+
disableTools: true,
|
|
121
|
+
});
|
|
122
|
+
if (summaryResult.content) {
|
|
123
|
+
session.messages = [
|
|
124
|
+
this.createSummarySystemMessage(summaryResult.content),
|
|
125
|
+
...recentMessages,
|
|
126
|
+
];
|
|
127
|
+
logger.info(`[ConversationMemory] Summarization complete for session ${session.sessionId}.`);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
logger.warn(`[ConversationMemory] Summarization failed for session ${session.sessionId}. History not modified.`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
logger.error(`[ConversationMemory] Error during summarization for session ${session.sessionId}`, { error });
|
|
106
135
|
}
|
|
107
|
-
// Remove from memory
|
|
108
|
-
this.sessions.delete(sessionId);
|
|
109
|
-
logger.info("Session cleared", { sessionId });
|
|
110
|
-
return true;
|
|
111
136
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
137
|
+
_createSummarizationPrompt(history) {
|
|
138
|
+
const formattedHistory = history
|
|
139
|
+
.map((msg) => `${msg.role}: ${msg.content}`)
|
|
140
|
+
.join("\n\n");
|
|
141
|
+
return `
|
|
142
|
+
You are a context summarization AI. Your task is to condense the following conversation history for another AI assistant.
|
|
143
|
+
The summary must be a concise, third-person narrative that retains all critical information, including key entities, technical details, decisions made, and any specific dates or times mentioned.
|
|
144
|
+
Ensure the summary flows logically and is ready to be used as context for the next turn in the conversation.
|
|
145
|
+
|
|
146
|
+
Conversation History to Summarize:
|
|
147
|
+
---
|
|
148
|
+
${formattedHistory}
|
|
149
|
+
---
|
|
150
|
+
`.trim();
|
|
120
151
|
}
|
|
121
|
-
// Private methods
|
|
122
152
|
async ensureInitialized() {
|
|
123
153
|
if (!this.isInitialized) {
|
|
124
154
|
await this.initialize();
|
|
@@ -138,16 +168,33 @@ export class ConversationMemoryManager {
|
|
|
138
168
|
if (this.sessions.size <= maxSessions) {
|
|
139
169
|
return;
|
|
140
170
|
}
|
|
141
|
-
// Sort sessions by last activity (oldest first)
|
|
142
171
|
const sessions = Array.from(this.sessions.entries()).sort(([, a], [, b]) => a.lastActivity - b.lastActivity);
|
|
143
|
-
|
|
144
|
-
const sessionsToRemove = sessions.slice(0, sessions.length - maxSessions);
|
|
172
|
+
const sessionsToRemove = sessions.slice(0, this.sessions.size - maxSessions);
|
|
145
173
|
for (const [sessionId] of sessionsToRemove) {
|
|
146
174
|
this.sessions.delete(sessionId);
|
|
147
175
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
176
|
+
}
|
|
177
|
+
async getStats() {
|
|
178
|
+
await this.ensureInitialized();
|
|
179
|
+
const sessions = Array.from(this.sessions.values());
|
|
180
|
+
const totalTurns = sessions.reduce((sum, session) => sum + session.messages.length / MESSAGES_PER_TURN, 0);
|
|
181
|
+
return {
|
|
182
|
+
totalSessions: sessions.length,
|
|
183
|
+
totalTurns,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
async clearSession(sessionId) {
|
|
187
|
+
const session = this.sessions.get(sessionId);
|
|
188
|
+
if (!session) {
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
this.sessions.delete(sessionId);
|
|
192
|
+
logger.info("Session cleared", { sessionId });
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
async clearAllSessions() {
|
|
196
|
+
const sessionIds = Array.from(this.sessions.keys());
|
|
197
|
+
this.sessions.clear();
|
|
198
|
+
logger.info("All sessions cleared", { clearedCount: sessionIds.length });
|
|
152
199
|
}
|
|
153
200
|
}
|
package/dist/lib/core/types.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { ZodUnknownSchema, ValidationSchema } from "../types/typeAliases.js
|
|
|
3
3
|
import type { GenerateResult } from "../types/generateTypes.js";
|
|
4
4
|
import type { StreamOptions, StreamResult } from "../types/streamTypes.js";
|
|
5
5
|
import type { JsonValue } from "../types/common.js";
|
|
6
|
-
import type { ChatMessage } from "../types/conversationTypes.js";
|
|
6
|
+
import type { ChatMessage, ConversationMemoryConfig } from "../types/conversationTypes.js";
|
|
7
7
|
import type { TokenUsage, AnalyticsData } from "../types/providers.js";
|
|
8
8
|
import type { EvaluationData } from "../index.js";
|
|
9
9
|
export type { EvaluationData };
|
|
@@ -155,6 +155,8 @@ export interface TextGenerationOptions {
|
|
|
155
155
|
content: string;
|
|
156
156
|
}>;
|
|
157
157
|
conversationMessages?: ChatMessage[];
|
|
158
|
+
conversationMemoryConfig?: Partial<ConversationMemoryConfig>;
|
|
159
|
+
originalPrompt?: string;
|
|
158
160
|
expectedOutcome?: string;
|
|
159
161
|
evaluationCriteria?: string[];
|
|
160
162
|
}
|
|
@@ -41,7 +41,7 @@ export class ProviderRegistry {
|
|
|
41
41
|
// Register Amazon Bedrock provider
|
|
42
42
|
ProviderFactory.registerProvider(AIProviderName.BEDROCK, async (modelName, _providerName, sdk) => {
|
|
43
43
|
const { AmazonBedrockProvider } = await import("../providers/amazonBedrock.js");
|
|
44
|
-
return new AmazonBedrockProvider(modelName,
|
|
44
|
+
return new AmazonBedrockProvider(modelName, sdk);
|
|
45
45
|
}, undefined, // Let provider read BEDROCK_MODEL from .env
|
|
46
46
|
["bedrock", "aws"]);
|
|
47
47
|
// Register Azure OpenAI provider
|
package/dist/lib/index.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export { validateTool } from "./sdk/toolRegistration.js";
|
|
|
15
15
|
export type { ToolResult, ToolDefinition } from "./types/tools.js";
|
|
16
16
|
export { BedrockModels, OpenAIModels, VertexModels, DEFAULT_PROVIDER_CONFIGS, } from "./core/types.js";
|
|
17
17
|
export { getBestProvider, getAvailableProviders, isValidProvider, } from "./utils/providerUtils.js";
|
|
18
|
+
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
19
|
+
export type { ModelConfig, ModelRegistry } from "./core/dynamicModels.js";
|
|
18
20
|
export { NeuroLink } from "./neurolink.js";
|
|
19
21
|
export type { ProviderStatus, MCPStatus } from "./neurolink.js";
|
|
20
22
|
export type { MCPServerInfo } from "./types/mcpTypes.js";
|
package/dist/lib/index.js
CHANGED
|
@@ -14,6 +14,8 @@ export { validateTool } from "./sdk/toolRegistration.js";
|
|
|
14
14
|
export { BedrockModels, OpenAIModels, VertexModels, DEFAULT_PROVIDER_CONFIGS, } from "./core/types.js";
|
|
15
15
|
// Utility exports
|
|
16
16
|
export { getBestProvider, getAvailableProviders, isValidProvider, } from "./utils/providerUtils.js";
|
|
17
|
+
// Dynamic Models exports
|
|
18
|
+
export { dynamicModelProvider } from "./core/dynamicModels.js";
|
|
17
19
|
// Main NeuroLink wrapper class and diagnostic types
|
|
18
20
|
export { NeuroLink } from "./neurolink.js";
|
|
19
21
|
export { MiddlewareFactory } from "./middleware/factory.js";
|