lynkr 8.0.0 → 9.0.1
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/.lynkr/telemetry.db +0 -0
- package/.lynkr/telemetry.db-shm +0 -0
- package/.lynkr/telemetry.db-wal +0 -0
- package/README.md +196 -322
- package/lynkr-skill.tar.gz +0 -0
- package/package.json +4 -3
- package/src/api/openai-router.js +64 -13
- package/src/api/providers-handler.js +171 -3
- package/src/api/router.js +9 -2
- package/src/clients/circuit-breaker.js +10 -247
- package/src/clients/codex-process.js +342 -0
- package/src/clients/codex-utils.js +143 -0
- package/src/clients/databricks.js +210 -63
- package/src/clients/resilience.js +540 -0
- package/src/clients/retry.js +22 -167
- package/src/clients/standard-tools.js +23 -0
- package/src/config/index.js +77 -0
- package/src/context/compression.js +42 -9
- package/src/context/distill.js +492 -0
- package/src/orchestrator/index.js +48 -8
- package/src/routing/complexity-analyzer.js +258 -5
- package/src/routing/index.js +12 -2
- package/src/routing/latency-tracker.js +148 -0
- package/src/routing/model-tiers.js +2 -0
- package/src/routing/quality-scorer.js +113 -0
- package/src/routing/telemetry.js +464 -0
- package/src/server.js +13 -12
- package/src/tools/code-graph.js +538 -0
- package/src/tools/code-mode.js +304 -0
- package/src/tools/index.js +4 -0
- package/src/tools/lazy-loader.js +18 -0
- package/src/tools/mcp-remote.js +7 -0
- package/src/tools/smart-selection.js +11 -0
- package/src/tools/tinyfish.js +358 -0
- package/src/tools/truncate.js +1 -0
- package/src/utils/payload.js +206 -0
- package/src/utils/perf-timer.js +80 -0
- package/.github/FUNDING.yml +0 -15
- package/.github/workflows/README.md +0 -215
- package/.github/workflows/ci.yml +0 -69
- package/.github/workflows/index.yml +0 -62
- package/.github/workflows/web-tools-tests.yml +0 -56
- package/CITATIONS.bib +0 -6
- package/DEPLOYMENT.md +0 -1001
- package/LYNKR-TUI-PLAN.md +0 -984
- package/PERFORMANCE-REPORT.md +0 -866
- package/PLAN-per-client-model-routing.md +0 -252
- package/docs/42642f749da6234f41b6b425c3bb07c9.txt +0 -1
- package/docs/BingSiteAuth.xml +0 -4
- package/docs/docs-style.css +0 -478
- package/docs/docs.html +0 -198
- package/docs/google5be250e608e6da39.html +0 -1
- package/docs/index.html +0 -577
- package/docs/index.md +0 -584
- package/docs/robots.txt +0 -4
- package/docs/sitemap.xml +0 -44
- package/docs/style.css +0 -1223
- package/docs/toon-integration-spec.md +0 -130
- package/documentation/README.md +0 -101
- package/documentation/api.md +0 -806
- package/documentation/claude-code-cli.md +0 -679
- package/documentation/codex-cli.md +0 -397
- package/documentation/contributing.md +0 -571
- package/documentation/cursor-integration.md +0 -734
- package/documentation/docker.md +0 -874
- package/documentation/embeddings.md +0 -762
- package/documentation/faq.md +0 -713
- package/documentation/features.md +0 -403
- package/documentation/headroom.md +0 -519
- package/documentation/installation.md +0 -758
- package/documentation/memory-system.md +0 -476
- package/documentation/production.md +0 -636
- package/documentation/providers.md +0 -1009
- package/documentation/routing.md +0 -476
- package/documentation/testing.md +0 -629
- package/documentation/token-optimization.md +0 -325
- package/documentation/tools.md +0 -697
- package/documentation/troubleshooting.md +0 -969
- package/final-test.js +0 -33
- package/headroom-sidecar/config.py +0 -93
- package/headroom-sidecar/requirements.txt +0 -14
- package/headroom-sidecar/server.py +0 -451
- package/monitor-agents.sh +0 -31
- package/scripts/audit-log-reader.js +0 -399
- package/scripts/compact-dictionary.js +0 -204
- package/scripts/test-deduplication.js +0 -448
- package/src/db/database.sqlite +0 -0
- package/te +0 -11622
- package/test/README.md +0 -212
- package/test/azure-openai-config.test.js +0 -213
- package/test/azure-openai-error-resilience.test.js +0 -238
- package/test/azure-openai-format-conversion.test.js +0 -354
- package/test/azure-openai-integration.test.js +0 -287
- package/test/azure-openai-routing.test.js +0 -175
- package/test/azure-openai-streaming.test.js +0 -171
- package/test/bedrock-integration.test.js +0 -457
- package/test/comprehensive-test-suite.js +0 -928
- package/test/config-validation.test.js +0 -207
- package/test/cursor-integration.test.js +0 -484
- package/test/format-conversion.test.js +0 -578
- package/test/hybrid-routing-integration.test.js +0 -269
- package/test/hybrid-routing-performance.test.js +0 -428
- package/test/llamacpp-integration.test.js +0 -882
- package/test/lmstudio-integration.test.js +0 -347
- package/test/memory/extractor.test.js +0 -398
- package/test/memory/retriever.test.js +0 -613
- package/test/memory/retriever.test.js.bak +0 -585
- package/test/memory/search.test.js +0 -537
- package/test/memory/search.test.js.bak +0 -389
- package/test/memory/store.test.js +0 -344
- package/test/memory/store.test.js.bak +0 -312
- package/test/memory/surprise.test.js +0 -300
- package/test/memory-performance.test.js +0 -472
- package/test/openai-integration.test.js +0 -683
- package/test/openrouter-error-resilience.test.js +0 -418
- package/test/passthrough-mode.test.js +0 -385
- package/test/performance-benchmark.js +0 -351
- package/test/performance-tests.js +0 -528
- package/test/routing.test.js +0 -225
- package/test/toon-compression.test.js +0 -131
- package/test/web-tools.test.js +0 -329
- package/test-agents-simple.js +0 -43
- package/test-cli-connection.sh +0 -33
- package/test-learning-unit.js +0 -126
- package/test-learning.js +0 -112
- package/test-parallel-agents.sh +0 -124
- package/test-parallel-direct.js +0 -155
- package/test-subagents.sh +0 -117
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Performance Tests for Titans-Inspired Long-Term Memory System
|
|
3
|
-
*
|
|
4
|
-
* Performance Targets:
|
|
5
|
-
* - Retrieval latency: <50ms for top 10 memories
|
|
6
|
-
* - Extraction latency: <100ms (async, non-blocking)
|
|
7
|
-
* - Memory overhead: <50MB for 10K memories
|
|
8
|
-
* - Database size: ~100 bytes per memory
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
const assert = require("assert");
|
|
12
|
-
const fs = require("fs");
|
|
13
|
-
const path = require("path");
|
|
14
|
-
|
|
15
|
-
// Test configuration
|
|
16
|
-
const PERFORMANCE_TARGETS = {
|
|
17
|
-
retrievalLatencyMs: 50,
|
|
18
|
-
extractionLatencyMs: 100,
|
|
19
|
-
storageLatencyMs: 10,
|
|
20
|
-
searchLatencyMs: 50,
|
|
21
|
-
memoryOverheadMb: 50,
|
|
22
|
-
bytesPerMemory: 200, // Conservative estimate
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const TEST_SIZES = {
|
|
26
|
-
small: 100,
|
|
27
|
-
medium: 1000,
|
|
28
|
-
large: 10000,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
console.log("=".repeat(80));
|
|
32
|
-
console.log("Memory System Performance Tests");
|
|
33
|
-
console.log("=".repeat(80));
|
|
34
|
-
console.log();
|
|
35
|
-
|
|
36
|
-
// Setup test environment
|
|
37
|
-
const testDbPath = path.join(__dirname, `../data/perf-test-${Date.now()}.db`);
|
|
38
|
-
process.env.DB_PATH = testDbPath;
|
|
39
|
-
process.env.MEMORY_ENABLED = "true";
|
|
40
|
-
process.env.MEMORY_SURPRISE_THRESHOLD = "0.3";
|
|
41
|
-
|
|
42
|
-
// Clear module cache
|
|
43
|
-
Object.keys(require.cache).forEach(key => {
|
|
44
|
-
if (key.includes('/src/')) {
|
|
45
|
-
delete require.cache[key];
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
// Initialize modules
|
|
50
|
-
const db = require("../src/db");
|
|
51
|
-
const store = require("../src/memory/store");
|
|
52
|
-
const search = require("../src/memory/search");
|
|
53
|
-
const retriever = require("../src/memory/retriever");
|
|
54
|
-
const surprise = require("../src/memory/surprise");
|
|
55
|
-
const extractor = require("../src/memory/extractor");
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Measure execution time
|
|
59
|
-
*/
|
|
60
|
-
function measureTime(fn) {
|
|
61
|
-
const start = process.hrtime.bigint();
|
|
62
|
-
const result = fn();
|
|
63
|
-
const end = process.hrtime.bigint();
|
|
64
|
-
const durationMs = Number(end - start) / 1_000_000;
|
|
65
|
-
return { result, durationMs };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Measure async execution time
|
|
70
|
-
*/
|
|
71
|
-
async function measureTimeAsync(fn) {
|
|
72
|
-
const start = process.hrtime.bigint();
|
|
73
|
-
const result = await fn();
|
|
74
|
-
const end = process.hrtime.bigint();
|
|
75
|
-
const durationMs = Number(end - start) / 1_000_000;
|
|
76
|
-
return { result, durationMs };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Create test memories
|
|
81
|
-
*/
|
|
82
|
-
function createTestMemories(count) {
|
|
83
|
-
const memories = [];
|
|
84
|
-
const types = ['preference', 'decision', 'fact', 'entity', 'relationship'];
|
|
85
|
-
const categories = ['user', 'code', 'project', 'general'];
|
|
86
|
-
|
|
87
|
-
console.log(`Creating ${count} test memories...`);
|
|
88
|
-
const start = Date.now();
|
|
89
|
-
|
|
90
|
-
for (let i = 0; i < count; i++) {
|
|
91
|
-
const type = types[i % types.length];
|
|
92
|
-
const category = categories[i % categories.length];
|
|
93
|
-
|
|
94
|
-
const memory = store.createMemory({
|
|
95
|
-
content: `Test memory ${i}: This is about ${type} in ${category} with various keywords like Python JavaScript TypeScript React Express`,
|
|
96
|
-
type,
|
|
97
|
-
category,
|
|
98
|
-
importance: Math.random(),
|
|
99
|
-
surpriseScore: Math.random(),
|
|
100
|
-
sessionId: null,
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
memories.push(memory);
|
|
104
|
-
|
|
105
|
-
if ((i + 1) % 1000 === 0) {
|
|
106
|
-
process.stdout.write(` Created ${i + 1}/${count}...\r`);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const duration = Date.now() - start;
|
|
111
|
-
console.log(` Created ${count} memories in ${duration}ms (${(duration/count).toFixed(2)}ms per memory)`);
|
|
112
|
-
console.log();
|
|
113
|
-
|
|
114
|
-
return memories;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Test 1: Memory Creation Performance
|
|
119
|
-
*/
|
|
120
|
-
function testCreationPerformance() {
|
|
121
|
-
console.log("Test 1: Memory Creation Performance");
|
|
122
|
-
console.log("-".repeat(60));
|
|
123
|
-
|
|
124
|
-
const { durationMs } = measureTime(() => {
|
|
125
|
-
return store.createMemory({
|
|
126
|
-
content: "User prefers Python for data processing with pandas and numpy libraries",
|
|
127
|
-
type: "preference",
|
|
128
|
-
category: "user",
|
|
129
|
-
importance: 0.8,
|
|
130
|
-
surpriseScore: 0.6,
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
console.log(` Single memory creation: ${durationMs.toFixed(2)}ms`);
|
|
135
|
-
|
|
136
|
-
if (durationMs < PERFORMANCE_TARGETS.storageLatencyMs) {
|
|
137
|
-
console.log(` ✓ PASS: Under ${PERFORMANCE_TARGETS.storageLatencyMs}ms target`);
|
|
138
|
-
} else {
|
|
139
|
-
console.log(` ✗ FAIL: Exceeds ${PERFORMANCE_TARGETS.storageLatencyMs}ms target`);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
console.log();
|
|
143
|
-
return durationMs < PERFORMANCE_TARGETS.storageLatencyMs;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Test 2: Retrieval Performance at Scale
|
|
148
|
-
*/
|
|
149
|
-
function testRetrievalPerformance(memoryCount) {
|
|
150
|
-
console.log(`Test 2: Retrieval Performance (${memoryCount} memories)`);
|
|
151
|
-
console.log("-".repeat(60));
|
|
152
|
-
|
|
153
|
-
createTestMemories(memoryCount);
|
|
154
|
-
|
|
155
|
-
// Test retrieval
|
|
156
|
-
const queries = [
|
|
157
|
-
"Python programming",
|
|
158
|
-
"JavaScript framework",
|
|
159
|
-
"database connection",
|
|
160
|
-
"user authentication",
|
|
161
|
-
"API endpoint",
|
|
162
|
-
];
|
|
163
|
-
|
|
164
|
-
const results = [];
|
|
165
|
-
|
|
166
|
-
for (const query of queries) {
|
|
167
|
-
const { result, durationMs } = measureTime(() => {
|
|
168
|
-
return retriever.retrieveRelevantMemories(query, { limit: 10 });
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
results.push({ query, durationMs, count: result.length });
|
|
172
|
-
console.log(` "${query}": ${durationMs.toFixed(2)}ms (${result.length} results)`);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const avgDuration = results.reduce((sum, r) => sum + r.durationMs, 0) / results.length;
|
|
176
|
-
console.log(` Average retrieval time: ${avgDuration.toFixed(2)}ms`);
|
|
177
|
-
|
|
178
|
-
if (avgDuration < PERFORMANCE_TARGETS.retrievalLatencyMs) {
|
|
179
|
-
console.log(` ✓ PASS: Under ${PERFORMANCE_TARGETS.retrievalLatencyMs}ms target`);
|
|
180
|
-
} else {
|
|
181
|
-
console.log(` ✗ FAIL: Exceeds ${PERFORMANCE_TARGETS.retrievalLatencyMs}ms target`);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
console.log();
|
|
185
|
-
return avgDuration < PERFORMANCE_TARGETS.retrievalLatencyMs;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
/**
|
|
189
|
-
* Test 3: FTS5 Search Performance
|
|
190
|
-
*/
|
|
191
|
-
function testSearchPerformance(memoryCount) {
|
|
192
|
-
console.log(`Test 3: FTS5 Search Performance (${memoryCount} memories)`);
|
|
193
|
-
console.log("-".repeat(60));
|
|
194
|
-
|
|
195
|
-
const queries = [
|
|
196
|
-
"Python",
|
|
197
|
-
"framework AND JavaScript",
|
|
198
|
-
"database OR connection",
|
|
199
|
-
"user authentication security",
|
|
200
|
-
];
|
|
201
|
-
|
|
202
|
-
const results = [];
|
|
203
|
-
|
|
204
|
-
for (const query of queries) {
|
|
205
|
-
const { result, durationMs } = measureTime(() => {
|
|
206
|
-
return search.searchMemories({ query, limit: 20 });
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
results.push({ query, durationMs, count: result.length });
|
|
210
|
-
console.log(` "${query}": ${durationMs.toFixed(2)}ms (${result.length} results)`);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const avgDuration = results.reduce((sum, r) => sum + r.durationMs, 0) / results.length;
|
|
214
|
-
console.log(` Average search time: ${avgDuration.toFixed(2)}ms`);
|
|
215
|
-
|
|
216
|
-
if (avgDuration < PERFORMANCE_TARGETS.searchLatencyMs) {
|
|
217
|
-
console.log(` ✓ PASS: Under ${PERFORMANCE_TARGETS.searchLatencyMs}ms target`);
|
|
218
|
-
} else {
|
|
219
|
-
console.log(` ✗ FAIL: Exceeds ${PERFORMANCE_TARGETS.searchLatencyMs}ms target`);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
console.log();
|
|
223
|
-
return avgDuration < PERFORMANCE_TARGETS.searchLatencyMs;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Test 4: Surprise Calculation Performance
|
|
228
|
-
*/
|
|
229
|
-
function testSurprisePerformance() {
|
|
230
|
-
console.log("Test 4: Surprise Calculation Performance");
|
|
231
|
-
console.log("-".repeat(60));
|
|
232
|
-
|
|
233
|
-
const existingMemories = store.getRecentMemories({ limit: 100 });
|
|
234
|
-
|
|
235
|
-
const testCases = [
|
|
236
|
-
"User prefers Rust for systems programming with zero-cost abstractions",
|
|
237
|
-
"This project uses GraphQL with Apollo Server and PostgreSQL database",
|
|
238
|
-
"IMPORTANT: Always validate input to prevent SQL injection attacks",
|
|
239
|
-
];
|
|
240
|
-
|
|
241
|
-
const results = [];
|
|
242
|
-
|
|
243
|
-
for (const content of testCases) {
|
|
244
|
-
const { result, durationMs } = measureTime(() => {
|
|
245
|
-
return surprise.calculateSurprise(
|
|
246
|
-
{ content, type: "fact", category: "code" },
|
|
247
|
-
existingMemories,
|
|
248
|
-
{ userContent: content }
|
|
249
|
-
);
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
results.push({ durationMs, score: result });
|
|
253
|
-
console.log(` Surprise calculation: ${durationMs.toFixed(2)}ms (score: ${result.toFixed(3)})`);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
const avgDuration = results.reduce((sum, r) => sum + r.durationMs, 0) / results.length;
|
|
257
|
-
console.log(` Average surprise calculation: ${avgDuration.toFixed(2)}ms`);
|
|
258
|
-
|
|
259
|
-
// Surprise calculation should be fast (<10ms)
|
|
260
|
-
const passThreshold = 10;
|
|
261
|
-
if (avgDuration < passThreshold) {
|
|
262
|
-
console.log(` ✓ PASS: Under ${passThreshold}ms target`);
|
|
263
|
-
} else {
|
|
264
|
-
console.log(` ✗ FAIL: Exceeds ${passThreshold}ms target`);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
console.log();
|
|
268
|
-
return avgDuration < passThreshold;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Test 5: Memory Extraction Performance
|
|
273
|
-
*/
|
|
274
|
-
async function testExtractionPerformance() {
|
|
275
|
-
console.log("Test 5: Memory Extraction Performance");
|
|
276
|
-
console.log("-".repeat(60));
|
|
277
|
-
|
|
278
|
-
const testResponses = [
|
|
279
|
-
{
|
|
280
|
-
role: "assistant",
|
|
281
|
-
content: "I understand that you prefer Python for data processing and always use pandas for DataFrame operations. We decided to implement the API using FastAPI framework with async/await patterns."
|
|
282
|
-
},
|
|
283
|
-
{
|
|
284
|
-
role: "assistant",
|
|
285
|
-
content: "This project uses TypeScript with strict mode, ESLint for linting, and Jest for testing. The database connection uses connection pooling with max 20 connections."
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
role: "assistant",
|
|
289
|
-
content: "IMPORTANT: User wants detailed error messages in development but minimal info in production. The authentication system must use JWT tokens with 1-hour expiration."
|
|
290
|
-
},
|
|
291
|
-
];
|
|
292
|
-
|
|
293
|
-
const results = [];
|
|
294
|
-
|
|
295
|
-
for (const response of testResponses) {
|
|
296
|
-
const { result, durationMs } = await measureTimeAsync(async () => {
|
|
297
|
-
return await extractor.extractMemories(response, [], { sessionId: null });
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
results.push({ durationMs, count: result.length });
|
|
301
|
-
console.log(` Extraction: ${durationMs.toFixed(2)}ms (${result.length} memories extracted)`);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const avgDuration = results.reduce((sum, r) => sum + r.durationMs, 0) / results.length;
|
|
305
|
-
console.log(` Average extraction time: ${avgDuration.toFixed(2)}ms`);
|
|
306
|
-
|
|
307
|
-
if (avgDuration < PERFORMANCE_TARGETS.extractionLatencyMs) {
|
|
308
|
-
console.log(` ✓ PASS: Under ${PERFORMANCE_TARGETS.extractionLatencyMs}ms target`);
|
|
309
|
-
} else {
|
|
310
|
-
console.log(` ✗ FAIL: Exceeds ${PERFORMANCE_TARGETS.extractionLatencyMs}ms target`);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
console.log();
|
|
314
|
-
return avgDuration < PERFORMANCE_TARGETS.extractionLatencyMs;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* Test 6: Database Size and Memory Overhead
|
|
319
|
-
*/
|
|
320
|
-
function testStorageEfficiency(memoryCount) {
|
|
321
|
-
console.log(`Test 6: Storage Efficiency (${memoryCount} memories)`);
|
|
322
|
-
console.log("-".repeat(60));
|
|
323
|
-
|
|
324
|
-
// Get the actual database path used
|
|
325
|
-
const actualDbPath = require("../src/config").dbPath;
|
|
326
|
-
|
|
327
|
-
if (!fs.existsSync(actualDbPath)) {
|
|
328
|
-
console.log(` ⚠ SKIP: Database file not found at ${actualDbPath}`);
|
|
329
|
-
console.log();
|
|
330
|
-
return true; // Skip, don't fail
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
const stats = fs.statSync(actualDbPath);
|
|
334
|
-
const sizeMb = stats.size / (1024 * 1024);
|
|
335
|
-
const bytesPerMemory = memoryCount > 0 ? stats.size / memoryCount : 0;
|
|
336
|
-
|
|
337
|
-
console.log(` Database size: ${sizeMb.toFixed(2)} MB`);
|
|
338
|
-
console.log(` Bytes per memory: ${bytesPerMemory.toFixed(0)} bytes`);
|
|
339
|
-
console.log(` Total memories: ${memoryCount}`);
|
|
340
|
-
|
|
341
|
-
if (bytesPerMemory < PERFORMANCE_TARGETS.bytesPerMemory) {
|
|
342
|
-
console.log(` ✓ PASS: Under ${PERFORMANCE_TARGETS.bytesPerMemory} bytes per memory target`);
|
|
343
|
-
} else {
|
|
344
|
-
console.log(` ✗ FAIL: Exceeds ${PERFORMANCE_TARGETS.bytesPerMemory} bytes per memory target`);
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
console.log();
|
|
348
|
-
return bytesPerMemory < PERFORMANCE_TARGETS.bytesPerMemory;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Test 7: Concurrent Access Performance
|
|
353
|
-
*/
|
|
354
|
-
function testConcurrentAccess() {
|
|
355
|
-
console.log("Test 7: Concurrent Access Performance");
|
|
356
|
-
console.log("-".repeat(60));
|
|
357
|
-
|
|
358
|
-
const queries = Array.from({ length: 10 }, (_, i) => `query${i}`);
|
|
359
|
-
|
|
360
|
-
const start = process.hrtime.bigint();
|
|
361
|
-
|
|
362
|
-
const results = queries.map(query => {
|
|
363
|
-
return retriever.retrieveRelevantMemories(query, { limit: 5 });
|
|
364
|
-
});
|
|
365
|
-
|
|
366
|
-
const end = process.hrtime.bigint();
|
|
367
|
-
const durationMs = Number(end - start) / 1_000_000;
|
|
368
|
-
|
|
369
|
-
console.log(` 10 concurrent retrievals: ${durationMs.toFixed(2)}ms`);
|
|
370
|
-
console.log(` Average per retrieval: ${(durationMs / 10).toFixed(2)}ms`);
|
|
371
|
-
|
|
372
|
-
const passThreshold = 100;
|
|
373
|
-
if (durationMs < passThreshold) {
|
|
374
|
-
console.log(` ✓ PASS: Under ${passThreshold}ms for 10 concurrent queries`);
|
|
375
|
-
} else {
|
|
376
|
-
console.log(` ✗ FAIL: Exceeds ${passThreshold}ms for 10 concurrent queries`);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
console.log();
|
|
380
|
-
return durationMs < passThreshold;
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/**
|
|
384
|
-
* Run all performance tests
|
|
385
|
-
*/
|
|
386
|
-
async function runPerformanceTests() {
|
|
387
|
-
console.log(`Starting at: ${new Date().toISOString()}`);
|
|
388
|
-
console.log();
|
|
389
|
-
|
|
390
|
-
const results = {
|
|
391
|
-
creation: false,
|
|
392
|
-
retrieval: false,
|
|
393
|
-
search: false,
|
|
394
|
-
surprise: false,
|
|
395
|
-
extraction: false,
|
|
396
|
-
storage: false,
|
|
397
|
-
concurrent: false,
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
try {
|
|
401
|
-
// Test 1: Creation
|
|
402
|
-
results.creation = testCreationPerformance();
|
|
403
|
-
|
|
404
|
-
// Test 2: Retrieval (with 1000 memories)
|
|
405
|
-
results.retrieval = testRetrievalPerformance(TEST_SIZES.medium);
|
|
406
|
-
|
|
407
|
-
// Test 3: Search
|
|
408
|
-
results.search = testSearchPerformance(TEST_SIZES.medium);
|
|
409
|
-
|
|
410
|
-
// Test 4: Surprise
|
|
411
|
-
results.surprise = testSurprisePerformance();
|
|
412
|
-
|
|
413
|
-
// Test 5: Extraction
|
|
414
|
-
results.extraction = await testExtractionPerformance();
|
|
415
|
-
|
|
416
|
-
// Test 6: Storage efficiency
|
|
417
|
-
const totalMemories = store.countMemories();
|
|
418
|
-
results.storage = testStorageEfficiency(totalMemories);
|
|
419
|
-
|
|
420
|
-
// Test 7: Concurrent access
|
|
421
|
-
results.concurrent = testConcurrentAccess();
|
|
422
|
-
|
|
423
|
-
// Summary
|
|
424
|
-
console.log("=".repeat(80));
|
|
425
|
-
console.log("Performance Test Summary");
|
|
426
|
-
console.log("=".repeat(80));
|
|
427
|
-
console.log();
|
|
428
|
-
|
|
429
|
-
const passCount = Object.values(results).filter(Boolean).length;
|
|
430
|
-
const totalTests = Object.keys(results).length;
|
|
431
|
-
|
|
432
|
-
Object.entries(results).forEach(([test, passed]) => {
|
|
433
|
-
console.log(` ${passed ? '✓' : '✗'} ${test.padEnd(20)} ${passed ? 'PASS' : 'FAIL'}`);
|
|
434
|
-
});
|
|
435
|
-
|
|
436
|
-
console.log();
|
|
437
|
-
console.log(`Total: ${passCount}/${totalTests} tests passed`);
|
|
438
|
-
console.log();
|
|
439
|
-
|
|
440
|
-
if (passCount === totalTests) {
|
|
441
|
-
console.log("✓ All performance tests PASSED");
|
|
442
|
-
return 0;
|
|
443
|
-
} else {
|
|
444
|
-
console.log(`✗ ${totalTests - passCount} performance tests FAILED`);
|
|
445
|
-
return 1;
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
} catch (err) {
|
|
449
|
-
console.error("Performance test error:", err);
|
|
450
|
-
return 1;
|
|
451
|
-
} finally {
|
|
452
|
-
// Cleanup
|
|
453
|
-
try {
|
|
454
|
-
if (fs.existsSync(testDbPath)) {
|
|
455
|
-
fs.unlinkSync(testDbPath);
|
|
456
|
-
console.log(`Cleaned up test database: ${testDbPath}`);
|
|
457
|
-
}
|
|
458
|
-
} catch (err) {
|
|
459
|
-
console.error("Cleanup error:", err);
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
// Run tests
|
|
465
|
-
runPerformanceTests()
|
|
466
|
-
.then(exitCode => {
|
|
467
|
-
process.exit(exitCode);
|
|
468
|
-
})
|
|
469
|
-
.catch(err => {
|
|
470
|
-
console.error("Fatal error:", err);
|
|
471
|
-
process.exit(1);
|
|
472
|
-
});
|