@aj-archipelago/cortex 1.4.24 → 1.4.25
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/package.json +1 -1
- package/pathways/system/entity/memory/sys_memory_manager.js +4 -0
- package/pathways/system/entity/sys_entity_agent.js +8 -5
- package/pathways/system/entity/tools/sys_tool_store_memory.js +1 -2
- package/server/pathwayResolver.js +33 -25
- package/server/plugins/claude3VertexPlugin.js +19 -6
- package/server/plugins/claude4VertexPlugin.js +26 -16
- package/server/plugins/grokResponsesPlugin.js +22 -2
- package/server/plugins/grokVisionPlugin.js +22 -2
- package/server/plugins/openAiVisionPlugin.js +22 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aj-archipelago/cortex",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.25",
|
|
4
4
|
"description": "Cortex is a GraphQL API for AI. It provides a simple, extensible interface for using AI services from OpenAI, Azure and others.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -26,6 +26,10 @@ export default {
|
|
|
26
26
|
timeout: 300,
|
|
27
27
|
executePathway: async ({args, resolver}) => {
|
|
28
28
|
try {
|
|
29
|
+
// Skip if memory is disabled
|
|
30
|
+
if (args.useMemory === false) {
|
|
31
|
+
return "";
|
|
32
|
+
}
|
|
29
33
|
|
|
30
34
|
args = { ...args, ...config.get('entityConstants') };
|
|
31
35
|
let parsedMemory;
|
|
@@ -452,7 +452,11 @@ export default {
|
|
|
452
452
|
|
|
453
453
|
const entityConfig = loadEntityConfig(entityId);
|
|
454
454
|
const { entityTools, entityToolsOpenAiFormat } = getToolsForEntity(entityConfig);
|
|
455
|
-
const {
|
|
455
|
+
const { name: entityName, instructions: entityInstructions } = entityConfig || {};
|
|
456
|
+
|
|
457
|
+
// Determine useMemory: entityConfig.useMemory === false is a hard disable (entity can't use memory)
|
|
458
|
+
// Otherwise args.useMemory can disable it, default true
|
|
459
|
+
args.useMemory = entityConfig?.useMemory === false ? false : (args.useMemory ?? true);
|
|
456
460
|
|
|
457
461
|
// Initialize chat history if needed
|
|
458
462
|
if (!args.chatHistory || args.chatHistory.length === 0) {
|
|
@@ -488,7 +492,7 @@ export default {
|
|
|
488
492
|
|
|
489
493
|
// Kick off the memory lookup required pathway in parallel - this takes like 500ms so we want to start it early
|
|
490
494
|
let memoryLookupRequiredPromise = null;
|
|
491
|
-
if (
|
|
495
|
+
if (args.useMemory) {
|
|
492
496
|
const chatHistoryLastTurn = args.chatHistory.slice(-2);
|
|
493
497
|
const chatHistorySizeOk = (JSON.stringify(chatHistoryLastTurn).length < 5000);
|
|
494
498
|
if (chatHistorySizeOk) {
|
|
@@ -512,7 +516,6 @@ export default {
|
|
|
512
516
|
entityId,
|
|
513
517
|
entityTools,
|
|
514
518
|
entityToolsOpenAiFormat,
|
|
515
|
-
entityUseMemory,
|
|
516
519
|
entityInstructions,
|
|
517
520
|
voiceResponse,
|
|
518
521
|
aiMemorySelfModify,
|
|
@@ -524,7 +527,7 @@ export default {
|
|
|
524
527
|
|
|
525
528
|
const promptPrefix = '';
|
|
526
529
|
|
|
527
|
-
const memoryTemplates =
|
|
530
|
+
const memoryTemplates = args.useMemory ?
|
|
528
531
|
`{{renderTemplate AI_MEMORY_INSTRUCTIONS}}\n\n{{renderTemplate AI_MEMORY}}\n\n{{renderTemplate AI_MEMORY_CONTEXT}}\n\n` : '';
|
|
529
532
|
|
|
530
533
|
const instructionTemplates = entityInstructions ? (entityInstructions + '\n\n') : `{{renderTemplate AI_COMMON_INSTRUCTIONS}}\n\n{{renderTemplate AI_EXPERTISE}}\n\n`;
|
|
@@ -560,7 +563,7 @@ export default {
|
|
|
560
563
|
const truncatedChatHistory = resolver.modelExecutor.plugin.truncateMessagesToTargetLength(args.chatHistory, null, 1000);
|
|
561
564
|
|
|
562
565
|
// Asynchronously manage memory for this context
|
|
563
|
-
if (args.aiMemorySelfModify &&
|
|
566
|
+
if (args.aiMemorySelfModify && args.useMemory) {
|
|
564
567
|
callPathway('sys_memory_manager', { ...args, chatHistory: truncatedChatHistory, stream: false })
|
|
565
568
|
.catch(error => logger.error(error?.message || "Error in sys_memory_manager pathway"));
|
|
566
569
|
}
|
|
@@ -52,8 +52,7 @@ export default {
|
|
|
52
52
|
|
|
53
53
|
executePathway: async ({args, runAllPrompts, resolver}) => {
|
|
54
54
|
// Check if memory is enabled for this entity
|
|
55
|
-
|
|
56
|
-
if (useMemory === false) {
|
|
55
|
+
if (args.useMemory === false) {
|
|
57
56
|
return JSON.stringify({
|
|
58
57
|
error: 'Memory storage is disabled for this entity. Cannot store memories when useMemory is false.'
|
|
59
58
|
});
|
|
@@ -404,38 +404,45 @@ class PathwayResolver {
|
|
|
404
404
|
}
|
|
405
405
|
|
|
406
406
|
// Get saved context from contextId or change contextId if needed
|
|
407
|
-
const { contextId } = args;
|
|
407
|
+
const { contextId, useMemory } = args;
|
|
408
408
|
this.savedContextId = contextId ? contextId : uuidv4();
|
|
409
409
|
|
|
410
|
+
// Check if memory is enabled (default true for backward compatibility)
|
|
411
|
+
const memoryEnabled = useMemory !== false;
|
|
412
|
+
|
|
410
413
|
const loadMemory = async () => {
|
|
411
414
|
try {
|
|
412
|
-
//
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
415
|
+
// Always load savedContext (legacy feature)
|
|
416
|
+
this.savedContext = (getvWithDoubleDecryption && await getvWithDoubleDecryption(this.savedContextId, this.args?.contextKey)) || {};
|
|
417
|
+
this.initialState = { savedContext: this.savedContext };
|
|
418
|
+
|
|
419
|
+
// Only load memory* sections if memory is enabled
|
|
420
|
+
if (memoryEnabled) {
|
|
421
|
+
const [memorySelf, memoryDirectives, memoryTopics, memoryUser, memoryContext] = await Promise.all([
|
|
422
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memorySelf', priority: 1, stripMetadata: true, contextKey: this.args?.contextKey }),
|
|
423
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memoryDirectives', priority: 1, stripMetadata: true, contextKey: this.args?.contextKey }),
|
|
424
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memoryTopics', priority: 0, numResults: 10, contextKey: this.args?.contextKey }),
|
|
425
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memoryUser', priority: 1, stripMetadata: true, contextKey: this.args?.contextKey }),
|
|
426
|
+
callPathway('sys_read_memory', { contextId: this.savedContextId, section: 'memoryContext', priority: 0, contextKey: this.args?.contextKey }),
|
|
427
|
+
]).catch(error => {
|
|
428
|
+
this.logError(`Failed to load memory: ${error.message}`);
|
|
429
|
+
return ['','','','',''];
|
|
430
|
+
});
|
|
424
431
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
432
|
+
this.memorySelf = memorySelf || '';
|
|
433
|
+
this.memoryDirectives = memoryDirectives || '';
|
|
434
|
+
this.memoryTopics = memoryTopics || '';
|
|
435
|
+
this.memoryUser = memoryUser || '';
|
|
436
|
+
this.memoryContext = memoryContext || '';
|
|
437
|
+
} else {
|
|
438
|
+
this.memorySelf = '';
|
|
439
|
+
this.memoryDirectives = '';
|
|
440
|
+
this.memoryTopics = '';
|
|
441
|
+
this.memoryUser = '';
|
|
442
|
+
this.memoryContext = '';
|
|
443
|
+
}
|
|
436
444
|
} catch (error) {
|
|
437
445
|
this.logError(`Error in loadMemory: ${error.message}`);
|
|
438
|
-
// Set default values in case of error
|
|
439
446
|
this.savedContext = {};
|
|
440
447
|
this.memorySelf = '';
|
|
441
448
|
this.memoryDirectives = '';
|
|
@@ -447,6 +454,7 @@ class PathwayResolver {
|
|
|
447
454
|
};
|
|
448
455
|
|
|
449
456
|
const saveChangedMemory = async () => {
|
|
457
|
+
// Always save savedContext (legacy feature, not governed by useMemory)
|
|
450
458
|
this.savedContextId = this.savedContextId || uuidv4();
|
|
451
459
|
|
|
452
460
|
const currentState = {
|
|
@@ -576,9 +576,16 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
|
|
|
576
576
|
let totalLength = 0;
|
|
577
577
|
let totalUnits;
|
|
578
578
|
messages.forEach((message, index) => {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
579
|
+
let content;
|
|
580
|
+
if (Array.isArray(message.content)) {
|
|
581
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
582
|
+
content = message.content.map((item) => {
|
|
583
|
+
const sanitized = sanitizeBase64(item);
|
|
584
|
+
return typeof sanitized === 'string' ? sanitized : JSON.stringify(sanitized);
|
|
585
|
+
}).join(", ");
|
|
586
|
+
} else {
|
|
587
|
+
content = message.content;
|
|
588
|
+
}
|
|
582
589
|
const { length, units } = this.getLength(content);
|
|
583
590
|
const preview = this.shortenContent(content);
|
|
584
591
|
|
|
@@ -593,9 +600,15 @@ class Claude3VertexPlugin extends OpenAIVisionPlugin {
|
|
|
593
600
|
logger.info(`[chat request contained ${totalLength} ${totalUnits}]`);
|
|
594
601
|
} else {
|
|
595
602
|
const message = messages[0];
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
603
|
+
let content;
|
|
604
|
+
if (Array.isArray(message.content)) {
|
|
605
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
606
|
+
content = message.content.map((item) => {
|
|
607
|
+
return typeof item === 'string' ? item : JSON.stringify(item);
|
|
608
|
+
}).join(", ");
|
|
609
|
+
} else {
|
|
610
|
+
content = message.content;
|
|
611
|
+
}
|
|
599
612
|
const { length, units } = this.getLength(content);
|
|
600
613
|
logger.info(`[request sent containing ${length} ${units}]`);
|
|
601
614
|
logger.verbose(`${this.shortenContent(content)}`);
|
|
@@ -474,14 +474,19 @@ class Claude4VertexPlugin extends Claude3VertexPlugin {
|
|
|
474
474
|
let totalLength = 0;
|
|
475
475
|
let totalUnits;
|
|
476
476
|
messages.forEach((message, index) => {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
return JSON.stringify(sanitizeBase64(item))
|
|
483
|
-
}
|
|
484
|
-
|
|
477
|
+
let content;
|
|
478
|
+
if (Array.isArray(message.content)) {
|
|
479
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
480
|
+
content = message.content.map((item) => {
|
|
481
|
+
if (item.type === 'document') {
|
|
482
|
+
return `{type: document, source: ${JSON.stringify(sanitizeBase64(item.source))}}`;
|
|
483
|
+
}
|
|
484
|
+
const sanitized = sanitizeBase64(item);
|
|
485
|
+
return typeof sanitized === 'string' ? sanitized : JSON.stringify(sanitized);
|
|
486
|
+
}).join(", ");
|
|
487
|
+
} else {
|
|
488
|
+
content = message.content;
|
|
489
|
+
}
|
|
485
490
|
const { length, units } = this.getLength(content);
|
|
486
491
|
const preview = this.shortenContent(content);
|
|
487
492
|
|
|
@@ -496,14 +501,19 @@ class Claude4VertexPlugin extends Claude3VertexPlugin {
|
|
|
496
501
|
logger.info(`[chat request contained ${totalLength} ${totalUnits}]`);
|
|
497
502
|
} else {
|
|
498
503
|
const message = messages[0];
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
return JSON.stringify(sanitizeBase64(item))
|
|
505
|
-
}
|
|
506
|
-
|
|
504
|
+
let content;
|
|
505
|
+
if (Array.isArray(message.content)) {
|
|
506
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
507
|
+
content = message.content.map((item) => {
|
|
508
|
+
if (item.type === 'document') {
|
|
509
|
+
return `{type: document, source: ${JSON.stringify(sanitizeBase64(item.source))}}`;
|
|
510
|
+
}
|
|
511
|
+
const sanitized = sanitizeBase64(item);
|
|
512
|
+
return typeof sanitized === 'string' ? sanitized : JSON.stringify(sanitized);
|
|
513
|
+
}).join(", ");
|
|
514
|
+
} else {
|
|
515
|
+
content = message.content;
|
|
516
|
+
}
|
|
507
517
|
const { length, units } = this.getLength(content);
|
|
508
518
|
logger.info(`[request sent containing ${length} ${units}]`);
|
|
509
519
|
logger.verbose(`${this.shortenContent(content)}`);
|
|
@@ -37,7 +37,18 @@ class GrokResponsesPlugin extends OpenAIVisionPlugin {
|
|
|
37
37
|
let totalLength = 0;
|
|
38
38
|
let totalUnits;
|
|
39
39
|
messages.forEach((message, index) => {
|
|
40
|
-
|
|
40
|
+
let content;
|
|
41
|
+
if (message.content === undefined) {
|
|
42
|
+
content = JSON.stringify(sanitizeBase64(message));
|
|
43
|
+
} else if (Array.isArray(message.content)) {
|
|
44
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
45
|
+
content = message.content.map(item => {
|
|
46
|
+
const sanitized = sanitizeBase64(item);
|
|
47
|
+
return typeof sanitized === 'string' ? sanitized : JSON.stringify(sanitized);
|
|
48
|
+
}).join(', ');
|
|
49
|
+
} else {
|
|
50
|
+
content = message.content;
|
|
51
|
+
}
|
|
41
52
|
const { length, units } = this.getLength(content);
|
|
42
53
|
const displayContent = this.shortenContent(content);
|
|
43
54
|
|
|
@@ -54,7 +65,16 @@ class GrokResponsesPlugin extends OpenAIVisionPlugin {
|
|
|
54
65
|
logger.info(`[grok responses request contained ${totalLength} ${totalUnits}]`);
|
|
55
66
|
} else if (messages && messages.length === 1) {
|
|
56
67
|
const message = messages[0];
|
|
57
|
-
|
|
68
|
+
let content;
|
|
69
|
+
if (Array.isArray(message.content)) {
|
|
70
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
71
|
+
content = message.content.map(item => {
|
|
72
|
+
const sanitized = sanitizeBase64(item);
|
|
73
|
+
return typeof sanitized === 'string' ? sanitized : JSON.stringify(sanitized);
|
|
74
|
+
}).join(', ');
|
|
75
|
+
} else {
|
|
76
|
+
content = message.content;
|
|
77
|
+
}
|
|
58
78
|
const { length, units } = this.getLength(content);
|
|
59
79
|
logger.info(`[grok responses request sent containing ${length} ${units}]`);
|
|
60
80
|
logger.verbose(`${this.shortenContent(content)}`);
|
|
@@ -29,7 +29,18 @@ class GrokVisionPlugin extends OpenAIVisionPlugin {
|
|
|
29
29
|
let totalUnits;
|
|
30
30
|
messages.forEach((message, index) => {
|
|
31
31
|
//message.content string or array
|
|
32
|
-
|
|
32
|
+
let content;
|
|
33
|
+
if (message.content === undefined) {
|
|
34
|
+
content = JSON.stringify(sanitizeBase64(message));
|
|
35
|
+
} else if (Array.isArray(message.content)) {
|
|
36
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
37
|
+
content = message.content.map(item => {
|
|
38
|
+
const sanitized = sanitizeBase64(item);
|
|
39
|
+
return typeof sanitized === 'string' ? sanitized : JSON.stringify(sanitized);
|
|
40
|
+
}).join(', ');
|
|
41
|
+
} else {
|
|
42
|
+
content = message.content;
|
|
43
|
+
}
|
|
33
44
|
const { length, units } = this.getLength(content);
|
|
34
45
|
const displayContent = this.shortenContent(content);
|
|
35
46
|
|
|
@@ -47,7 +58,16 @@ class GrokVisionPlugin extends OpenAIVisionPlugin {
|
|
|
47
58
|
logger.info(`[grok request contained ${totalLength} ${totalUnits}]`);
|
|
48
59
|
} else {
|
|
49
60
|
const message = messages[0];
|
|
50
|
-
|
|
61
|
+
let content;
|
|
62
|
+
if (Array.isArray(message.content)) {
|
|
63
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
64
|
+
content = message.content.map(item => {
|
|
65
|
+
const sanitized = sanitizeBase64(item);
|
|
66
|
+
return typeof sanitized === 'string' ? sanitized : JSON.stringify(sanitized);
|
|
67
|
+
}).join(', ');
|
|
68
|
+
} else {
|
|
69
|
+
content = message.content;
|
|
70
|
+
}
|
|
51
71
|
const { length, units } = this.getLength(content);
|
|
52
72
|
logger.info(`[grok request sent containing ${length} ${units}]`);
|
|
53
73
|
logger.verbose(`${this.shortenContent(content)}`);
|
|
@@ -159,7 +159,18 @@ class OpenAIVisionPlugin extends OpenAIChatPlugin {
|
|
|
159
159
|
let totalUnits;
|
|
160
160
|
messages.forEach((message, index) => {
|
|
161
161
|
//message.content string or array
|
|
162
|
-
|
|
162
|
+
let content;
|
|
163
|
+
if (message.content === undefined) {
|
|
164
|
+
content = JSON.stringify(sanitizeBase64(message));
|
|
165
|
+
} else if (Array.isArray(message.content)) {
|
|
166
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
167
|
+
content = message.content.map(item => {
|
|
168
|
+
const sanitized = sanitizeBase64(item);
|
|
169
|
+
return typeof sanitized === 'string' ? sanitized : JSON.stringify(sanitized);
|
|
170
|
+
}).join(', ');
|
|
171
|
+
} else {
|
|
172
|
+
content = message.content;
|
|
173
|
+
}
|
|
163
174
|
const { length, units } = this.getLength(content);
|
|
164
175
|
const displayContent = this.shortenContent(content);
|
|
165
176
|
|
|
@@ -177,7 +188,16 @@ class OpenAIVisionPlugin extends OpenAIChatPlugin {
|
|
|
177
188
|
logger.info(`[chat request contained ${totalLength} ${totalUnits}]`);
|
|
178
189
|
} else {
|
|
179
190
|
const message = messages[0];
|
|
180
|
-
|
|
191
|
+
let content;
|
|
192
|
+
if (Array.isArray(message.content)) {
|
|
193
|
+
// Only stringify objects, not strings (which may already be JSON strings)
|
|
194
|
+
content = message.content.map(item => {
|
|
195
|
+
const sanitized = sanitizeBase64(item);
|
|
196
|
+
return typeof sanitized === 'string' ? sanitized : JSON.stringify(sanitized);
|
|
197
|
+
}).join(', ');
|
|
198
|
+
} else {
|
|
199
|
+
content = message.content;
|
|
200
|
+
}
|
|
181
201
|
const { length, units } = this.getLength(content);
|
|
182
202
|
logger.info(`[request sent containing ${length} ${units}]`);
|
|
183
203
|
logger.verbose(`${this.shortenContent(content)}`);
|