@aj-archipelago/cortex 1.3.5 → 1.3.7
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/helper-apps/cortex-autogen/agents.py +31 -2
- package/helper-apps/cortex-realtime-voice-server/.env.sample +6 -0
- package/helper-apps/cortex-realtime-voice-server/README.md +22 -0
- package/helper-apps/cortex-realtime-voice-server/bun.lockb +0 -0
- package/helper-apps/cortex-realtime-voice-server/client/bun.lockb +0 -0
- package/helper-apps/cortex-realtime-voice-server/client/index.html +12 -0
- package/helper-apps/cortex-realtime-voice-server/client/package.json +65 -0
- package/helper-apps/cortex-realtime-voice-server/client/postcss.config.js +6 -0
- package/helper-apps/cortex-realtime-voice-server/client/public/favicon.ico +0 -0
- package/helper-apps/cortex-realtime-voice-server/client/public/index.html +43 -0
- package/helper-apps/cortex-realtime-voice-server/client/public/logo192.png +0 -0
- package/helper-apps/cortex-realtime-voice-server/client/public/logo512.png +0 -0
- package/helper-apps/cortex-realtime-voice-server/client/public/manifest.json +25 -0
- package/helper-apps/cortex-realtime-voice-server/client/public/robots.txt +3 -0
- package/helper-apps/cortex-realtime-voice-server/client/public/sounds/connect.mp3 +0 -0
- package/helper-apps/cortex-realtime-voice-server/client/public/sounds/disconnect.mp3 +0 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/App.test.tsx +9 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/App.tsx +126 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/SettingsModal.tsx +207 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/Chat.tsx +553 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatBubble.tsx +22 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatBubbleLeft.tsx +22 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatBubbleRight.tsx +21 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatMessage.tsx +27 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatMessageInput.tsx +74 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/ChatTile.tsx +211 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/SoundEffects.ts +56 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/WavPacker.ts +112 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/WavRecorder.ts +571 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/WavStreamPlayer.ts +290 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/analysis/AudioAnalysis.ts +186 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/analysis/constants.ts +59 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/worklets/AudioProcessor.ts +214 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/audio/worklets/StreamProcessor.ts +183 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/AudioVisualizer.tsx +151 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/CopyButton.tsx +32 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/ImageOverlay.tsx +166 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/MicrophoneVisualizer.tsx +95 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/components/ScreenshotCapture.tsx +116 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/hooks/useWindowResize.ts +27 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/chat/utils/audio.ts +33 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/index.css +20 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/index.tsx +19 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/logo.svg +1 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/react-app-env.d.ts +1 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/reportWebVitals.ts +15 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/setupTests.ts +5 -0
- package/helper-apps/cortex-realtime-voice-server/client/src/utils/logger.ts +45 -0
- package/helper-apps/cortex-realtime-voice-server/client/tailwind.config.js +14 -0
- package/helper-apps/cortex-realtime-voice-server/client/tsconfig.json +30 -0
- package/helper-apps/cortex-realtime-voice-server/client/vite.config.ts +22 -0
- package/helper-apps/cortex-realtime-voice-server/index.ts +19 -0
- package/helper-apps/cortex-realtime-voice-server/package.json +28 -0
- package/helper-apps/cortex-realtime-voice-server/src/ApiServer.ts +35 -0
- package/helper-apps/cortex-realtime-voice-server/src/SocketServer.ts +737 -0
- package/helper-apps/cortex-realtime-voice-server/src/Tools.ts +520 -0
- package/helper-apps/cortex-realtime-voice-server/src/cortex/expert.ts +29 -0
- package/helper-apps/cortex-realtime-voice-server/src/cortex/image.ts +29 -0
- package/helper-apps/cortex-realtime-voice-server/src/cortex/memory.ts +91 -0
- package/helper-apps/cortex-realtime-voice-server/src/cortex/reason.ts +29 -0
- package/helper-apps/cortex-realtime-voice-server/src/cortex/search.ts +30 -0
- package/helper-apps/cortex-realtime-voice-server/src/cortex/style.ts +31 -0
- package/helper-apps/cortex-realtime-voice-server/src/cortex/utils.ts +95 -0
- package/helper-apps/cortex-realtime-voice-server/src/cortex/vision.ts +34 -0
- package/helper-apps/cortex-realtime-voice-server/src/realtime/client.ts +499 -0
- package/helper-apps/cortex-realtime-voice-server/src/realtime/realtimeTypes.ts +279 -0
- package/helper-apps/cortex-realtime-voice-server/src/realtime/socket.ts +27 -0
- package/helper-apps/cortex-realtime-voice-server/src/realtime/transcription.ts +75 -0
- package/helper-apps/cortex-realtime-voice-server/src/realtime/utils.ts +33 -0
- package/helper-apps/cortex-realtime-voice-server/src/utils/logger.ts +45 -0
- package/helper-apps/cortex-realtime-voice-server/src/utils/prompt.ts +81 -0
- package/helper-apps/cortex-realtime-voice-server/tsconfig.json +28 -0
- package/package.json +1 -1
- package/pathways/basePathway.js +3 -1
- package/pathways/system/entity/memory/sys_memory_manager.js +3 -0
- package/pathways/system/entity/memory/sys_memory_update.js +44 -45
- package/pathways/system/entity/memory/sys_read_memory.js +86 -6
- package/pathways/system/entity/memory/sys_search_memory.js +66 -0
- package/pathways/system/entity/shared/sys_entity_constants.js +2 -2
- package/pathways/system/entity/sys_entity_continue.js +2 -1
- package/pathways/system/entity/sys_entity_start.js +10 -0
- package/pathways/system/entity/sys_generator_expert.js +0 -2
- package/pathways/system/entity/sys_generator_memory.js +31 -0
- package/pathways/system/entity/sys_generator_voice_sample.js +36 -0
- package/pathways/system/entity/sys_router_tool.js +13 -10
- package/pathways/system/sys_parse_numbered_object_list.js +1 -1
- package/server/pathwayResolver.js +41 -31
- package/server/plugins/azureVideoTranslatePlugin.js +28 -16
- package/server/plugins/claude3VertexPlugin.js +0 -9
- package/server/plugins/gemini15ChatPlugin.js +18 -5
- package/server/plugins/modelPlugin.js +27 -6
- package/server/plugins/openAiChatPlugin.js +10 -8
- package/server/plugins/openAiVisionPlugin.js +56 -0
- package/tests/memoryfunction.test.js +73 -1
|
@@ -223,21 +223,42 @@ class PathwayResolver {
|
|
|
223
223
|
this.savedContextId = contextId ? contextId : uuidv4();
|
|
224
224
|
|
|
225
225
|
const loadMemory = async () => {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
226
|
+
try {
|
|
227
|
+
// Load saved context and core memory if it exists
|
|
228
|
+
const [savedContext, memorySelf, memoryDirectives, memoryTopics, memoryUser, memoryContext] = await Promise.all([
|
|
229
|
+
(getv && await getv(this.savedContextId)) || {},
|
|
230
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memorySelf', priority: 1}),
|
|
231
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memoryDirectives', priority: 1 }),
|
|
232
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memoryTopics', priority: 0, numResults: 10 }),
|
|
233
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memoryUser', priority: 1 }),
|
|
234
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memoryContext', priority: 0 }),
|
|
235
|
+
]).catch(error => {
|
|
236
|
+
this.logError(`Failed to load memory: ${error.message}`);
|
|
237
|
+
return [{},'','','','',''];
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
this.savedContext = savedContext;
|
|
241
|
+
this.memorySelf = memorySelf || '';
|
|
242
|
+
this.memoryDirectives = memoryDirectives || '';
|
|
243
|
+
this.memoryTopics = memoryTopics || '';
|
|
244
|
+
this.memoryUser = memoryUser || '';
|
|
245
|
+
this.memoryContext = memoryContext || '';
|
|
246
|
+
|
|
247
|
+
// Store initial state for comparison
|
|
248
|
+
this.initialState = {
|
|
249
|
+
savedContext: this.savedContext,
|
|
250
|
+
};
|
|
251
|
+
} catch (error) {
|
|
252
|
+
this.logError(`Error in loadMemory: ${error.message}`);
|
|
253
|
+
// Set default values in case of error
|
|
254
|
+
this.savedContext = {};
|
|
255
|
+
this.memorySelf = '';
|
|
256
|
+
this.memoryDirectives = '';
|
|
257
|
+
this.memoryTopics = '';
|
|
258
|
+
this.memoryUser = '';
|
|
259
|
+
this.memoryContext = '';
|
|
260
|
+
this.initialState = { savedContext: {} };
|
|
261
|
+
}
|
|
241
262
|
};
|
|
242
263
|
|
|
243
264
|
const saveChangedMemory = async () => {
|
|
@@ -245,27 +266,11 @@ class PathwayResolver {
|
|
|
245
266
|
|
|
246
267
|
const currentState = {
|
|
247
268
|
savedContext: this.savedContext,
|
|
248
|
-
memorySelf: this.memorySelf,
|
|
249
|
-
memoryDirectives: this.memoryDirectives,
|
|
250
|
-
memoryTopics: this.memoryTopics,
|
|
251
|
-
memoryUser: this.memoryUser
|
|
252
269
|
};
|
|
253
270
|
|
|
254
271
|
if (currentState.savedContext !== this.initialState.savedContext) {
|
|
255
272
|
setv && await setv(this.savedContextId, this.savedContext);
|
|
256
273
|
}
|
|
257
|
-
if (currentState.memorySelf !== this.initialState.memorySelf) {
|
|
258
|
-
setv && await setv(`${this.savedContextId}-memorySelf`, this.memorySelf);
|
|
259
|
-
}
|
|
260
|
-
if (currentState.memoryDirectives !== this.initialState.memoryDirectives) {
|
|
261
|
-
setv && await setv(`${this.savedContextId}-memoryDirectives`, this.memoryDirectives);
|
|
262
|
-
}
|
|
263
|
-
if (currentState.memoryTopics !== this.initialState.memoryTopics) {
|
|
264
|
-
setv && await setv(`${this.savedContextId}-memoryTopics`, this.memoryTopics);
|
|
265
|
-
}
|
|
266
|
-
if (currentState.memoryUser !== this.initialState.memoryUser) {
|
|
267
|
-
setv && await setv(`${this.savedContextId}-memoryUser`, this.memoryUser);
|
|
268
|
-
}
|
|
269
274
|
};
|
|
270
275
|
|
|
271
276
|
const MAX_RETRIES = 3;
|
|
@@ -344,6 +349,11 @@ class PathwayResolver {
|
|
|
344
349
|
|
|
345
350
|
// Calculate the maximum token length for a chunk
|
|
346
351
|
getChunkMaxTokenLength() {
|
|
352
|
+
// Skip expensive calculations if not using input chunking
|
|
353
|
+
if (!this.useInputChunking) {
|
|
354
|
+
return this.modelExecutor.plugin.getModelMaxTokenLength();
|
|
355
|
+
}
|
|
356
|
+
|
|
347
357
|
// find the longest prompt
|
|
348
358
|
const maxPromptTokenLength = Math.max(...this.prompts.map((promptData) => this.modelExecutor.plugin.getCompiledPrompt('', this.args, promptData).tokenLength));
|
|
349
359
|
|
|
@@ -7,13 +7,13 @@ import { config } from "../../config.js";
|
|
|
7
7
|
|
|
8
8
|
function isValidJSON(str) {
|
|
9
9
|
try {
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
JSON.parse(str);
|
|
11
|
+
return true;
|
|
12
12
|
} catch (e) {
|
|
13
|
-
|
|
13
|
+
return false;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
|
|
17
17
|
class AzureVideoTranslatePlugin extends ModelPlugin {
|
|
18
18
|
constructor(pathway, model) {
|
|
19
19
|
super(pathway, model);
|
|
@@ -21,8 +21,6 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
|
|
|
21
21
|
this.eventSource = null;
|
|
22
22
|
this.jsonBuffer = '';
|
|
23
23
|
this.jsonDepth = 0;
|
|
24
|
-
this.currentStep = 0;
|
|
25
|
-
this.totalNumOfSteps = 30;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
getRequestParameters(_, parameters, __) {
|
|
@@ -77,11 +75,23 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
|
|
|
77
75
|
this.jsonDepth += (data.match(/{/g) || []).length - (data.match(/}/g) || []).length;
|
|
78
76
|
|
|
79
77
|
if (this.jsonDepth === 0 && this.jsonBuffer.trim()) {
|
|
80
|
-
|
|
78
|
+
logger.debug(this.jsonBuffer);
|
|
81
79
|
if (this.jsonBuffer.includes('Failed to run with exception')) {
|
|
82
80
|
this.cleanup();
|
|
83
81
|
throw new Error(this.jsonBuffer);
|
|
84
82
|
}
|
|
83
|
+
|
|
84
|
+
if (isValidJSON(this.jsonBuffer)) {
|
|
85
|
+
const parsedData = JSON.parse(this.jsonBuffer);
|
|
86
|
+
if (parsedData.progress !== undefined) {
|
|
87
|
+
publishRequestProgress({
|
|
88
|
+
requestId: this.requestId,
|
|
89
|
+
progress: parsedData.progress,
|
|
90
|
+
info: this.jsonBuffer
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
85
95
|
onData(this.jsonBuffer);
|
|
86
96
|
this.jsonBuffer = '';
|
|
87
97
|
this.jsonDepth = 0;
|
|
@@ -106,21 +116,23 @@ class AzureVideoTranslatePlugin extends ModelPlugin {
|
|
|
106
116
|
|
|
107
117
|
return new Promise((resolve, reject) => {
|
|
108
118
|
let finalJson = '';
|
|
109
|
-
this.handleStream(response.data,
|
|
110
|
-
(data) => {
|
|
111
|
-
this.currentStep++;
|
|
119
|
+
this.handleStream(response.data,
|
|
120
|
+
(data) => {
|
|
112
121
|
publishRequestProgress({
|
|
113
122
|
requestId: this.requestId,
|
|
114
|
-
progress: this.currentStep / this.totalNumOfSteps,
|
|
115
|
-
// data: this.jsonBuffer,
|
|
116
123
|
info: data
|
|
117
124
|
});
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
125
|
+
logger.debug('Data:', data);
|
|
126
|
+
// Extract JSON content if message contains targetLocales
|
|
127
|
+
const jsonMatch = data.match(/{[\s\S]*"targetLocales"[\s\S]*}/);
|
|
128
|
+
if (jsonMatch) {
|
|
129
|
+
const extractedJson = jsonMatch[0];
|
|
130
|
+
if (isValidJSON(extractedJson)) {
|
|
131
|
+
finalJson = extractedJson;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
121
134
|
},
|
|
122
135
|
() => {
|
|
123
|
-
// console.log('Full data:', fullData);
|
|
124
136
|
resolve(finalJson)
|
|
125
137
|
},
|
|
126
138
|
(error) => reject(error)
|
|
@@ -309,15 +309,6 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
|
|
|
309
309
|
return requestProgress;
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
shortenContent(content, maxWords = 40) {
|
|
313
|
-
const words = content.split(" ");
|
|
314
|
-
if (words.length <= maxWords || logger.level === 'debug') {
|
|
315
|
-
return content;
|
|
316
|
-
}
|
|
317
|
-
return words.slice(0, maxWords / 2).join(" ") +
|
|
318
|
-
" ... " +
|
|
319
|
-
words.slice(-maxWords / 2).join(" ");
|
|
320
|
-
}
|
|
321
312
|
}
|
|
322
313
|
|
|
323
314
|
export default Claude3VertexPlugin;
|
|
@@ -179,24 +179,37 @@ class Gemini15ChatPlugin extends ModelPlugin {
|
|
|
179
179
|
const messageContent = message.parts.reduce((acc, part) => {
|
|
180
180
|
if (part.text) {
|
|
181
181
|
return acc + part.text;
|
|
182
|
+
} else if (part.inlineData) {
|
|
183
|
+
return acc + '* base64 data truncated for log *';
|
|
184
|
+
} else if (part.fileData) {
|
|
185
|
+
return acc + part.fileData.fileUri;
|
|
182
186
|
}
|
|
183
187
|
return acc;
|
|
184
188
|
} , '');
|
|
185
|
-
const words = messageContent.split(" ");
|
|
186
189
|
const { length, units } = this.getLength(messageContent);
|
|
187
|
-
const preview =
|
|
190
|
+
const preview = this.shortenContent(messageContent);
|
|
188
191
|
|
|
189
192
|
logger.verbose(`message ${index + 1}: role: ${message.role}, ${units}: ${length}, content: "${preview}"`);
|
|
190
193
|
});
|
|
191
194
|
} else if (messages && messages.length === 1) {
|
|
192
|
-
|
|
195
|
+
const messageContent = messages[0].parts.reduce((acc, part) => {
|
|
196
|
+
if (part.text) {
|
|
197
|
+
return acc + part.text;
|
|
198
|
+
} else if (part.inlineData) {
|
|
199
|
+
return acc + '* base64 data truncated for log *';
|
|
200
|
+
} else if (part.fileData) {
|
|
201
|
+
return acc + part.fileData.fileUri;
|
|
202
|
+
}
|
|
203
|
+
return acc;
|
|
204
|
+
} , '');
|
|
205
|
+
logger.verbose(`${this.shortenContent(messageContent)}`);
|
|
193
206
|
}
|
|
194
207
|
|
|
195
208
|
// check if responseData is an array or string
|
|
196
209
|
if (typeof responseData === 'string') {
|
|
197
210
|
const { length, units } = this.getLength(responseData);
|
|
198
211
|
logger.info(`[response received containing ${length} ${units}]`);
|
|
199
|
-
logger.verbose(`${responseData}`);
|
|
212
|
+
logger.verbose(`${this.shortenContent(responseData)}`);
|
|
200
213
|
} else if (Array.isArray(responseData)) {
|
|
201
214
|
const { mergedResult, safetyRatings } = mergeResults(responseData);
|
|
202
215
|
if (safetyRatings?.length) {
|
|
@@ -205,7 +218,7 @@ class Gemini15ChatPlugin extends ModelPlugin {
|
|
|
205
218
|
}
|
|
206
219
|
const { length, units } = this.getLength(mergedResult);
|
|
207
220
|
logger.info(`[response received containing ${length} ${units}]`);
|
|
208
|
-
logger.verbose(`${mergedResult}`);
|
|
221
|
+
logger.verbose(`${this.shortenContent(mergedResult)}`);
|
|
209
222
|
} else {
|
|
210
223
|
logger.info(`[response received as an SSE stream]`);
|
|
211
224
|
}
|
|
@@ -36,11 +36,19 @@ class ModelPlugin {
|
|
|
36
36
|
this.requestCount = 0;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
safeGetEncodedLength(data) {
|
|
40
|
+
if (data && data.length > 100000) {
|
|
41
|
+
return data.length * 3 / 16;
|
|
42
|
+
} else {
|
|
43
|
+
return encode(data).length;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
39
47
|
truncateMessagesToTargetLength(messages, targetTokenLength) {
|
|
40
48
|
// Calculate the token length of each message
|
|
41
49
|
const tokenLengths = messages.map((message) => ({
|
|
42
50
|
message,
|
|
43
|
-
tokenLength:
|
|
51
|
+
tokenLength: this.safeGetEncodedLength(this.messagesToChatML([message], false)),
|
|
44
52
|
}));
|
|
45
53
|
|
|
46
54
|
// Calculate the total token length of all messages
|
|
@@ -89,7 +97,7 @@ class ModelPlugin {
|
|
|
89
97
|
|
|
90
98
|
tokenLengths[index] = {
|
|
91
99
|
message: truncatedMessage,
|
|
92
|
-
tokenLength:
|
|
100
|
+
tokenLength: this.safeGetEncodedLength(this.messagesToChatML([ truncatedMessage ], false))
|
|
93
101
|
}
|
|
94
102
|
|
|
95
103
|
// calculate the length again to keep us honest
|
|
@@ -141,9 +149,9 @@ class ModelPlugin {
|
|
|
141
149
|
const modelPromptMessagesML = this.messagesToChatML(modelPromptMessages);
|
|
142
150
|
|
|
143
151
|
if (modelPromptMessagesML) {
|
|
144
|
-
return { modelPromptMessages, tokenLength:
|
|
152
|
+
return { modelPromptMessages, tokenLength: this.safeGetEncodedLength(modelPromptMessagesML), modelPrompt };
|
|
145
153
|
} else {
|
|
146
|
-
return { modelPromptText, tokenLength:
|
|
154
|
+
return { modelPromptText, tokenLength: this.safeGetEncodedLength(modelPromptText), modelPrompt };
|
|
147
155
|
}
|
|
148
156
|
}
|
|
149
157
|
|
|
@@ -260,19 +268,32 @@ class ModelPlugin {
|
|
|
260
268
|
return {length, units};
|
|
261
269
|
}
|
|
262
270
|
|
|
271
|
+
shortenContent(content, maxWords = 40) {
|
|
272
|
+
if (!content || typeof content !== 'string') {
|
|
273
|
+
return content;
|
|
274
|
+
}
|
|
275
|
+
const words = content.split(" ");
|
|
276
|
+
if (words.length <= maxWords || logger.level === 'debug') {
|
|
277
|
+
return content;
|
|
278
|
+
}
|
|
279
|
+
return words.slice(0, maxWords / 2).join(" ") +
|
|
280
|
+
" ... " +
|
|
281
|
+
words.slice(-maxWords / 2).join(" ");
|
|
282
|
+
}
|
|
283
|
+
|
|
263
284
|
logRequestData(data, responseData, prompt) {
|
|
264
285
|
const modelInput = data.prompt || (data.messages && data.messages[0].content) || (data.length > 0 && data[0].Text) || null;
|
|
265
286
|
|
|
266
287
|
if (modelInput) {
|
|
267
288
|
const { length, units } = this.getLength(modelInput);
|
|
268
289
|
logger.info(`[request sent containing ${length} ${units}]`);
|
|
269
|
-
logger.verbose(`${modelInput}`);
|
|
290
|
+
logger.verbose(`${this.shortenContent(modelInput)}`);
|
|
270
291
|
}
|
|
271
292
|
|
|
272
293
|
const responseText = JSON.stringify(responseData);
|
|
273
294
|
const { length, units } = this.getLength(responseText);
|
|
274
295
|
logger.info(`[response received containing ${length} ${units}]`);
|
|
275
|
-
logger.verbose(`${responseText}`);
|
|
296
|
+
logger.verbose(`${this.shortenContent(responseText)}`);
|
|
276
297
|
|
|
277
298
|
prompt && prompt.debugInfo && (prompt.debugInfo += `\n${JSON.stringify(data)}`);
|
|
278
299
|
}
|
|
@@ -61,7 +61,7 @@ class OpenAIChatPlugin extends ModelPlugin {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// Check if the token length exceeds the model's max token length
|
|
64
|
-
if (tokenLength > modelTargetTokenLength) {
|
|
64
|
+
if (tokenLength > modelTargetTokenLength && this.promptParameters?.manageTokenLength) {
|
|
65
65
|
// Remove older messages until the token length is within the model's limit
|
|
66
66
|
requestMessages = this.truncateMessagesToTargetLength(requestMessages, modelTargetTokenLength);
|
|
67
67
|
}
|
|
@@ -112,11 +112,11 @@ class OpenAIChatPlugin extends ModelPlugin {
|
|
|
112
112
|
let totalUnits;
|
|
113
113
|
messages.forEach((message, index) => {
|
|
114
114
|
//message.content string or array
|
|
115
|
-
const content = message.content === undefined ? JSON.stringify(message) : (Array.isArray(message.content) ? message.content.map(item =>
|
|
116
|
-
|
|
115
|
+
const content = message.content === undefined ? JSON.stringify(message) : (Array.isArray(message.content) ? message.content.map(item => {
|
|
116
|
+
return JSON.stringify(item);
|
|
117
|
+
}).join(', ') : message.content);
|
|
117
118
|
const { length, units } = this.getLength(content);
|
|
118
|
-
|
|
119
|
-
const displayContent = logger.level === 'debug' ? content : (words.length < 41 ? content : words.slice(0, 20).join(" ") + " ... " + words.slice(-20).join(" "));
|
|
119
|
+
const displayContent = this.shortenContent(content);
|
|
120
120
|
|
|
121
121
|
logger.verbose(`message ${index + 1}: role: ${message.role}, ${units}: ${length}, content: "${displayContent}"`);
|
|
122
122
|
totalLength += length;
|
|
@@ -125,10 +125,12 @@ class OpenAIChatPlugin extends ModelPlugin {
|
|
|
125
125
|
logger.info(`[chat request contained ${totalLength} ${totalUnits}]`);
|
|
126
126
|
} else {
|
|
127
127
|
const message = messages[0];
|
|
128
|
-
const content = Array.isArray(message.content) ? message.content.map(item =>
|
|
128
|
+
const content = Array.isArray(message.content) ? message.content.map(item => {
|
|
129
|
+
return JSON.stringify(item);
|
|
130
|
+
}).join(', ') : message.content;
|
|
129
131
|
const { length, units } = this.getLength(content);
|
|
130
132
|
logger.info(`[request sent containing ${length} ${units}]`);
|
|
131
|
-
logger.verbose(`${content}`);
|
|
133
|
+
logger.verbose(`${this.shortenContent(content)}`);
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
if (stream) {
|
|
@@ -137,7 +139,7 @@ class OpenAIChatPlugin extends ModelPlugin {
|
|
|
137
139
|
const responseText = this.parseResponse(responseData);
|
|
138
140
|
const { length, units } = this.getLength(responseText);
|
|
139
141
|
logger.info(`[response received containing ${length} ${units}]`);
|
|
140
|
-
logger.verbose(`${responseText}`);
|
|
142
|
+
logger.verbose(`${this.shortenContent(responseText)}`);
|
|
141
143
|
}
|
|
142
144
|
|
|
143
145
|
prompt && prompt.debugInfo && (prompt.debugInfo += `\n${JSON.stringify(data)}`);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import OpenAIChatPlugin from './openAiChatPlugin.js';
|
|
2
|
+
import logger from '../../lib/logger.js';
|
|
2
3
|
|
|
3
4
|
function safeJsonParse(content) {
|
|
4
5
|
try {
|
|
@@ -44,6 +45,61 @@ class OpenAIVisionPlugin extends OpenAIChatPlugin {
|
|
|
44
45
|
});
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
// Override the logging function to display the messages and responses
|
|
49
|
+
logRequestData(data, responseData, prompt) {
|
|
50
|
+
const { stream, messages } = data;
|
|
51
|
+
if (messages && messages.length > 1) {
|
|
52
|
+
logger.info(`[chat request sent containing ${messages.length} messages]`);
|
|
53
|
+
let totalLength = 0;
|
|
54
|
+
let totalUnits;
|
|
55
|
+
messages.forEach((message, index) => {
|
|
56
|
+
//message.content string or array
|
|
57
|
+
const content = message.content === undefined ? JSON.stringify(message) : (Array.isArray(message.content) ? message.content.map(item => {
|
|
58
|
+
if (item.type === 'image_url' && item.image_url?.url?.startsWith('data:')) {
|
|
59
|
+
return JSON.stringify({
|
|
60
|
+
type: 'image_url',
|
|
61
|
+
image_url: { url: '* base64 data truncated for log *' }
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return JSON.stringify(item);
|
|
65
|
+
}).join(', ') : message.content);
|
|
66
|
+
const { length, units } = this.getLength(content);
|
|
67
|
+
const displayContent = this.shortenContent(content);
|
|
68
|
+
|
|
69
|
+
logger.verbose(`message ${index + 1}: role: ${message.role}, ${units}: ${length}, content: "${displayContent}"`);
|
|
70
|
+
totalLength += length;
|
|
71
|
+
totalUnits = units;
|
|
72
|
+
});
|
|
73
|
+
logger.info(`[chat request contained ${totalLength} ${totalUnits}]`);
|
|
74
|
+
} else {
|
|
75
|
+
const message = messages[0];
|
|
76
|
+
const content = Array.isArray(message.content) ? message.content.map(item => {
|
|
77
|
+
if (item.type === 'image_url' && item.image_url?.url?.startsWith('data:')) {
|
|
78
|
+
return JSON.stringify({
|
|
79
|
+
type: 'image_url',
|
|
80
|
+
image_url: { url: '* base64 data truncated for log *' }
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return JSON.stringify(item);
|
|
84
|
+
}).join(', ') : message.content;
|
|
85
|
+
const { length, units } = this.getLength(content);
|
|
86
|
+
logger.info(`[request sent containing ${length} ${units}]`);
|
|
87
|
+
logger.verbose(`${this.shortenContent(content)}`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (stream) {
|
|
91
|
+
logger.info(`[response received as an SSE stream]`);
|
|
92
|
+
} else {
|
|
93
|
+
const responseText = this.parseResponse(responseData);
|
|
94
|
+
const { length, units } = this.getLength(responseText);
|
|
95
|
+
logger.info(`[response received containing ${length} ${units}]`);
|
|
96
|
+
logger.verbose(`${this.shortenContent(responseText)}`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
prompt && prompt.debugInfo && (prompt.debugInfo += `\n${JSON.stringify(data)}`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
47
103
|
getRequestParameters(text, parameters, prompt) {
|
|
48
104
|
const requestParameters = super.getRequestParameters(text, parameters, prompt);
|
|
49
105
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import test from 'ava';
|
|
2
|
-
import { enforceTokenLimit } from '../pathways/system/entity/memory/sys_memory_update.js';
|
|
2
|
+
import { enforceTokenLimit, modifyText } from '../pathways/system/entity/memory/sys_memory_update.js';
|
|
3
3
|
|
|
4
4
|
test('enforceTokenLimit preserves priority order correctly', t => {
|
|
5
5
|
const input = `
|
|
@@ -61,4 +61,76 @@ Item without priority
|
|
|
61
61
|
|
|
62
62
|
t.true(result.includes('[P3] Item without priority'));
|
|
63
63
|
t.true(result.includes('[P1] Item with priority'));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('modifyText handles delete operations with escaped characters', t => {
|
|
67
|
+
const input = '[P2] Pizza Connection: Has special appreciation for Pisanello\'s';
|
|
68
|
+
const modifications = [{
|
|
69
|
+
type: 'delete',
|
|
70
|
+
pattern: '\\[P2\\] Pizza Connection: Has special appreciation for Pisanello\'s'
|
|
71
|
+
}];
|
|
72
|
+
|
|
73
|
+
const result = modifyText(input, modifications);
|
|
74
|
+
t.false(result.includes('Pizza Connection'));
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('modifyText handles delete with partial priority match', t => {
|
|
78
|
+
const input = '[P3] Test memory item';
|
|
79
|
+
const modifications = [{
|
|
80
|
+
type: 'delete',
|
|
81
|
+
pattern: 'Test memory item'
|
|
82
|
+
}];
|
|
83
|
+
|
|
84
|
+
const result = modifyText(input, modifications);
|
|
85
|
+
t.false(result.includes('Test memory item'));
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('modifyText handles multiple modifications in sequence', t => {
|
|
89
|
+
const input = '[P2] Keep this line\n[P3] Delete this line\n[P1] Also keep this';
|
|
90
|
+
const modifications = [
|
|
91
|
+
{ type: 'delete', pattern: 'Delete this line' },
|
|
92
|
+
{ type: 'add', newtext: 'New line added', priority: '2' }
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const result = modifyText(input, modifications);
|
|
96
|
+
t.true(result.includes('Keep this line'));
|
|
97
|
+
t.true(result.includes('Also keep this'));
|
|
98
|
+
t.true(result.includes('[P2] New line added'));
|
|
99
|
+
t.false(result.includes('Delete this line'));
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test('modifyText handles delete with whitespace variations', t => {
|
|
103
|
+
const input = ' [P2] Item with spaces \n[P3]Item without spaces';
|
|
104
|
+
const modifications = [
|
|
105
|
+
{ type: 'delete', pattern: 'Item with spaces' },
|
|
106
|
+
{ type: 'delete', pattern: 'Item without spaces' }
|
|
107
|
+
];
|
|
108
|
+
|
|
109
|
+
const result = modifyText(input, modifications);
|
|
110
|
+
t.false(result.includes('Item with spaces'));
|
|
111
|
+
t.false(result.includes('Item without spaces'));
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test('modifyText preserves existing priority when adding with priority in text', t => {
|
|
115
|
+
const input = '';
|
|
116
|
+
const modifications = [{
|
|
117
|
+
type: 'add',
|
|
118
|
+
newtext: '[P1] High priority item',
|
|
119
|
+
priority: '3' // This should be ignored since priority is in text
|
|
120
|
+
}];
|
|
121
|
+
|
|
122
|
+
const result = modifyText(input, modifications);
|
|
123
|
+
t.true(result.includes('[P1] High priority item'));
|
|
124
|
+
t.false(result.includes('[P3] [P1] High priority item'));
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('modifyText handles delete with regex special characters', t => {
|
|
128
|
+
const input = '[P2] Special (chars) [test] {here} *star*';
|
|
129
|
+
const modifications = [{
|
|
130
|
+
type: 'delete',
|
|
131
|
+
pattern: 'Special \\(chars\\) \\[test\\] \\{here\\} \\*star\\*'
|
|
132
|
+
}];
|
|
133
|
+
|
|
134
|
+
const result = modifyText(input, modifications);
|
|
135
|
+
t.false(result.includes('Special (chars)'));
|
|
64
136
|
});
|