@aj-archipelago/cortex 1.3.4 → 1.3.6
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 +90 -20
- 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 +769 -0
- package/helper-apps/cortex-realtime-voice-server/src/Tools.ts +546 -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 +89 -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 +94 -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 +484 -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 +43 -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 +1 -1
- package/pathways/system/entity/sys_entity_continue.js +2 -1
- package/pathways/system/entity/sys_entity_start.js +13 -2
- package/pathways/system/entity/sys_generator_ack.js +2 -2
- 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_quick.js +22 -7
- package/pathways/system/entity/sys_generator_reasoning.js +1 -1
- package/pathways/system/entity/sys_generator_results.js +20 -16
- package/pathways/system/entity/sys_generator_voice_filler.js +1 -1
- 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
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Prompt } from '../../../server/prompt.js';
|
|
2
|
+
import entityConstants from './shared/sys_entity_constants.js';
|
|
3
|
+
export default {
|
|
4
|
+
prompt:
|
|
5
|
+
[
|
|
6
|
+
new Prompt({ messages: [
|
|
7
|
+
{"role": "system", "content": `{{renderTemplate AI_MEMORY}}\n\n{{renderTemplate AI_COMMON_INSTRUCTIONS}}\n{{renderTemplate AI_EXPERTISE}}\n{{renderTemplate AI_MEMORY_INSTRUCTIONS}}\n{{renderTemplate AI_DATETIME}}\nYour voice communication system needs some examples to train it to sound like you. Based on your perception of yourself from your memories and your unique voice, generate some sample dialogue for your voice communication system to use as a reference for your style and tone. It can be anything, but make sure to overindex on your personality and voice for good training data. Make sure to reference a greeting and a closing statement. Put it between <EXAMPLE_DIALOGUE> tags and don't generate any other commentary outside of the tags.`},
|
|
8
|
+
{"role": "user", "content": `Generate a sample dialogue for your voice communication system to use as a reference for your style and tone.`},
|
|
9
|
+
]}),
|
|
10
|
+
],
|
|
11
|
+
inputParameters: {
|
|
12
|
+
chatHistory: [{role: '', content: []}],
|
|
13
|
+
contextId: ``,
|
|
14
|
+
aiName: "Jarvis",
|
|
15
|
+
language: "English",
|
|
16
|
+
aiStyle: "OpenAI",
|
|
17
|
+
},
|
|
18
|
+
useInputChunking: false,
|
|
19
|
+
enableDuplicateRequests: false,
|
|
20
|
+
executePathway: async ({args, runAllPrompts, resolver}) => {
|
|
21
|
+
|
|
22
|
+
args = {
|
|
23
|
+
...args,
|
|
24
|
+
...entityConstants
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const pathwayResolver = resolver;
|
|
28
|
+
const { anthropicModel, openAIModel } = pathwayResolver.pathway;
|
|
29
|
+
|
|
30
|
+
const styleModel = args.aiStyle === "Anthropic" ? anthropicModel : openAIModel;
|
|
31
|
+
|
|
32
|
+
const result = await runAllPrompts({ ...args, model: styleModel, stream: false });
|
|
33
|
+
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -19,25 +19,27 @@ Available tools and their specific use cases:
|
|
|
19
19
|
|
|
20
20
|
1. Search: Use for current events, news, fact-checking, and information requiring citation. This tool can search the internet, all Al Jazeera news articles and the latest news wires from multiple sources. Only search when necessary for current events, user documents, latest news, or complex topics needing grounding. Don't search for remembered information or general knowledge within your capabilities.
|
|
21
21
|
|
|
22
|
-
2. Document: Access user's personal document index. Use for user-specific uploaded information. If user refers vaguely to "this document/file/article" without context, search the personal index.
|
|
22
|
+
2. Document: Access user's personal document index. Use for user-specific uploaded information. If user refers vaguely to "this document/file/article" without context, use this tool to search the personal index.
|
|
23
23
|
|
|
24
|
-
3.
|
|
24
|
+
3. Memory: Access to your memory index. Use to recall any information that you may have stored in your memory that you don't currently see elsewhere in your context.
|
|
25
25
|
|
|
26
|
-
4.
|
|
26
|
+
4. Write: Engage for any task related to composing, editing, or refining written content. This includes articles, essays, scripts, or any form of textual creation or modification. If you need to search for information or look at a document first, use the Search or Document tools. This tool is just to create or modify content.
|
|
27
27
|
|
|
28
|
-
5.
|
|
28
|
+
5. Image: Use when asked to create, generate, or revise visual content. This covers photographs, illustrations, diagrams, or any other type of image. This tool only creates images - it cannot manipulate images (e.g. it cannot crop, rotate, or resize an existing image) - for those tasks you will need to use the CodeExecution tool.
|
|
29
29
|
|
|
30
|
-
6.
|
|
30
|
+
6. Code: Engage for any programming-related tasks, including creating, modifying, reviewing, or explaining code. Use for general coding discussions or when specific programming expertise is needed.
|
|
31
31
|
|
|
32
|
-
7.
|
|
32
|
+
7. CodeExecution: Use when explicitly asked to run or execute code, or when a coding agent is needed to perform specific tasks that require code execution like data analysis, data processing, image processing, or business intelligence tasks.
|
|
33
33
|
|
|
34
|
-
8.
|
|
34
|
+
8. Reason: Employ for reasoning, scientific analysis, evaluating evidence, strategic planning, problem-solving, logic puzzles, mathematical calculations, or any questions that require careful thought or complex choices. Also use when deep, step-by-step reasoning is required.
|
|
35
35
|
|
|
36
|
-
9.
|
|
36
|
+
9. PDF: Use specifically for processing and answering questions about PDF file content.
|
|
37
37
|
|
|
38
|
-
10.
|
|
38
|
+
10. Vision: Engage for analyzing and responding to queries about image files (jpg, gif, bmp, png, etc).
|
|
39
39
|
|
|
40
|
-
11.
|
|
40
|
+
11. Video: Use for processing and answering questions about video or audio file content.
|
|
41
|
+
|
|
42
|
+
12. Clarify: Use when you must have more information from the user to determine which tool to use. In this case your tool message should be one or more questions to the user to clarify their request.
|
|
41
43
|
|
|
42
44
|
Tool Selection Guidelines:
|
|
43
45
|
- Prioritize the most specific tool for the task at hand.
|
|
@@ -54,6 +56,7 @@ toolMessage Guidelines:
|
|
|
54
56
|
- The message is a filler message to the user to let them know you're working on their request.
|
|
55
57
|
- The message should be consistent in style and tone with the rest of your responses in the conversation history.
|
|
56
58
|
- The message should be brief and conversational and flow naturally with the conversation history.
|
|
59
|
+
- The message should not refer to the tool directly, but rather what you're trying to accomplish. E.g. for the memory tool, the message would be something like "Let me think about that for a moment..." or "I'm trying to remember...", etc.
|
|
57
60
|
|
|
58
61
|
If no tool is required, return:
|
|
59
62
|
{"toolRequired": false, "toolReason": "explanation of why no tool was necessary"}
|
|
@@ -4,7 +4,7 @@ export default {
|
|
|
4
4
|
prompt: [
|
|
5
5
|
new Prompt({
|
|
6
6
|
messages: [
|
|
7
|
-
{ "role": "system", "content": "Assistant is a list parsing AI. When user posts text including a numbered list and a desired set of fields, assistant will carefully read the list and attempt to convert
|
|
7
|
+
{ "role": "system", "content": "Assistant is a list parsing AI. When user posts text including a numbered list and a desired set of fields, assistant will carefully read the list and attempt to convert each list item into a JSON object with the given fields. If a field value is numeric, it should be returned as a number in the JSON object. If there are extra fields, assistant will ignore them. If a list item doesn't contain all fields, assistant will return the fields that are present and skip the missing fields. If the conversion is not at all possible, assistant will return an empty JSON array. Assistant will generate only the repaired JSON object in a directly parseable format with no markdown surrounding it and no other response or commentary." },
|
|
8
8
|
{ "role": "user", "content": `Fields: {{{format}}}\nList: {{{text}}}`},
|
|
9
9
|
]
|
|
10
10
|
})
|
|
@@ -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 && getv(contextId)) || {},
|
|
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
|
});
|