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.
Files changed (128) hide show
  1. package/.lynkr/telemetry.db +0 -0
  2. package/.lynkr/telemetry.db-shm +0 -0
  3. package/.lynkr/telemetry.db-wal +0 -0
  4. package/README.md +196 -322
  5. package/lynkr-skill.tar.gz +0 -0
  6. package/package.json +4 -3
  7. package/src/api/openai-router.js +64 -13
  8. package/src/api/providers-handler.js +171 -3
  9. package/src/api/router.js +9 -2
  10. package/src/clients/circuit-breaker.js +10 -247
  11. package/src/clients/codex-process.js +342 -0
  12. package/src/clients/codex-utils.js +143 -0
  13. package/src/clients/databricks.js +210 -63
  14. package/src/clients/resilience.js +540 -0
  15. package/src/clients/retry.js +22 -167
  16. package/src/clients/standard-tools.js +23 -0
  17. package/src/config/index.js +77 -0
  18. package/src/context/compression.js +42 -9
  19. package/src/context/distill.js +492 -0
  20. package/src/orchestrator/index.js +48 -8
  21. package/src/routing/complexity-analyzer.js +258 -5
  22. package/src/routing/index.js +12 -2
  23. package/src/routing/latency-tracker.js +148 -0
  24. package/src/routing/model-tiers.js +2 -0
  25. package/src/routing/quality-scorer.js +113 -0
  26. package/src/routing/telemetry.js +464 -0
  27. package/src/server.js +13 -12
  28. package/src/tools/code-graph.js +538 -0
  29. package/src/tools/code-mode.js +304 -0
  30. package/src/tools/index.js +4 -0
  31. package/src/tools/lazy-loader.js +18 -0
  32. package/src/tools/mcp-remote.js +7 -0
  33. package/src/tools/smart-selection.js +11 -0
  34. package/src/tools/tinyfish.js +358 -0
  35. package/src/tools/truncate.js +1 -0
  36. package/src/utils/payload.js +206 -0
  37. package/src/utils/perf-timer.js +80 -0
  38. package/.github/FUNDING.yml +0 -15
  39. package/.github/workflows/README.md +0 -215
  40. package/.github/workflows/ci.yml +0 -69
  41. package/.github/workflows/index.yml +0 -62
  42. package/.github/workflows/web-tools-tests.yml +0 -56
  43. package/CITATIONS.bib +0 -6
  44. package/DEPLOYMENT.md +0 -1001
  45. package/LYNKR-TUI-PLAN.md +0 -984
  46. package/PERFORMANCE-REPORT.md +0 -866
  47. package/PLAN-per-client-model-routing.md +0 -252
  48. package/docs/42642f749da6234f41b6b425c3bb07c9.txt +0 -1
  49. package/docs/BingSiteAuth.xml +0 -4
  50. package/docs/docs-style.css +0 -478
  51. package/docs/docs.html +0 -198
  52. package/docs/google5be250e608e6da39.html +0 -1
  53. package/docs/index.html +0 -577
  54. package/docs/index.md +0 -584
  55. package/docs/robots.txt +0 -4
  56. package/docs/sitemap.xml +0 -44
  57. package/docs/style.css +0 -1223
  58. package/docs/toon-integration-spec.md +0 -130
  59. package/documentation/README.md +0 -101
  60. package/documentation/api.md +0 -806
  61. package/documentation/claude-code-cli.md +0 -679
  62. package/documentation/codex-cli.md +0 -397
  63. package/documentation/contributing.md +0 -571
  64. package/documentation/cursor-integration.md +0 -734
  65. package/documentation/docker.md +0 -874
  66. package/documentation/embeddings.md +0 -762
  67. package/documentation/faq.md +0 -713
  68. package/documentation/features.md +0 -403
  69. package/documentation/headroom.md +0 -519
  70. package/documentation/installation.md +0 -758
  71. package/documentation/memory-system.md +0 -476
  72. package/documentation/production.md +0 -636
  73. package/documentation/providers.md +0 -1009
  74. package/documentation/routing.md +0 -476
  75. package/documentation/testing.md +0 -629
  76. package/documentation/token-optimization.md +0 -325
  77. package/documentation/tools.md +0 -697
  78. package/documentation/troubleshooting.md +0 -969
  79. package/final-test.js +0 -33
  80. package/headroom-sidecar/config.py +0 -93
  81. package/headroom-sidecar/requirements.txt +0 -14
  82. package/headroom-sidecar/server.py +0 -451
  83. package/monitor-agents.sh +0 -31
  84. package/scripts/audit-log-reader.js +0 -399
  85. package/scripts/compact-dictionary.js +0 -204
  86. package/scripts/test-deduplication.js +0 -448
  87. package/src/db/database.sqlite +0 -0
  88. package/te +0 -11622
  89. package/test/README.md +0 -212
  90. package/test/azure-openai-config.test.js +0 -213
  91. package/test/azure-openai-error-resilience.test.js +0 -238
  92. package/test/azure-openai-format-conversion.test.js +0 -354
  93. package/test/azure-openai-integration.test.js +0 -287
  94. package/test/azure-openai-routing.test.js +0 -175
  95. package/test/azure-openai-streaming.test.js +0 -171
  96. package/test/bedrock-integration.test.js +0 -457
  97. package/test/comprehensive-test-suite.js +0 -928
  98. package/test/config-validation.test.js +0 -207
  99. package/test/cursor-integration.test.js +0 -484
  100. package/test/format-conversion.test.js +0 -578
  101. package/test/hybrid-routing-integration.test.js +0 -269
  102. package/test/hybrid-routing-performance.test.js +0 -428
  103. package/test/llamacpp-integration.test.js +0 -882
  104. package/test/lmstudio-integration.test.js +0 -347
  105. package/test/memory/extractor.test.js +0 -398
  106. package/test/memory/retriever.test.js +0 -613
  107. package/test/memory/retriever.test.js.bak +0 -585
  108. package/test/memory/search.test.js +0 -537
  109. package/test/memory/search.test.js.bak +0 -389
  110. package/test/memory/store.test.js +0 -344
  111. package/test/memory/store.test.js.bak +0 -312
  112. package/test/memory/surprise.test.js +0 -300
  113. package/test/memory-performance.test.js +0 -472
  114. package/test/openai-integration.test.js +0 -683
  115. package/test/openrouter-error-resilience.test.js +0 -418
  116. package/test/passthrough-mode.test.js +0 -385
  117. package/test/performance-benchmark.js +0 -351
  118. package/test/performance-tests.js +0 -528
  119. package/test/routing.test.js +0 -225
  120. package/test/toon-compression.test.js +0 -131
  121. package/test/web-tools.test.js +0 -329
  122. package/test-agents-simple.js +0 -43
  123. package/test-cli-connection.sh +0 -33
  124. package/test-learning-unit.js +0 -126
  125. package/test-learning.js +0 -112
  126. package/test-parallel-agents.sh +0 -124
  127. package/test-parallel-direct.js +0 -155
  128. package/test-subagents.sh +0 -117
@@ -1,585 +0,0 @@
1
- const assert = require("assert");
2
- const { describe, it, beforeEach, afterEach } = require("node:test");
3
- const fs = require("fs");
4
- const path = require("path");
5
-
6
- describe("Memory Retriever", () => {
7
- let store;
8
- let retriever;
9
- let testDbPath;
10
-
11
- beforeEach(() => {
12
- // Create a temporary test database
13
- testDbPath = path.join(__dirname, `../../data/test-memory-${Date.now()}.db`);
14
-
15
- // Clear module cache
16
- delete require.cache[require.resolve("../../src/db")];
17
- delete require.cache[require.resolve("../../src/memory/store")];
18
- delete require.cache[require.resolve("../../src/memory/search")];
19
- delete require.cache[require.resolve("../../src/memory/retriever")];
20
-
21
- // Set test environment
22
- process.env.DB_PATH = testDbPath;
23
-
24
- // Initialize database with schema
25
- require("../../src/db");
26
-
27
- // Load modules
28
- store = require("../../src/memory/store");
29
- retriever = require("../../src/memory/retriever");
30
-
31
- // Create test memories with different characteristics
32
- const now = Date.now();
33
-
34
- // Recent + important + relevant
35
- store.createMemory({
36
- content: "User prefers Python for data processing and machine learning",
37
- type: "preference",
38
- category: "user",
39
- importance: 0.9,
40
- surpriseScore: 0.8
41
- });
42
-
43
- // Old but important
44
- const db = require("../../src/db");
45
- const oldTimestamp = now - (30 * 24 * 60 * 60 * 1000); // 30 days ago
46
- db.prepare(`
47
- INSERT INTO memories (content, type, category, importance, surprise_score, created_at, updated_at)
48
- VALUES (?, ?, ?, ?, ?, ?, ?)
49
- `).run(
50
- "Critical: Always validate user input for SQL injection",
51
- "fact",
52
- "security",
53
- 0.95,
54
- 0.9,
55
- oldTimestamp,
56
- oldTimestamp
57
- );
58
-
59
- // Recent but less important
60
- store.createMemory({
61
- content: "User mentioned liking the color blue",
62
- type: "preference",
63
- category: "user",
64
- importance: 0.3,
65
- surpriseScore: 0.2
66
- });
67
-
68
- // Relevant to specific queries
69
- store.createMemory({
70
- content: "This project uses Express.js with TypeScript and JWT authentication",
71
- type: "fact",
72
- category: "project",
73
- importance: 0.7,
74
- surpriseScore: 0.6
75
- });
76
-
77
- store.createMemory({
78
- content: "Database connection pool configured with max 20 connections",
79
- type: "fact",
80
- category: "code",
81
- importance: 0.6,
82
- surpriseScore: 0.5
83
- });
84
- });
85
-
86
- afterEach(() => {
87
- // Clean up test database
88
- try {
89
- if (fs.existsSync(testDbPath)) {
90
- fs.unlinkSync(testDbPath);
91
- }
92
- } catch (err) {
93
- // Ignore cleanup errors
94
- }
95
- });
96
-
97
- describe("retrieveRelevantMemories()", () => {
98
- it("should retrieve memories relevant to query", () => {
99
- const memories = retriever.retrieveRelevantMemories("Python programming");
100
- assert.ok(memories.length > 0);
101
- assert.ok(memories.some(m => m.content.toLowerCase().includes("python")));
102
- });
103
-
104
- it("should respect limit parameter", () => {
105
- const memories = retriever.retrieveRelevantMemories("project", { limit: 2 });
106
- assert.ok(memories.length <= 2);
107
- });
108
-
109
- it("should rank by multi-signal scoring", () => {
110
- const memories = retriever.retrieveRelevantMemories("authentication security", { limit: 5 });
111
-
112
- if (memories.length > 1) {
113
- // First result should have highest score
114
- const scores = memories.map(m =>
115
- retriever.calculateRetrievalScore(m, "authentication security", {
116
- recencyWeight: 0.3,
117
- importanceWeight: 0.4,
118
- relevanceWeight: 0.3
119
- })
120
- );
121
-
122
- for (let i = 1; i < scores.length; i++) {
123
- assert.ok(scores[i - 1] >= scores[i],
124
- `Memory ${i-1} score ${scores[i-1]} should be >= memory ${i} score ${scores[i]}`);
125
- }
126
- }
127
- });
128
-
129
- it("should combine recency, importance, and relevance", () => {
130
- const memories = retriever.retrieveRelevantMemories("Python", { limit: 5 });
131
-
132
- // Should include the high-importance Python memory
133
- assert.ok(memories.some(m =>
134
- m.content.includes("Python") && m.importance >= 0.8
135
- ));
136
- });
137
-
138
- it("should filter by session id when specified", () => {
139
- // Use null for sessionId to avoid FOREIGN KEY constraint
140
- store.createMemory({
141
- content: "Session-specific memory about testing",
142
- type: "fact",
143
- sessionId: null, // Changed from "test-session-123" to avoid FK constraint
144
- importance: 0.8
145
- });
146
-
147
- const memories = retriever.retrieveRelevantMemories("testing", {
148
- sessionId: null,
149
- includeGlobal: true
150
- });
151
-
152
- // Should include memories
153
- assert.ok(Array.isArray(memories));
154
- });
155
-
156
- it("should include global memories when includeGlobal is true", () => {
157
- // All memories use null sessionId to avoid FK constraint
158
- store.createMemory({
159
- content: "Memory about databases type A",
160
- type: "fact",
161
- sessionId: null,
162
- importance: 0.5
163
- });
164
-
165
- store.createMemory({
166
- content: "Global memory about databases type B",
167
- type: "fact",
168
- sessionId: null,
169
- importance: 0.9
170
- });
171
-
172
- const memories = retriever.retrieveRelevantMemories("databases", {
173
- sessionId: null,
174
- includeGlobal: true,
175
- limit: 10
176
- });
177
-
178
- // Should include memories
179
- assert.ok(memories.length >= 0);
180
- });
181
-
182
- it("should handle empty query gracefully", () => {
183
- const memories = retriever.retrieveRelevantMemories("", { limit: 3 });
184
- // Should return recent/important memories even without query
185
- assert.ok(Array.isArray(memories));
186
- });
187
-
188
- it("should handle queries with no matches", () => {
189
- const memories = retriever.retrieveRelevantMemories("nonexistent-keyword-xyz");
190
- // Should still return some memories (e.g., by importance)
191
- assert.ok(Array.isArray(memories));
192
- });
193
- });
194
-
195
- describe("calculateRetrievalScore()", () => {
196
- it("should calculate score with default weights", () => {
197
- const memory = {
198
- content: "User prefers Python for data processing",
199
- importance: 0.8,
200
- createdAt: Date.now(),
201
- accessCount: 5
202
- };
203
-
204
- const score = retriever.calculateRetrievalScore(memory, "Python data", {
205
- recencyWeight: 0.3,
206
- importanceWeight: 0.4,
207
- relevanceWeight: 0.3
208
- });
209
- assert.ok(score >= 0 && score <= 1, `Score ${score} should be in [0,1]`);
210
- });
211
-
212
- it("should give higher scores to recent memories", () => {
213
- const recent = {
214
- content: "Recent memory about Python",
215
- importance: 0.5,
216
- createdAt: Date.now(),
217
- accessCount: 0
218
- };
219
-
220
- const old = {
221
- content: "Old memory about Python",
222
- importance: 0.5,
223
- createdAt: Date.now() - (60 * 24 * 60 * 60 * 1000), // 60 days ago
224
- accessCount: 0
225
- };
226
-
227
- const weights = { recencyWeight: 0.3, importanceWeight: 0.4, relevanceWeight: 0.3 };
228
- const recentScore = retriever.calculateRetrievalScore(recent, "Python", weights);
229
- const oldScore = retriever.calculateRetrievalScore(old, "Python", weights);
230
-
231
- assert.ok(recentScore > oldScore,
232
- `Recent score ${recentScore} should be > old score ${oldScore}`);
233
- });
234
-
235
- it("should give higher scores to important memories", () => {
236
- const important = {
237
- content: "Important memory about Python",
238
- importance: 0.9,
239
- createdAt: Date.now(),
240
- accessCount: 0
241
- };
242
-
243
- const unimportant = {
244
- content: "Unimportant memory about Python",
245
- importance: 0.2,
246
- createdAt: Date.now(),
247
- accessCount: 0
248
- };
249
-
250
- const weights = { recencyWeight: 0.3, importanceWeight: 0.4, relevanceWeight: 0.3 };
251
- const importantScore = retriever.calculateRetrievalScore(important, "Python", weights);
252
- const unimportantScore = retriever.calculateRetrievalScore(unimportant, "Python", weights);
253
-
254
- assert.ok(importantScore > unimportantScore,
255
- `Important score ${importantScore} should be > unimportant score ${unimportantScore}`);
256
- });
257
-
258
- it("should give higher scores to relevant content", () => {
259
- const relevant = {
260
- content: "Python programming language for data processing and machine learning",
261
- importance: 0.5,
262
- createdAt: Date.now(),
263
- accessCount: 0
264
- };
265
-
266
- const irrelevant = {
267
- content: "JavaScript framework for web development",
268
- importance: 0.5,
269
- createdAt: Date.now(),
270
- accessCount: 0
271
- };
272
-
273
- const weights = { recencyWeight: 0.3, importanceWeight: 0.4, relevanceWeight: 0.3 };
274
- const relevantScore = retriever.calculateRetrievalScore(relevant, "Python programming", weights);
275
- const irrelevantScore = retriever.calculateRetrievalScore(irrelevant, "Python programming", weights);
276
-
277
- assert.ok(relevantScore > irrelevantScore,
278
- `Relevant score ${relevantScore} should be > irrelevant score ${irrelevantScore}`);
279
- });
280
-
281
- it("should allow custom weight configuration", () => {
282
- const memory = {
283
- content: "Test memory",
284
- importance: 0.8,
285
- createdAt: Date.now() - (30 * 24 * 60 * 60 * 1000),
286
- accessCount: 0
287
- };
288
-
289
- // Emphasize importance over recency
290
- const importanceHeavy = retriever.calculateRetrievalScore(memory, "test", {
291
- recencyWeight: 0.1,
292
- importanceWeight: 0.8,
293
- relevanceWeight: 0.1
294
- });
295
-
296
- // Emphasize recency over importance
297
- const recencyHeavy = retriever.calculateRetrievalScore(memory, "test", {
298
- recencyWeight: 0.8,
299
- importanceWeight: 0.1,
300
- relevanceWeight: 0.1
301
- });
302
-
303
- // For an old but important memory, importance-heavy should score higher
304
- assert.ok(importanceHeavy > recencyHeavy,
305
- `Importance-heavy ${importanceHeavy} should be > recency-heavy ${recencyHeavy} for old memory`);
306
- });
307
- });
308
-
309
- describe("formatMemoriesForContext()", () => {
310
- it("should format memories as readable text", () => {
311
- const memories = store.getRecentMemories({ limit: 3 });
312
- const formatted = retriever.formatMemoriesForContext(memories);
313
-
314
- assert.ok(typeof formatted === "string");
315
- assert.ok(formatted.length > 0);
316
-
317
- // Should include memory types and content
318
- memories.forEach(m => {
319
- assert.ok(formatted.includes(m.type) || formatted.includes(m.content));
320
- });
321
- });
322
-
323
- it("should handle empty memories array", () => {
324
- const formatted = retriever.formatMemoriesForContext([]);
325
- assert.strictEqual(formatted, "");
326
- });
327
-
328
- it("should include relative timestamps", () => {
329
- const memories = store.getRecentMemories({ limit: 2 });
330
- const formatted = retriever.formatMemoriesForContext(memories);
331
-
332
- // Should include time indicators
333
- assert.ok(
334
- formatted.includes("ago") ||
335
- formatted.includes("recently") ||
336
- formatted.includes("just now")
337
- );
338
- });
339
-
340
- it("should group by type", () => {
341
- const memories = [
342
- { content: "Preference 1", type: "preference", createdAt: Date.now() },
343
- { content: "Preference 2", type: "preference", createdAt: Date.now() },
344
- { content: "Fact 1", type: "fact", createdAt: Date.now() }
345
- ];
346
-
347
- const formatted = retriever.formatMemoriesForContext(memories);
348
-
349
- // Should mention types
350
- assert.ok(formatted.includes("preference") || formatted.includes("Preference"));
351
- assert.ok(formatted.includes("fact") || formatted.includes("Fact"));
352
- });
353
- });
354
-
355
- describe("injectMemoriesIntoSystem()", () => {
356
- it("should inject memories into system prompt", () => {
357
- const originalSystem = "You are a helpful assistant.";
358
- const memories = store.getRecentMemories({ limit: 2 });
359
-
360
- const injected = retriever.injectMemoriesIntoSystem(originalSystem, memories);
361
-
362
- assert.ok(typeof injected === "string");
363
- assert.ok(injected.includes(originalSystem));
364
- assert.ok(injected.length > originalSystem.length);
365
- });
366
-
367
- it("should include memory content in injection", () => {
368
- const originalSystem = "You are a helpful assistant.";
369
- const memories = [
370
- {
371
- content: "User prefers Python",
372
- type: "preference",
373
- createdAt: Date.now()
374
- }
375
- ];
376
-
377
- const injected = retriever.injectMemoriesIntoSystem(originalSystem, memories);
378
-
379
- assert.ok(injected.includes("Python") || injected.includes("prefer"));
380
- });
381
-
382
- it("should handle empty memories", () => {
383
- const originalSystem = "You are a helpful assistant.";
384
- const injected = retriever.injectMemoriesIntoSystem(originalSystem, []);
385
-
386
- assert.strictEqual(injected, originalSystem);
387
- });
388
-
389
- it("should handle null/undefined system prompt", () => {
390
- const memories = store.getRecentMemories({ limit: 2 });
391
-
392
- const fromNull = retriever.injectMemoriesIntoSystem(null, memories);
393
- const fromUndefined = retriever.injectMemoriesIntoSystem(undefined, memories);
394
-
395
- assert.ok(typeof fromNull === "string");
396
- assert.ok(typeof fromUndefined === "string");
397
- });
398
-
399
- it("should support different injection formats", () => {
400
- const memories = store.getRecentMemories({ limit: 2 });
401
-
402
- const systemFormat = retriever.injectMemoriesIntoSystem(
403
- "You are helpful.",
404
- memories,
405
- "system"
406
- );
407
-
408
- const preambleFormat = retriever.injectMemoriesIntoSystem(
409
- "You are helpful.",
410
- memories,
411
- "assistant_preamble"
412
- );
413
-
414
- assert.ok(typeof systemFormat === "string");
415
- // assistant_preamble format returns an object
416
- assert.ok(typeof preambleFormat === "object");
417
- assert.ok(preambleFormat.system === "You are helpful.");
418
- assert.ok(typeof preambleFormat.memoryPreamble === "string");
419
- assert.ok(preambleFormat.memoryPreamble.length > 0);
420
- });
421
- });
422
-
423
- describe("getMemoryStats()", () => {
424
- it("should return statistics about memories", () => {
425
- const stats = retriever.getMemoryStats();
426
-
427
- assert.ok(stats.total >= 0);
428
- assert.ok(stats.byType);
429
- assert.ok(stats.byCategory);
430
- assert.ok(typeof stats.avgImportance === "number");
431
- });
432
-
433
- it("should count memories by type", () => {
434
- const stats = retriever.getMemoryStats();
435
-
436
- assert.ok(typeof stats.byType === "object");
437
- // Should have counts for types we created
438
- assert.ok(stats.byType.preference >= 0);
439
- assert.ok(stats.byType.fact >= 0);
440
- });
441
-
442
- it("should count memories by category", () => {
443
- const stats = retriever.getMemoryStats();
444
-
445
- assert.ok(typeof stats.byCategory === "object");
446
- // Should have counts for categories we created
447
- assert.ok(stats.byCategory.user >= 0 || stats.byCategory.project >= 0);
448
- });
449
-
450
- it("should calculate average importance", () => {
451
- const stats = retriever.getMemoryStats();
452
-
453
- assert.ok(stats.avgImportance >= 0 && stats.avgImportance <= 1);
454
- });
455
-
456
- it("should filter stats by session", () => {
457
- store.createMemory({
458
- content: "Session memory",
459
- type: "fact",
460
- sessionId: "test-session"
461
- });
462
-
463
- const globalStats = retriever.getMemoryStats();
464
- const sessionStats = retriever.getMemoryStats({ sessionId: "test-session" });
465
-
466
- assert.ok(sessionStats.total <= globalStats.total);
467
- });
468
- });
469
-
470
- describe("extractQueryFromMessage()", () => {
471
- it("should extract query from simple user message", () => {
472
- const message = {
473
- role: "user",
474
- content: "How do I use Python for data processing?"
475
- };
476
-
477
- const query = retriever.extractQueryFromMessage(message);
478
- assert.ok(typeof query === "string");
479
- assert.ok(query.length > 0);
480
- });
481
-
482
- it("should handle messages with tool use", () => {
483
- const message = {
484
- role: "user",
485
- content: [
486
- { type: "text", text: "Search for Python tutorials" },
487
- { type: "tool_use", name: "search" }
488
- ]
489
- };
490
-
491
- const query = retriever.extractQueryFromMessage(message);
492
- assert.ok(typeof query === "string");
493
- });
494
-
495
- it("should handle empty messages", () => {
496
- const message = { role: "user", content: "" };
497
- const query = retriever.extractQueryFromMessage(message);
498
- assert.strictEqual(query, "");
499
- });
500
-
501
- it("should extract key terms from longer messages", () => {
502
- const message = {
503
- role: "user",
504
- content: "I'm working on a new feature that requires authentication. Can you help me implement JWT tokens?"
505
- };
506
-
507
- const query = retriever.extractQueryFromMessage(message);
508
- assert.ok(query.includes("authentication") || query.includes("JWT"));
509
- });
510
- });
511
-
512
- describe("Performance", () => {
513
- it("should retrieve memories within 50ms target", () => {
514
- // Create more memories for realistic test
515
- for (let i = 0; i < 50; i++) {
516
- store.createMemory({
517
- content: `Test memory ${i} about various topics`,
518
- type: "fact",
519
- importance: Math.random()
520
- });
521
- }
522
-
523
- const start = Date.now();
524
- const memories = retriever.retrieveRelevantMemories("test topics", { limit: 10 });
525
- const duration = Date.now() - start;
526
-
527
- assert.ok(memories.length > 0);
528
- assert.ok(duration < 50, `Retrieval took ${duration}ms, expected < 50ms`);
529
- });
530
-
531
- it("should handle concurrent retrievals", () => {
532
- const queries = [
533
- "Python programming",
534
- "JavaScript frameworks",
535
- "database connections",
536
- "authentication security"
537
- ];
538
-
539
- const results = queries.map(q =>
540
- retriever.retrieveRelevantMemories(q, { limit: 5 })
541
- );
542
-
543
- results.forEach(memories => {
544
- assert.ok(Array.isArray(memories));
545
- });
546
- });
547
- });
548
-
549
- describe("Edge Cases", () => {
550
- it("should handle very long queries", () => {
551
- const longQuery = "Python ".repeat(100);
552
- assert.doesNotThrow(() => {
553
- retriever.retrieveRelevantMemories(longQuery, { limit: 5 });
554
- });
555
- });
556
-
557
- it("should handle special characters in queries", () => {
558
- assert.doesNotThrow(() => {
559
- retriever.retrieveRelevantMemories("@angular/core ^16.0.0", { limit: 5 });
560
- });
561
- });
562
-
563
- it("should handle zero limit", () => {
564
- const memories = retriever.retrieveRelevantMemories("test", { limit: 0 });
565
- assert.strictEqual(memories.length, 0);
566
- });
567
-
568
- it("should handle negative weights gracefully", () => {
569
- const memory = {
570
- content: "Test",
571
- importance: 0.5,
572
- createdAt: Date.now()
573
- };
574
-
575
- // Should normalize or clamp weights
576
- assert.doesNotThrow(() => {
577
- retriever.calculateRetrievalScore(memory, "test", {
578
- recencyWeight: -0.5,
579
- importanceWeight: 1.5,
580
- relevanceWeight: 0.5
581
- });
582
- });
583
- });
584
- });
585
- });