lynkr 8.0.0 → 8.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 (102) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/src/api/openai-router.js +34 -2
  4. package/src/clients/standard-tools.js +23 -0
  5. package/src/config/index.js +20 -0
  6. package/src/orchestrator/index.js +2 -2
  7. package/src/server.js +2 -12
  8. package/src/tools/index.js +4 -0
  9. package/src/tools/lazy-loader.js +7 -0
  10. package/src/tools/tinyfish.js +358 -0
  11. package/src/tools/truncate.js +1 -0
  12. package/.github/FUNDING.yml +0 -15
  13. package/.github/workflows/README.md +0 -215
  14. package/.github/workflows/ci.yml +0 -69
  15. package/.github/workflows/index.yml +0 -62
  16. package/.github/workflows/web-tools-tests.yml +0 -56
  17. package/CITATIONS.bib +0 -6
  18. package/DEPLOYMENT.md +0 -1001
  19. package/LYNKR-TUI-PLAN.md +0 -984
  20. package/PERFORMANCE-REPORT.md +0 -866
  21. package/PLAN-per-client-model-routing.md +0 -252
  22. package/docs/42642f749da6234f41b6b425c3bb07c9.txt +0 -1
  23. package/docs/BingSiteAuth.xml +0 -4
  24. package/docs/docs-style.css +0 -478
  25. package/docs/docs.html +0 -198
  26. package/docs/google5be250e608e6da39.html +0 -1
  27. package/docs/index.html +0 -577
  28. package/docs/index.md +0 -584
  29. package/docs/robots.txt +0 -4
  30. package/docs/sitemap.xml +0 -44
  31. package/docs/style.css +0 -1223
  32. package/docs/toon-integration-spec.md +0 -130
  33. package/documentation/README.md +0 -101
  34. package/documentation/api.md +0 -806
  35. package/documentation/claude-code-cli.md +0 -679
  36. package/documentation/codex-cli.md +0 -397
  37. package/documentation/contributing.md +0 -571
  38. package/documentation/cursor-integration.md +0 -734
  39. package/documentation/docker.md +0 -874
  40. package/documentation/embeddings.md +0 -762
  41. package/documentation/faq.md +0 -713
  42. package/documentation/features.md +0 -403
  43. package/documentation/headroom.md +0 -519
  44. package/documentation/installation.md +0 -758
  45. package/documentation/memory-system.md +0 -476
  46. package/documentation/production.md +0 -636
  47. package/documentation/providers.md +0 -1009
  48. package/documentation/routing.md +0 -476
  49. package/documentation/testing.md +0 -629
  50. package/documentation/token-optimization.md +0 -325
  51. package/documentation/tools.md +0 -697
  52. package/documentation/troubleshooting.md +0 -969
  53. package/final-test.js +0 -33
  54. package/headroom-sidecar/config.py +0 -93
  55. package/headroom-sidecar/requirements.txt +0 -14
  56. package/headroom-sidecar/server.py +0 -451
  57. package/monitor-agents.sh +0 -31
  58. package/scripts/audit-log-reader.js +0 -399
  59. package/scripts/compact-dictionary.js +0 -204
  60. package/scripts/test-deduplication.js +0 -448
  61. package/src/db/database.sqlite +0 -0
  62. package/te +0 -11622
  63. package/test/README.md +0 -212
  64. package/test/azure-openai-config.test.js +0 -213
  65. package/test/azure-openai-error-resilience.test.js +0 -238
  66. package/test/azure-openai-format-conversion.test.js +0 -354
  67. package/test/azure-openai-integration.test.js +0 -287
  68. package/test/azure-openai-routing.test.js +0 -175
  69. package/test/azure-openai-streaming.test.js +0 -171
  70. package/test/bedrock-integration.test.js +0 -457
  71. package/test/comprehensive-test-suite.js +0 -928
  72. package/test/config-validation.test.js +0 -207
  73. package/test/cursor-integration.test.js +0 -484
  74. package/test/format-conversion.test.js +0 -578
  75. package/test/hybrid-routing-integration.test.js +0 -269
  76. package/test/hybrid-routing-performance.test.js +0 -428
  77. package/test/llamacpp-integration.test.js +0 -882
  78. package/test/lmstudio-integration.test.js +0 -347
  79. package/test/memory/extractor.test.js +0 -398
  80. package/test/memory/retriever.test.js +0 -613
  81. package/test/memory/retriever.test.js.bak +0 -585
  82. package/test/memory/search.test.js +0 -537
  83. package/test/memory/search.test.js.bak +0 -389
  84. package/test/memory/store.test.js +0 -344
  85. package/test/memory/store.test.js.bak +0 -312
  86. package/test/memory/surprise.test.js +0 -300
  87. package/test/memory-performance.test.js +0 -472
  88. package/test/openai-integration.test.js +0 -683
  89. package/test/openrouter-error-resilience.test.js +0 -418
  90. package/test/passthrough-mode.test.js +0 -385
  91. package/test/performance-benchmark.js +0 -351
  92. package/test/performance-tests.js +0 -528
  93. package/test/routing.test.js +0 -225
  94. package/test/toon-compression.test.js +0 -131
  95. package/test/web-tools.test.js +0 -329
  96. package/test-agents-simple.js +0 -43
  97. package/test-cli-connection.sh +0 -33
  98. package/test-learning-unit.js +0 -126
  99. package/test-learning.js +0 -112
  100. package/test-parallel-agents.sh +0 -124
  101. package/test-parallel-direct.js +0 -155
  102. 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
- });