ai.matey.middleware 0.2.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/LICENSE +21 -0
- package/dist/cjs/caching.js +226 -0
- package/dist/cjs/caching.js.map +1 -0
- package/dist/cjs/conversation-history.js +213 -0
- package/dist/cjs/conversation-history.js.map +1 -0
- package/dist/cjs/cost-tracking.js +355 -0
- package/dist/cjs/cost-tracking.js.map +1 -0
- package/dist/cjs/index.js +37 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/logging.js +174 -0
- package/dist/cjs/logging.js.map +1 -0
- package/dist/cjs/opentelemetry.js +499 -0
- package/dist/cjs/opentelemetry.js.map +1 -0
- package/dist/cjs/retry.js +205 -0
- package/dist/cjs/retry.js.map +1 -0
- package/dist/cjs/security.js +175 -0
- package/dist/cjs/security.js.map +1 -0
- package/dist/cjs/telemetry.js +216 -0
- package/dist/cjs/telemetry.js.map +1 -0
- package/dist/cjs/transform.js +284 -0
- package/dist/cjs/transform.js.map +1 -0
- package/dist/cjs/validation.js +506 -0
- package/dist/cjs/validation.js.map +1 -0
- package/dist/esm/caching.js +221 -0
- package/dist/esm/caching.js.map +1 -0
- package/dist/esm/conversation-history.js +207 -0
- package/dist/esm/conversation-history.js.map +1 -0
- package/dist/esm/cost-tracking.js +347 -0
- package/dist/esm/cost-tracking.js.map +1 -0
- package/dist/esm/index.js +21 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/logging.js +171 -0
- package/dist/esm/logging.js.map +1 -0
- package/dist/esm/opentelemetry.js +458 -0
- package/dist/esm/opentelemetry.js.map +1 -0
- package/dist/esm/retry.js +198 -0
- package/dist/esm/retry.js.map +1 -0
- package/dist/esm/security.js +169 -0
- package/dist/esm/security.js.map +1 -0
- package/dist/esm/telemetry.js +210 -0
- package/dist/esm/telemetry.js.map +1 -0
- package/dist/esm/transform.js +272 -0
- package/dist/esm/transform.js.map +1 -0
- package/dist/esm/validation.js +494 -0
- package/dist/esm/validation.js.map +1 -0
- package/dist/types/caching.d.ts +98 -0
- package/dist/types/caching.d.ts.map +1 -0
- package/dist/types/conversation-history.d.ts +188 -0
- package/dist/types/conversation-history.d.ts.map +1 -0
- package/dist/types/cost-tracking.d.ts +262 -0
- package/dist/types/cost-tracking.d.ts.map +1 -0
- package/dist/types/index.d.ts +20 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/logging.d.ts +82 -0
- package/dist/types/logging.d.ts.map +1 -0
- package/dist/types/opentelemetry.d.ts +219 -0
- package/dist/types/opentelemetry.d.ts.map +1 -0
- package/dist/types/retry.d.ts +86 -0
- package/dist/types/retry.d.ts.map +1 -0
- package/dist/types/security.d.ts +120 -0
- package/dist/types/security.d.ts.map +1 -0
- package/dist/types/telemetry.d.ts +120 -0
- package/dist/types/telemetry.d.ts.map +1 -0
- package/dist/types/transform.d.ts +184 -0
- package/dist/types/transform.d.ts.map +1 -0
- package/dist/types/validation.d.ts +356 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/package.json +203 -0
- package/readme.md +103 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 AI Matey Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Caching Middleware
|
|
4
|
+
*
|
|
5
|
+
* Caches responses with TTL-based expiration and LRU eviction.
|
|
6
|
+
*
|
|
7
|
+
* @module
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.InMemoryCacheStorage = void 0;
|
|
11
|
+
exports.createCachingMiddleware = createCachingMiddleware;
|
|
12
|
+
const crypto_1 = require("crypto");
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Default Key Generator
|
|
15
|
+
// ============================================================================
|
|
16
|
+
/**
|
|
17
|
+
* Default cache key generator.
|
|
18
|
+
*
|
|
19
|
+
* Generates cache key from model, messages, and parameters.
|
|
20
|
+
* Excludes metadata and streaming flag.
|
|
21
|
+
*/
|
|
22
|
+
function defaultKeyGenerator(request) {
|
|
23
|
+
// Create a stable cache key from request
|
|
24
|
+
const cacheableData = {
|
|
25
|
+
model: request.parameters?.model,
|
|
26
|
+
messages: request.messages,
|
|
27
|
+
temperature: request.parameters?.temperature,
|
|
28
|
+
maxTokens: request.parameters?.maxTokens,
|
|
29
|
+
topP: request.parameters?.topP,
|
|
30
|
+
topK: request.parameters?.topK,
|
|
31
|
+
stopSequences: request.parameters?.stopSequences,
|
|
32
|
+
tools: request.tools,
|
|
33
|
+
toolChoice: request.toolChoice,
|
|
34
|
+
};
|
|
35
|
+
// Generate hash
|
|
36
|
+
const json = JSON.stringify(cacheableData);
|
|
37
|
+
return (0, crypto_1.createHash)('sha256').update(json).digest('hex');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* In-memory cache storage with LRU eviction.
|
|
41
|
+
*/
|
|
42
|
+
class InMemoryCacheStorage {
|
|
43
|
+
cache = new Map();
|
|
44
|
+
accessOrder = [];
|
|
45
|
+
maxSize;
|
|
46
|
+
constructor(maxSize = 1000) {
|
|
47
|
+
this.maxSize = maxSize;
|
|
48
|
+
}
|
|
49
|
+
get(key) {
|
|
50
|
+
const entry = this.cache.get(key);
|
|
51
|
+
if (!entry) {
|
|
52
|
+
return Promise.resolve(undefined);
|
|
53
|
+
}
|
|
54
|
+
// Check if expired
|
|
55
|
+
if (Date.now() > entry.expiresAt) {
|
|
56
|
+
this.cache.delete(key);
|
|
57
|
+
this.removeFromAccessOrder(key);
|
|
58
|
+
return Promise.resolve(undefined);
|
|
59
|
+
}
|
|
60
|
+
// Update access order (LRU)
|
|
61
|
+
this.updateAccessOrder(key);
|
|
62
|
+
return Promise.resolve(entry.value);
|
|
63
|
+
}
|
|
64
|
+
set(key, value, ttl = 3600000) {
|
|
65
|
+
// Evict if at max size
|
|
66
|
+
if (this.cache.size >= this.maxSize && !this.cache.has(key)) {
|
|
67
|
+
this.evictLRU();
|
|
68
|
+
}
|
|
69
|
+
// Store entry
|
|
70
|
+
this.cache.set(key, {
|
|
71
|
+
value,
|
|
72
|
+
expiresAt: Date.now() + ttl,
|
|
73
|
+
});
|
|
74
|
+
// Update access order
|
|
75
|
+
this.updateAccessOrder(key);
|
|
76
|
+
return Promise.resolve();
|
|
77
|
+
}
|
|
78
|
+
has(key) {
|
|
79
|
+
const entry = this.cache.get(key);
|
|
80
|
+
if (!entry) {
|
|
81
|
+
return Promise.resolve(false);
|
|
82
|
+
}
|
|
83
|
+
// Check if expired
|
|
84
|
+
if (Date.now() > entry.expiresAt) {
|
|
85
|
+
this.cache.delete(key);
|
|
86
|
+
this.removeFromAccessOrder(key);
|
|
87
|
+
return Promise.resolve(false);
|
|
88
|
+
}
|
|
89
|
+
return Promise.resolve(true);
|
|
90
|
+
}
|
|
91
|
+
delete(key) {
|
|
92
|
+
this.removeFromAccessOrder(key);
|
|
93
|
+
return Promise.resolve(this.cache.delete(key));
|
|
94
|
+
}
|
|
95
|
+
clear() {
|
|
96
|
+
this.cache.clear();
|
|
97
|
+
this.accessOrder = [];
|
|
98
|
+
return Promise.resolve();
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Get cache statistics.
|
|
102
|
+
*/
|
|
103
|
+
getStats() {
|
|
104
|
+
return {
|
|
105
|
+
size: this.cache.size,
|
|
106
|
+
maxSize: this.maxSize,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Update LRU access order.
|
|
111
|
+
*/
|
|
112
|
+
updateAccessOrder(key) {
|
|
113
|
+
// Remove from current position
|
|
114
|
+
this.removeFromAccessOrder(key);
|
|
115
|
+
// Add to end (most recently used)
|
|
116
|
+
this.accessOrder.push(key);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Remove key from access order.
|
|
120
|
+
*/
|
|
121
|
+
removeFromAccessOrder(key) {
|
|
122
|
+
const index = this.accessOrder.indexOf(key);
|
|
123
|
+
if (index !== -1) {
|
|
124
|
+
this.accessOrder.splice(index, 1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Evict least recently used entry.
|
|
129
|
+
*/
|
|
130
|
+
evictLRU() {
|
|
131
|
+
if (this.accessOrder.length === 0) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// Get least recently used key (first in array)
|
|
135
|
+
const lruKey = this.accessOrder[0];
|
|
136
|
+
if (lruKey) {
|
|
137
|
+
this.cache.delete(lruKey);
|
|
138
|
+
this.accessOrder.shift();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Clean up expired entries.
|
|
143
|
+
*/
|
|
144
|
+
cleanup() {
|
|
145
|
+
const now = Date.now();
|
|
146
|
+
const expiredKeys = [];
|
|
147
|
+
// Use Array.from to avoid iteration issues
|
|
148
|
+
for (const [key, entry] of Array.from(this.cache.entries())) {
|
|
149
|
+
if (now > entry.expiresAt) {
|
|
150
|
+
expiredKeys.push(key);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
for (const key of expiredKeys) {
|
|
154
|
+
this.cache.delete(key);
|
|
155
|
+
this.removeFromAccessOrder(key);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
exports.InMemoryCacheStorage = InMemoryCacheStorage;
|
|
160
|
+
// ============================================================================
|
|
161
|
+
// Middleware Factory
|
|
162
|
+
// ============================================================================
|
|
163
|
+
/**
|
|
164
|
+
* Create caching middleware.
|
|
165
|
+
*
|
|
166
|
+
* Caches responses with TTL-based expiration and LRU eviction.
|
|
167
|
+
*
|
|
168
|
+
* @param config Caching configuration
|
|
169
|
+
* @returns Caching middleware
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* ```typescript
|
|
173
|
+
* const caching = createCachingMiddleware({
|
|
174
|
+
* ttl: 3600000, // 1 hour
|
|
175
|
+
* maxSize: 1000,
|
|
176
|
+
* cacheStreaming: false
|
|
177
|
+
* });
|
|
178
|
+
*
|
|
179
|
+
* bridge.use(caching);
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
function createCachingMiddleware(config = {}) {
|
|
183
|
+
const { keyGenerator = defaultKeyGenerator, ttl = 3600000, // 1 hour
|
|
184
|
+
maxSize = 1000, storage = new InMemoryCacheStorage(maxSize), cacheStreaming = false, } = config;
|
|
185
|
+
return async (context, next) => {
|
|
186
|
+
// Skip caching for streaming requests unless explicitly enabled
|
|
187
|
+
if (context.request.stream && !cacheStreaming) {
|
|
188
|
+
return next();
|
|
189
|
+
}
|
|
190
|
+
// Generate cache key
|
|
191
|
+
const cacheKey = keyGenerator(context.request);
|
|
192
|
+
// Check cache
|
|
193
|
+
const cachedResponse = await storage.get(cacheKey);
|
|
194
|
+
if (cachedResponse) {
|
|
195
|
+
// Cache hit - add cache metadata
|
|
196
|
+
return {
|
|
197
|
+
...cachedResponse,
|
|
198
|
+
metadata: {
|
|
199
|
+
...cachedResponse.metadata,
|
|
200
|
+
custom: {
|
|
201
|
+
...cachedResponse.metadata.custom,
|
|
202
|
+
cacheHit: true,
|
|
203
|
+
cacheKey,
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
// Cache miss - call next middleware/handler
|
|
209
|
+
const response = await next();
|
|
210
|
+
// Store in cache
|
|
211
|
+
await storage.set(cacheKey, response, ttl);
|
|
212
|
+
// Add cache metadata
|
|
213
|
+
return {
|
|
214
|
+
...response,
|
|
215
|
+
metadata: {
|
|
216
|
+
...response.metadata,
|
|
217
|
+
custom: {
|
|
218
|
+
...response.metadata.custom,
|
|
219
|
+
cacheHit: false,
|
|
220
|
+
cacheKey,
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=caching.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caching.js","sourceRoot":"","sources":["../../src/caching.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Conversation History Middleware
|
|
4
|
+
*
|
|
5
|
+
* Manages conversation history across requests with configurable trimming strategies.
|
|
6
|
+
* Maintains a global conversation history that can be accessed and modified by requests.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.createConversationHistoryMiddleware = createConversationHistoryMiddleware;
|
|
12
|
+
exports.simpleConversationHistory = simpleConversationHistory;
|
|
13
|
+
exports.statelessConversation = statelessConversation;
|
|
14
|
+
exports.conversationOnlyHistory = conversationOnlyHistory;
|
|
15
|
+
const ai_matey_utils_1 = require("ai.matey.utils");
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Middleware Factory
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Create conversation history middleware.
|
|
21
|
+
*
|
|
22
|
+
* Maintains a global conversation history across requests. Automatically prepends
|
|
23
|
+
* history to requests and appends responses to history after completion.
|
|
24
|
+
*
|
|
25
|
+
* @param config Conversation history configuration
|
|
26
|
+
* @returns Conversation history middleware and manager
|
|
27
|
+
*
|
|
28
|
+
* @example Basic Usage
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const { middleware, manager } = createConversationHistoryMiddleware({
|
|
31
|
+
* maxHistorySize: 10,
|
|
32
|
+
* strategy: 'smart'
|
|
33
|
+
* });
|
|
34
|
+
*
|
|
35
|
+
* bridge.use(middleware);
|
|
36
|
+
*
|
|
37
|
+
* // Access history
|
|
38
|
+
* console.log('Pairs:', manager.getPairCount());
|
|
39
|
+
* console.log('History:', manager.getHistory());
|
|
40
|
+
*
|
|
41
|
+
* // Clear history when needed
|
|
42
|
+
* manager.clear();
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* @example With Initial System Message
|
|
46
|
+
* ```typescript
|
|
47
|
+
* const { middleware } = createConversationHistoryMiddleware({
|
|
48
|
+
* initialHistory: [
|
|
49
|
+
* { role: 'system', content: 'You are a helpful assistant.' }
|
|
50
|
+
* ],
|
|
51
|
+
* maxHistorySize: 5,
|
|
52
|
+
* strategy: 'smart' // Preserves system message
|
|
53
|
+
* });
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* @example Stateless Mode (No History)
|
|
57
|
+
* ```typescript
|
|
58
|
+
* const { middleware } = createConversationHistoryMiddleware({
|
|
59
|
+
* maxHistorySize: 0 // No history tracking
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
* @example Custom Message Filtering
|
|
64
|
+
* ```typescript
|
|
65
|
+
* const { middleware } = createConversationHistoryMiddleware({
|
|
66
|
+
* maxHistorySize: 10,
|
|
67
|
+
* // Only track user and assistant messages, ignore system
|
|
68
|
+
* messageFilter: (msg) => msg.role !== 'system'
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
function createConversationHistoryMiddleware(config = {}) {
|
|
73
|
+
const { maxHistorySize = -1, strategy = 'smart', prependHistory = true, trackResponses = true, initialHistory = [], messageFilter = () => true, } = config;
|
|
74
|
+
// Internal conversation history state
|
|
75
|
+
let history = [...initialHistory];
|
|
76
|
+
// Create manager for external access
|
|
77
|
+
const manager = {
|
|
78
|
+
getHistory: () => [...history],
|
|
79
|
+
addMessage: (message) => {
|
|
80
|
+
if (messageFilter(message)) {
|
|
81
|
+
history.push(message);
|
|
82
|
+
manager.trim();
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
addMessages: (messages) => {
|
|
86
|
+
for (const message of messages) {
|
|
87
|
+
if (messageFilter(message)) {
|
|
88
|
+
history.push(message);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
manager.trim();
|
|
92
|
+
},
|
|
93
|
+
clear: () => {
|
|
94
|
+
history = [];
|
|
95
|
+
},
|
|
96
|
+
setHistory: (newHistory) => {
|
|
97
|
+
history = [...newHistory];
|
|
98
|
+
manager.trim();
|
|
99
|
+
},
|
|
100
|
+
getPairCount: () => {
|
|
101
|
+
const nonSystemMessages = history.filter((m) => m.role !== 'system');
|
|
102
|
+
return Math.floor(nonSystemMessages.length / 2);
|
|
103
|
+
},
|
|
104
|
+
trim: () => {
|
|
105
|
+
if ((0, ai_matey_utils_1.shouldTrimHistory)(history, maxHistorySize, strategy)) {
|
|
106
|
+
history = (0, ai_matey_utils_1.trimHistory)(history, maxHistorySize, strategy);
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
// Create middleware
|
|
111
|
+
const middleware = async (context, next) => {
|
|
112
|
+
let request = context.request;
|
|
113
|
+
// Prepend history to request if enabled
|
|
114
|
+
if (prependHistory && maxHistorySize !== 0) {
|
|
115
|
+
const currentHistory = manager.getHistory();
|
|
116
|
+
// Merge history with request messages
|
|
117
|
+
// Filter out duplicate system messages from request if history already has them
|
|
118
|
+
const requestMessages = request.messages.filter((msg) => {
|
|
119
|
+
// Keep all non-system messages
|
|
120
|
+
if (msg.role !== 'system') {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
// For system messages, only keep if not already in history
|
|
124
|
+
const existingSystemMessage = currentHistory.find((h) => h.role === 'system' && h.content === msg.content);
|
|
125
|
+
return !existingSystemMessage;
|
|
126
|
+
});
|
|
127
|
+
request = {
|
|
128
|
+
...request,
|
|
129
|
+
messages: [...currentHistory, ...requestMessages],
|
|
130
|
+
};
|
|
131
|
+
context.request = request;
|
|
132
|
+
}
|
|
133
|
+
// Call next middleware/handler
|
|
134
|
+
const response = await next();
|
|
135
|
+
// Track response in history if enabled
|
|
136
|
+
if (trackResponses && maxHistorySize !== 0) {
|
|
137
|
+
// Add the new user message(s) from this request to history
|
|
138
|
+
const newUserMessages = context.request.messages.filter((msg) => msg.role === 'user' || msg.role === 'assistant');
|
|
139
|
+
// Find messages that aren't already in history
|
|
140
|
+
for (const msg of newUserMessages) {
|
|
141
|
+
const alreadyInHistory = history.some((h) => h.role === msg.role &&
|
|
142
|
+
h.content === msg.content &&
|
|
143
|
+
h.timestamp === msg.timestamp);
|
|
144
|
+
if (!alreadyInHistory) {
|
|
145
|
+
manager.addMessage(msg);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Add assistant response to history
|
|
149
|
+
if (response.message) {
|
|
150
|
+
manager.addMessage(response.message);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return response;
|
|
154
|
+
};
|
|
155
|
+
return { middleware, manager };
|
|
156
|
+
}
|
|
157
|
+
// ============================================================================
|
|
158
|
+
// Helper Functions
|
|
159
|
+
// ============================================================================
|
|
160
|
+
/**
|
|
161
|
+
* Create a simple conversation history middleware with minimal config.
|
|
162
|
+
*
|
|
163
|
+
* @param maxHistorySize Maximum number of message pairs to keep
|
|
164
|
+
* @returns Conversation history middleware
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* // Keep last 5 message pairs
|
|
169
|
+
* bridge.use(simpleConversationHistory(5));
|
|
170
|
+
* ```
|
|
171
|
+
*/
|
|
172
|
+
function simpleConversationHistory(maxHistorySize = 10) {
|
|
173
|
+
const { middleware } = createConversationHistoryMiddleware({ maxHistorySize });
|
|
174
|
+
return middleware;
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Create a stateless conversation history middleware.
|
|
178
|
+
* Useful for explicitly disabling history in a pipeline.
|
|
179
|
+
*
|
|
180
|
+
* @returns Stateless middleware
|
|
181
|
+
*
|
|
182
|
+
* @example
|
|
183
|
+
* ```typescript
|
|
184
|
+
* // Explicitly disable history
|
|
185
|
+
* bridge.use(statelessConversation());
|
|
186
|
+
* ```
|
|
187
|
+
*/
|
|
188
|
+
function statelessConversation() {
|
|
189
|
+
const { middleware } = createConversationHistoryMiddleware({ maxHistorySize: 0 });
|
|
190
|
+
return middleware;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Create a conversation history middleware that only tracks user/assistant pairs.
|
|
194
|
+
* System messages from requests are passed through but not tracked.
|
|
195
|
+
*
|
|
196
|
+
* @param maxHistorySize Maximum number of message pairs
|
|
197
|
+
* @returns Conversation history middleware
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* // Track conversation but not system messages
|
|
202
|
+
* bridge.use(conversationOnlyHistory(10));
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
function conversationOnlyHistory(maxHistorySize = 10) {
|
|
206
|
+
const { middleware } = createConversationHistoryMiddleware({
|
|
207
|
+
maxHistorySize,
|
|
208
|
+
strategy: 'fifo',
|
|
209
|
+
messageFilter: (msg) => msg.role !== 'system',
|
|
210
|
+
});
|
|
211
|
+
return middleware;
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=conversation-history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversation-history.js","sourceRoot":"","sources":["../../src/conversation-history.ts"],"names":[],"mappings":"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"}
|