@aj-archipelago/cortex 1.3.32 → 1.3.34
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/OAI_CONFIG_LIST +1 -1
- package/lib/encodeCache.js +22 -10
- package/lib/pathwayTools.js +10 -3
- package/lib/requestExecutor.js +1 -1
- package/lib/util.js +136 -1
- package/package.json +2 -2
- package/pathways/system/entity/memory/sys_memory_manager.js +2 -1
- package/pathways/system/entity/sys_entity_continue.js +10 -2
- package/pathways/system/entity/sys_entity_start.js +12 -10
- package/pathways/system/entity/sys_router_tool.js +2 -2
- package/server/chunker.js +23 -3
- package/server/pathwayResolver.js +2 -5
- package/server/plugins/claude3VertexPlugin.js +2 -3
- package/server/plugins/cohereGeneratePlugin.js +1 -1
- package/server/plugins/gemini15ChatPlugin.js +1 -1
- package/server/plugins/geminiChatPlugin.js +1 -1
- package/server/plugins/localModelPlugin.js +1 -1
- package/server/plugins/modelPlugin.js +332 -77
- package/server/plugins/openAiChatPlugin.js +1 -1
- package/server/plugins/openAiCompletionPlugin.js +1 -1
- package/server/plugins/palmChatPlugin.js +1 -1
- package/server/plugins/palmCodeCompletionPlugin.js +1 -1
- package/server/plugins/palmCompletionPlugin.js +1 -1
- package/tests/chunkfunction.test.js +9 -6
- package/tests/claude3VertexPlugin.test.js +81 -3
- package/tests/data/largecontent.txt +1 -0
- package/tests/data/mixedcontent.txt +1 -0
- package/tests/encodeCache.test.js +47 -14
- package/tests/modelPlugin.test.js +21 -0
- package/tests/multimodal_conversion.test.js +1 -1
- package/tests/subscription.test.js +7 -1
- package/tests/tokenHandlingTests.test.js +587 -0
- package/tests/truncateMessages.test.js +404 -46
- package/tests/util.test.js +146 -0
|
@@ -2,7 +2,21 @@ import test from 'ava';
|
|
|
2
2
|
import { faker } from '@faker-js/faker';
|
|
3
3
|
import { performance } from 'perf_hooks';
|
|
4
4
|
import { encode, decode } from '../lib/encodeCache.js';
|
|
5
|
-
import {
|
|
5
|
+
import { encoding_for_model } from '@dqbd/tiktoken';
|
|
6
|
+
|
|
7
|
+
// Create reference encoder with same model as used in encodeCache
|
|
8
|
+
const encoder = encoding_for_model("gpt-4o");
|
|
9
|
+
|
|
10
|
+
// Helper to create a stable representation of token arrays for comparisons
|
|
11
|
+
const tokenArrayToString = arr => Array.from(arr).toString();
|
|
12
|
+
|
|
13
|
+
// Helper to normalize decoded content to string
|
|
14
|
+
const normalizeDecoded = decoded => {
|
|
15
|
+
if (decoded instanceof Uint8Array) {
|
|
16
|
+
return new TextDecoder().decode(decoded);
|
|
17
|
+
}
|
|
18
|
+
return decoded;
|
|
19
|
+
};
|
|
6
20
|
|
|
7
21
|
// Test the accuracy of the cached encoding and decoding
|
|
8
22
|
test('cached encode and decode are reversible', t => {
|
|
@@ -12,23 +26,29 @@ test('cached encode and decode are reversible', t => {
|
|
|
12
26
|
t.is(decoded, original);
|
|
13
27
|
})
|
|
14
28
|
|
|
15
|
-
// Test whether the cached encoding and decoding is identical to
|
|
29
|
+
// Test whether the cached encoding and decoding is identical to tiktoken
|
|
16
30
|
test('cached encode and decode are identical to noncached', t => {
|
|
17
31
|
const original = faker.lorem.paragraph(50);
|
|
18
32
|
const encoded = encode(original);
|
|
19
|
-
const
|
|
20
|
-
|
|
33
|
+
const tiktokenEncoded = encoder.encode(original);
|
|
34
|
+
|
|
35
|
+
// Compare arrays by converting to strings
|
|
36
|
+
t.is(tokenArrayToString(encoded), tokenArrayToString(tiktokenEncoded));
|
|
21
37
|
|
|
22
38
|
const decoded = decode(encoded);
|
|
23
|
-
const
|
|
24
|
-
|
|
39
|
+
const tiktokenDecoded = encoder.decode(tiktokenEncoded);
|
|
40
|
+
|
|
41
|
+
// Normalize tiktoken decoded output to string for comparison
|
|
42
|
+
const normalizedTiktokenDecoded = normalizeDecoded(tiktokenDecoded);
|
|
43
|
+
|
|
44
|
+
t.is(decoded, normalizedTiktokenDecoded);
|
|
25
45
|
})
|
|
26
46
|
|
|
27
47
|
// Test whether decoding adds the encoded value to the encode cache
|
|
28
48
|
// the only way to tell is if the encode is faster after the cached decode
|
|
29
49
|
test('decode operation adds to encode cache', t => {
|
|
30
50
|
const original = faker.lorem.paragraph(50);
|
|
31
|
-
const encodedOriginal =
|
|
51
|
+
const encodedOriginal = encoder.encode(original);
|
|
32
52
|
|
|
33
53
|
const startEncode = performance.now();
|
|
34
54
|
const encoded = encode(original);
|
|
@@ -36,39 +56,51 @@ test('decode operation adds to encode cache', t => {
|
|
|
36
56
|
const encodeTime = endEncode - startEncode;
|
|
37
57
|
console.log("pre-decode encode time", encodeTime);
|
|
38
58
|
|
|
39
|
-
|
|
59
|
+
// Compare arrays using our helper
|
|
60
|
+
t.is(tokenArrayToString(encoded), tokenArrayToString(encodedOriginal));
|
|
40
61
|
|
|
41
62
|
const original2 = faker.lorem.paragraph(50);
|
|
42
|
-
const encodedOriginal2 =
|
|
63
|
+
const encodedOriginal2 = encoder.encode(original2);
|
|
64
|
+
|
|
65
|
+
// Decode should add to cache
|
|
43
66
|
const decodedOriginal2 = decode(encodedOriginal2);
|
|
67
|
+
|
|
44
68
|
const startEncode2 = performance.now();
|
|
45
69
|
const encoded2 = encode(original2);
|
|
46
70
|
const endEncode2 = performance.now();
|
|
47
71
|
const encodeTime2 = endEncode2 - startEncode2;
|
|
48
72
|
console.log("post-decode encode time", encodeTime2);
|
|
49
73
|
|
|
50
|
-
t.
|
|
74
|
+
t.is(tokenArrayToString(encoded2), tokenArrayToString(encodedOriginal2));
|
|
75
|
+
|
|
76
|
+
// Allow some buffer for timing variations
|
|
51
77
|
t.true(encodeTime2 <= encodeTime);
|
|
52
78
|
})
|
|
53
79
|
|
|
54
|
-
|
|
55
80
|
// Test encode and decode caching
|
|
56
81
|
test('caching', t => {
|
|
57
82
|
const original = faker.lorem.paragraph(50);
|
|
83
|
+
|
|
84
|
+
// First encode should be uncached
|
|
58
85
|
const startEncode1 = performance.now();
|
|
59
86
|
const encoded1 = encode(original);
|
|
60
87
|
const endEncode1 = performance.now();
|
|
61
88
|
const encodeTime1 = endEncode1 - startEncode1;
|
|
62
89
|
|
|
63
90
|
const original2 = faker.lorem.paragraph(50);
|
|
64
|
-
const encodedOriginal2 =
|
|
91
|
+
const encodedOriginal2 = encoder.encode(original2);
|
|
92
|
+
|
|
93
|
+
// First decode should be uncached
|
|
65
94
|
const startDecode1 = performance.now();
|
|
66
95
|
const decoded1 = decode(encodedOriginal2);
|
|
67
96
|
const endDecode1 = performance.now();
|
|
68
97
|
const decodeTime1 = endDecode1 - startDecode1;
|
|
69
98
|
|
|
70
|
-
t.
|
|
71
|
-
|
|
99
|
+
t.is(tokenArrayToString(encoded1), tokenArrayToString(encoder.encode(original)));
|
|
100
|
+
|
|
101
|
+
// Compare with normalized tiktoken output
|
|
102
|
+
const normalizedOriginal2 = normalizeDecoded(encoder.decode(encodedOriginal2));
|
|
103
|
+
t.is(decoded1, normalizedOriginal2);
|
|
72
104
|
|
|
73
105
|
console.log('uncached encode time', encodeTime1);
|
|
74
106
|
console.log('uncached decode time', decodeTime1);
|
|
@@ -87,6 +119,7 @@ test('caching', t => {
|
|
|
87
119
|
console.log('cached encode time', encodeTime2);
|
|
88
120
|
console.log('cached decode time', decodeTime2);
|
|
89
121
|
|
|
122
|
+
// Allow some buffer for timing variations
|
|
90
123
|
t.true(encodeTime2 <= encodeTime1);
|
|
91
124
|
t.true(decodeTime2 <= decodeTime1);
|
|
92
125
|
});
|
|
@@ -71,6 +71,27 @@ test('getPromptTokenRatio', (t) => {
|
|
|
71
71
|
t.is(modelPlugin.getPromptTokenRatio(), DEFAULT_PROMPT_TOKEN_RATIO, 'getPromptTokenRatio should return default prompt token ratio');
|
|
72
72
|
});
|
|
73
73
|
|
|
74
|
+
test('getModelMaxPromptTokens', (t) => {
|
|
75
|
+
const { modelPlugin } = t.context;
|
|
76
|
+
|
|
77
|
+
// Default case - should use token ratio
|
|
78
|
+
t.is(
|
|
79
|
+
modelPlugin.getModelMaxPromptTokens(),
|
|
80
|
+
Math.floor(DEFAULT_MAX_TOKENS * DEFAULT_PROMPT_TOKEN_RATIO),
|
|
81
|
+
'Should return maxTokenLength * tokenRatio when maxReturnTokens is not defined'
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
// When maxReturnTokens is defined
|
|
85
|
+
const returnTokens = 256;
|
|
86
|
+
modelPlugin.promptParameters.maxReturnTokens = returnTokens;
|
|
87
|
+
|
|
88
|
+
t.is(
|
|
89
|
+
modelPlugin.getModelMaxPromptTokens(),
|
|
90
|
+
DEFAULT_MAX_TOKENS - returnTokens,
|
|
91
|
+
'Should return maxTokenLength - maxReturnTokens when maxReturnTokens is defined'
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
74
95
|
test('default parseResponse', (t) => {
|
|
75
96
|
const { modelPlugin } = t.context;
|
|
76
97
|
const multipleChoicesResponse = {
|
|
@@ -200,7 +200,7 @@ test('Unsupported mime type conversion', async (t) => {
|
|
|
200
200
|
const pdfMessage = [
|
|
201
201
|
{ role: 'user', content: [
|
|
202
202
|
{ type: 'text', text: 'Can you analyze this PDF?' },
|
|
203
|
-
{ type: 'image_url', image_url: { url: 'https://
|
|
203
|
+
{ type: 'image_url', image_url: { url: 'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf' } }
|
|
204
204
|
]}
|
|
205
205
|
];
|
|
206
206
|
|
|
@@ -162,13 +162,19 @@ function validateProgressMessage(t, progress, requestId = null) {
|
|
|
162
162
|
}
|
|
163
163
|
|
|
164
164
|
// Validate info field if present and not an error
|
|
165
|
-
if (progress.info
|
|
165
|
+
if (progress.info) {
|
|
166
166
|
t.true(typeof progress.info === 'string', 'Info field should be a string');
|
|
167
167
|
t.notThrows(() => {
|
|
168
168
|
const parsedInfo = JSON.parse(progress.info);
|
|
169
169
|
t.true(typeof parsedInfo === 'object', 'Info should be valid JSON object');
|
|
170
170
|
}, 'Info should be valid JSON');
|
|
171
171
|
}
|
|
172
|
+
|
|
173
|
+
// Validate error field if present
|
|
174
|
+
if (progress.error) {
|
|
175
|
+
t.true(typeof progress.error === 'string', 'Error field should be a string');
|
|
176
|
+
t.notThrows(() => JSON.parse(progress.error), 'Error should be valid JSON');
|
|
177
|
+
}
|
|
172
178
|
}
|
|
173
179
|
|
|
174
180
|
test.serial('Request progress messages have string data and info fields', async (t) => {
|