@desplega.ai/agent-swarm 1.64.0 → 1.65.0
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/openapi.json +42 -1
- package/package.json +3 -1
- package/src/be/db.ts +18 -290
- package/src/be/embedding.ts +0 -38
- package/src/be/memory/constants.ts +26 -0
- package/src/be/memory/index.ts +22 -0
- package/src/be/memory/providers/openai-embedding.ts +94 -0
- package/src/be/memory/providers/sqlite-store.ts +530 -0
- package/src/be/memory/reranker.ts +59 -0
- package/src/be/memory/types.ts +83 -0
- package/src/be/migrations/036_memory_ttl_staleness.sql +8 -0
- package/src/http/memory.ts +99 -46
- package/src/server.ts +2 -0
- package/src/tests/artifact-sdk.test.ts +2 -1
- package/src/tests/memory-e2e.test.ts +453 -0
- package/src/tests/memory-reranker.test.ts +192 -0
- package/src/tests/memory-store.test.ts +330 -0
- package/src/tests/memory.test.ts +105 -121
- package/src/tests/package-publish.test.ts +47 -0
- package/src/tests/self-improvement.test.ts +18 -19
- package/src/tests/tool-annotations.test.ts +2 -2
- package/src/tools/inject-learning.ts +7 -5
- package/src/tools/memory-delete.ts +89 -0
- package/src/tools/memory-get.ts +2 -2
- package/src/tools/memory-search.ts +13 -7
- package/src/tools/store-progress.ts +12 -11
- package/src/tools/tool-config.ts +1 -0
- package/src/types.ts +3 -0
- package/tsconfig.json +49 -0
package/src/tests/memory.test.ts
CHANGED
|
@@ -1,21 +1,9 @@
|
|
|
1
1
|
import { afterAll, beforeAll, describe, expect, test } from "bun:test";
|
|
2
2
|
import { unlink } from "node:fs/promises";
|
|
3
3
|
import { chunkContent } from "../be/chunking";
|
|
4
|
-
import {
|
|
5
|
-
closeDb,
|
|
6
|
-
createAgent,
|
|
7
|
-
createMemory,
|
|
8
|
-
deleteMemoriesBySourcePath,
|
|
9
|
-
deleteMemory,
|
|
10
|
-
getDb,
|
|
11
|
-
getMemoryById,
|
|
12
|
-
getMemoryStats,
|
|
13
|
-
initDb,
|
|
14
|
-
listMemoriesByAgent,
|
|
15
|
-
searchMemoriesByVector,
|
|
16
|
-
updateMemoryEmbedding,
|
|
17
|
-
} from "../be/db";
|
|
4
|
+
import { closeDb, createAgent, getDb, initDb } from "../be/db";
|
|
18
5
|
import { cosineSimilarity, deserializeEmbedding, serializeEmbedding } from "../be/embedding";
|
|
6
|
+
import { SqliteMemoryStore } from "../be/memory/providers/sqlite-store";
|
|
19
7
|
|
|
20
8
|
const TEST_DB_PATH = "./test-memory.sqlite";
|
|
21
9
|
|
|
@@ -23,6 +11,8 @@ describe("Memory System", () => {
|
|
|
23
11
|
const agentA = "aaaa0000-0000-4000-8000-000000000001";
|
|
24
12
|
const agentB = "bbbb0000-0000-4000-8000-000000000002";
|
|
25
13
|
|
|
14
|
+
let store: SqliteMemoryStore;
|
|
15
|
+
|
|
26
16
|
beforeAll(async () => {
|
|
27
17
|
for (const suffix of ["", "-wal", "-shm"]) {
|
|
28
18
|
try {
|
|
@@ -33,6 +23,7 @@ describe("Memory System", () => {
|
|
|
33
23
|
}
|
|
34
24
|
|
|
35
25
|
initDb(TEST_DB_PATH);
|
|
26
|
+
store = new SqliteMemoryStore();
|
|
36
27
|
|
|
37
28
|
createAgent({ id: agentA, name: "Agent A", isLead: false, status: "idle" });
|
|
38
29
|
createAgent({ id: agentB, name: "Agent B", isLead: true, status: "idle" });
|
|
@@ -212,12 +203,12 @@ describe("Memory System", () => {
|
|
|
212
203
|
});
|
|
213
204
|
|
|
214
205
|
// ==========================================================================
|
|
215
|
-
// DB CRUD tests
|
|
206
|
+
// DB CRUD tests (using SqliteMemoryStore)
|
|
216
207
|
// ==========================================================================
|
|
217
208
|
|
|
218
|
-
describe("createMemory", () => {
|
|
209
|
+
describe("store.store (createMemory)", () => {
|
|
219
210
|
test("creates a memory with all fields", () => {
|
|
220
|
-
const memory =
|
|
211
|
+
const memory = store.store({
|
|
221
212
|
agentId: agentA,
|
|
222
213
|
scope: "agent",
|
|
223
214
|
name: "Test Memory",
|
|
@@ -246,7 +237,8 @@ describe("Memory System", () => {
|
|
|
246
237
|
});
|
|
247
238
|
|
|
248
239
|
test("creates with minimal fields", () => {
|
|
249
|
-
const memory =
|
|
240
|
+
const memory = store.store({
|
|
241
|
+
agentId: null,
|
|
250
242
|
scope: "swarm",
|
|
251
243
|
name: "Minimal",
|
|
252
244
|
content: "Just content",
|
|
@@ -263,9 +255,9 @@ describe("Memory System", () => {
|
|
|
263
255
|
});
|
|
264
256
|
});
|
|
265
257
|
|
|
266
|
-
describe("getMemoryById", () => {
|
|
258
|
+
describe("store.get (getMemoryById)", () => {
|
|
267
259
|
test("returns existing memory", () => {
|
|
268
|
-
const created =
|
|
260
|
+
const created = store.store({
|
|
269
261
|
agentId: agentA,
|
|
270
262
|
scope: "agent",
|
|
271
263
|
name: "Findable",
|
|
@@ -273,19 +265,19 @@ describe("Memory System", () => {
|
|
|
273
265
|
source: "manual",
|
|
274
266
|
});
|
|
275
267
|
|
|
276
|
-
const found =
|
|
268
|
+
const found = store.get(created.id);
|
|
277
269
|
expect(found).not.toBeNull();
|
|
278
270
|
expect(found!.id).toBe(created.id);
|
|
279
271
|
expect(found!.name).toBe("Findable");
|
|
280
272
|
});
|
|
281
273
|
|
|
282
274
|
test("returns null for non-existent ID", () => {
|
|
283
|
-
const found =
|
|
275
|
+
const found = store.get("00000000-0000-0000-0000-000000000000");
|
|
284
276
|
expect(found).toBeNull();
|
|
285
277
|
});
|
|
286
278
|
|
|
287
279
|
test("updates accessedAt on retrieval", () => {
|
|
288
|
-
const created =
|
|
280
|
+
const created = store.store({
|
|
289
281
|
agentId: agentA,
|
|
290
282
|
scope: "agent",
|
|
291
283
|
name: "Access Test",
|
|
@@ -299,16 +291,16 @@ describe("Memory System", () => {
|
|
|
299
291
|
/* spin */
|
|
300
292
|
}
|
|
301
293
|
|
|
302
|
-
const found =
|
|
294
|
+
const found = store.get(created.id);
|
|
303
295
|
expect(found).not.toBeNull();
|
|
304
296
|
// accessedAt should be updated (may or may not differ depending on timing)
|
|
305
297
|
expect(found!.accessedAt).toBeDefined();
|
|
306
298
|
});
|
|
307
299
|
});
|
|
308
300
|
|
|
309
|
-
describe("
|
|
301
|
+
describe("store.updateEmbedding", () => {
|
|
310
302
|
test("stores and retrieves embedding BLOB", () => {
|
|
311
|
-
const memory =
|
|
303
|
+
const memory = store.store({
|
|
312
304
|
agentId: agentA,
|
|
313
305
|
scope: "agent",
|
|
314
306
|
name: "Embedding Test",
|
|
@@ -317,10 +309,9 @@ describe("Memory System", () => {
|
|
|
317
309
|
});
|
|
318
310
|
|
|
319
311
|
const embedding = new Float32Array([0.1, 0.2, 0.3, -0.5]);
|
|
320
|
-
|
|
312
|
+
store.updateEmbedding(memory.id, embedding, "test-model");
|
|
321
313
|
|
|
322
314
|
// Read back the raw row to check embedding
|
|
323
|
-
const { getDb } = require("../be/db");
|
|
324
315
|
const row = getDb()
|
|
325
316
|
.prepare("SELECT embedding FROM agent_memory WHERE id = ?")
|
|
326
317
|
.get(memory.id) as { embedding: Buffer | null };
|
|
@@ -333,7 +324,7 @@ describe("Memory System", () => {
|
|
|
333
324
|
});
|
|
334
325
|
});
|
|
335
326
|
|
|
336
|
-
describe("searchMemoriesByVector", () => {
|
|
327
|
+
describe("store.search (searchMemoriesByVector)", () => {
|
|
337
328
|
const searchAgentId = "cccc0000-0000-4000-8000-000000000003";
|
|
338
329
|
const searchAgentId2 = "dddd0000-0000-4000-8000-000000000004";
|
|
339
330
|
|
|
@@ -353,39 +344,39 @@ describe("Memory System", () => {
|
|
|
353
344
|
|
|
354
345
|
// Create memories with known embeddings
|
|
355
346
|
// Memory 1: agent scope for searchAgentId, embedding [1,0,0]
|
|
356
|
-
const m1 =
|
|
347
|
+
const m1 = store.store({
|
|
357
348
|
agentId: searchAgentId,
|
|
358
349
|
scope: "agent",
|
|
359
350
|
name: "Agent Memory 1",
|
|
360
351
|
content: "Agent-scoped content",
|
|
361
352
|
source: "manual",
|
|
362
353
|
});
|
|
363
|
-
|
|
354
|
+
store.updateEmbedding(m1.id, new Float32Array([1, 0, 0]), "test-model");
|
|
364
355
|
|
|
365
356
|
// Memory 2: swarm scope, embedding [0,1,0]
|
|
366
|
-
const m2 =
|
|
357
|
+
const m2 = store.store({
|
|
367
358
|
agentId: searchAgentId,
|
|
368
359
|
scope: "swarm",
|
|
369
360
|
name: "Swarm Memory 1",
|
|
370
361
|
content: "Swarm-scoped content",
|
|
371
362
|
source: "file_index",
|
|
372
363
|
});
|
|
373
|
-
|
|
364
|
+
store.updateEmbedding(m2.id, new Float32Array([0, 1, 0]), "test-model");
|
|
374
365
|
|
|
375
366
|
// Memory 3: agent scope for OTHER agent, embedding [0,0,1]
|
|
376
|
-
const m3 =
|
|
367
|
+
const m3 = store.store({
|
|
377
368
|
agentId: searchAgentId2,
|
|
378
369
|
scope: "agent",
|
|
379
370
|
name: "Other Agent Memory",
|
|
380
371
|
content: "Other agent's private memory",
|
|
381
372
|
source: "manual",
|
|
382
373
|
});
|
|
383
|
-
|
|
374
|
+
store.updateEmbedding(m3.id, new Float32Array([0, 0, 1]), "test-model");
|
|
384
375
|
});
|
|
385
376
|
|
|
386
377
|
test("worker sees own agent-scoped + swarm memories", () => {
|
|
387
378
|
const query = new Float32Array([1, 0, 0]); // closest to Memory 1
|
|
388
|
-
const results =
|
|
379
|
+
const results = store.search(query, searchAgentId, { isLead: false });
|
|
389
380
|
const names = results.map((r) => r.name);
|
|
390
381
|
|
|
391
382
|
expect(names).toContain("Agent Memory 1");
|
|
@@ -395,7 +386,7 @@ describe("Memory System", () => {
|
|
|
395
386
|
|
|
396
387
|
test("worker does not see other agent's agent-scoped memories", () => {
|
|
397
388
|
const query = new Float32Array([0, 0, 1]); // closest to Memory 3
|
|
398
|
-
const results =
|
|
389
|
+
const results = store.search(query, searchAgentId, { isLead: false });
|
|
399
390
|
const names = results.map((r) => r.name);
|
|
400
391
|
|
|
401
392
|
expect(names).not.toContain("Other Agent Memory");
|
|
@@ -403,7 +394,7 @@ describe("Memory System", () => {
|
|
|
403
394
|
|
|
404
395
|
test("lead sees ALL memories across agents", () => {
|
|
405
396
|
const query = new Float32Array([0, 0, 1]); // closest to Memory 3
|
|
406
|
-
const results =
|
|
397
|
+
const results = store.search(query, searchAgentId, { isLead: true });
|
|
407
398
|
const names = results.map((r) => r.name);
|
|
408
399
|
|
|
409
400
|
expect(names).toContain("Other Agent Memory");
|
|
@@ -413,7 +404,7 @@ describe("Memory System", () => {
|
|
|
413
404
|
|
|
414
405
|
test("results sorted by similarity (highest first)", () => {
|
|
415
406
|
const query = new Float32Array([1, 0, 0]); // identical to Memory 1's embedding
|
|
416
|
-
const results =
|
|
407
|
+
const results = store.search(query, searchAgentId, { isLead: true });
|
|
417
408
|
|
|
418
409
|
expect(results.length).toBeGreaterThan(0);
|
|
419
410
|
expect(results[0].name).toBe("Agent Memory 1");
|
|
@@ -427,11 +418,11 @@ describe("Memory System", () => {
|
|
|
427
418
|
|
|
428
419
|
test("scope filter works", () => {
|
|
429
420
|
const query = new Float32Array([1, 1, 1]);
|
|
430
|
-
const agentOnly =
|
|
421
|
+
const agentOnly = store.search(query, searchAgentId, {
|
|
431
422
|
scope: "agent",
|
|
432
423
|
isLead: false,
|
|
433
424
|
});
|
|
434
|
-
const swarmOnly =
|
|
425
|
+
const swarmOnly = store.search(query, searchAgentId, {
|
|
435
426
|
scope: "swarm",
|
|
436
427
|
isLead: false,
|
|
437
428
|
});
|
|
@@ -446,7 +437,7 @@ describe("Memory System", () => {
|
|
|
446
437
|
|
|
447
438
|
test("source filter works", () => {
|
|
448
439
|
const query = new Float32Array([1, 1, 1]);
|
|
449
|
-
const results =
|
|
440
|
+
const results = store.search(query, searchAgentId, {
|
|
450
441
|
source: "file_index",
|
|
451
442
|
isLead: true,
|
|
452
443
|
});
|
|
@@ -458,7 +449,7 @@ describe("Memory System", () => {
|
|
|
458
449
|
|
|
459
450
|
test("limit works", () => {
|
|
460
451
|
const query = new Float32Array([1, 1, 1]);
|
|
461
|
-
const results =
|
|
452
|
+
const results = store.search(query, searchAgentId, {
|
|
462
453
|
limit: 1,
|
|
463
454
|
isLead: true,
|
|
464
455
|
});
|
|
@@ -466,13 +457,13 @@ describe("Memory System", () => {
|
|
|
466
457
|
});
|
|
467
458
|
});
|
|
468
459
|
|
|
469
|
-
describe("listMemoriesByAgent", () => {
|
|
460
|
+
describe("store.list (listMemoriesByAgent)", () => {
|
|
470
461
|
test("lists agent memories with pagination", () => {
|
|
471
462
|
const listAgent = "eeee0000-0000-4000-8000-000000000005";
|
|
472
463
|
createAgent({ id: listAgent, name: "List Agent", isLead: false, status: "idle" });
|
|
473
464
|
|
|
474
465
|
for (let i = 0; i < 5; i++) {
|
|
475
|
-
|
|
466
|
+
store.store({
|
|
476
467
|
agentId: listAgent,
|
|
477
468
|
scope: "agent",
|
|
478
469
|
name: `List Memory ${i}`,
|
|
@@ -481,17 +472,17 @@ describe("Memory System", () => {
|
|
|
481
472
|
});
|
|
482
473
|
}
|
|
483
474
|
|
|
484
|
-
const page1 =
|
|
475
|
+
const page1 = store.list(listAgent, { scope: "agent", limit: 3, offset: 0 });
|
|
485
476
|
expect(page1.length).toBe(3);
|
|
486
477
|
|
|
487
|
-
const page2 =
|
|
478
|
+
const page2 = store.list(listAgent, { scope: "agent", limit: 3, offset: 3 });
|
|
488
479
|
expect(page2.length).toBe(2);
|
|
489
480
|
});
|
|
490
481
|
});
|
|
491
482
|
|
|
492
|
-
describe("deleteMemory", () => {
|
|
483
|
+
describe("store.delete (deleteMemory)", () => {
|
|
493
484
|
test("deletes existing memory", () => {
|
|
494
|
-
const memory =
|
|
485
|
+
const memory = store.store({
|
|
495
486
|
agentId: agentA,
|
|
496
487
|
scope: "agent",
|
|
497
488
|
name: "To Delete",
|
|
@@ -499,26 +490,26 @@ describe("Memory System", () => {
|
|
|
499
490
|
source: "manual",
|
|
500
491
|
});
|
|
501
492
|
|
|
502
|
-
const deleted =
|
|
493
|
+
const deleted = store.delete(memory.id);
|
|
503
494
|
expect(deleted).toBe(true);
|
|
504
495
|
|
|
505
|
-
const found =
|
|
496
|
+
const found = store.get(memory.id);
|
|
506
497
|
expect(found).toBeNull();
|
|
507
498
|
});
|
|
508
499
|
|
|
509
500
|
test("returns false for non-existent memory", () => {
|
|
510
|
-
const deleted =
|
|
501
|
+
const deleted = store.delete("00000000-0000-0000-0000-000000000000");
|
|
511
502
|
expect(deleted).toBe(false);
|
|
512
503
|
});
|
|
513
504
|
});
|
|
514
505
|
|
|
515
|
-
describe("deleteMemoriesBySourcePath", () => {
|
|
506
|
+
describe("store.deleteBySourcePath (deleteMemoriesBySourcePath)", () => {
|
|
516
507
|
test("deletes all chunks for a source path", () => {
|
|
517
508
|
const path = "/workspace/personal/memory/to-reindex.md";
|
|
518
509
|
|
|
519
510
|
// Create multiple chunks
|
|
520
511
|
for (let i = 0; i < 3; i++) {
|
|
521
|
-
|
|
512
|
+
store.store({
|
|
522
513
|
agentId: agentA,
|
|
523
514
|
scope: "agent",
|
|
524
515
|
name: "Reindex Test",
|
|
@@ -530,35 +521,35 @@ describe("Memory System", () => {
|
|
|
530
521
|
});
|
|
531
522
|
}
|
|
532
523
|
|
|
533
|
-
const deleted =
|
|
524
|
+
const deleted = store.deleteBySourcePath(path, agentA);
|
|
534
525
|
expect(deleted).toBe(3);
|
|
535
526
|
|
|
536
527
|
// Verify they're gone
|
|
537
|
-
const remaining =
|
|
528
|
+
const remaining = store.list(agentA).filter((m) => m.sourcePath === path);
|
|
538
529
|
expect(remaining.length).toBe(0);
|
|
539
530
|
});
|
|
540
531
|
});
|
|
541
532
|
|
|
542
|
-
describe("getMemoryStats", () => {
|
|
533
|
+
describe("store.getStats (getMemoryStats)", () => {
|
|
543
534
|
test("returns correct stats", () => {
|
|
544
535
|
const statsAgent = "ffff0000-0000-4000-8000-000000000006";
|
|
545
536
|
createAgent({ id: statsAgent, name: "Stats Agent", isLead: false, status: "idle" });
|
|
546
537
|
|
|
547
|
-
|
|
538
|
+
store.store({
|
|
548
539
|
agentId: statsAgent,
|
|
549
540
|
scope: "agent",
|
|
550
541
|
name: "Stat 1",
|
|
551
542
|
content: "Content",
|
|
552
543
|
source: "manual",
|
|
553
544
|
});
|
|
554
|
-
|
|
545
|
+
store.store({
|
|
555
546
|
agentId: statsAgent,
|
|
556
547
|
scope: "swarm",
|
|
557
548
|
name: "Stat 2",
|
|
558
549
|
content: "Content",
|
|
559
550
|
source: "file_index",
|
|
560
551
|
});
|
|
561
|
-
|
|
552
|
+
store.store({
|
|
562
553
|
agentId: statsAgent,
|
|
563
554
|
scope: "agent",
|
|
564
555
|
name: "Stat 3",
|
|
@@ -566,12 +557,14 @@ describe("Memory System", () => {
|
|
|
566
557
|
source: "manual",
|
|
567
558
|
});
|
|
568
559
|
|
|
569
|
-
const stats =
|
|
560
|
+
const stats = store.getStats(statsAgent);
|
|
570
561
|
expect(stats.total).toBe(3);
|
|
571
562
|
expect(stats.bySource.manual).toBe(2);
|
|
572
563
|
expect(stats.bySource.file_index).toBe(1);
|
|
573
564
|
expect(stats.byScope.agent).toBe(2);
|
|
574
565
|
expect(stats.byScope.swarm).toBe(1);
|
|
566
|
+
expect(stats.withEmbeddings).toBe(0);
|
|
567
|
+
expect(stats.expired).toBe(0);
|
|
575
568
|
});
|
|
576
569
|
});
|
|
577
570
|
|
|
@@ -601,26 +594,21 @@ describe("Memory System", () => {
|
|
|
601
594
|
},
|
|
602
595
|
];
|
|
603
596
|
|
|
604
|
-
const
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
return ids;
|
|
620
|
-
})();
|
|
621
|
-
|
|
622
|
-
expect(memoryIds.length).toBe(1);
|
|
623
|
-
const memory = getMemoryById(memoryIds[0]!);
|
|
597
|
+
const memories = store.storeBatch(
|
|
598
|
+
finalChunks.map((chunk) => ({
|
|
599
|
+
agentId: ingestAgent,
|
|
600
|
+
content: chunk.content,
|
|
601
|
+
name: "ingest-test",
|
|
602
|
+
scope: "agent" as const,
|
|
603
|
+
source: "file_index" as const,
|
|
604
|
+
sourcePath: "/workspace/personal/memory/ingest-test.md",
|
|
605
|
+
chunkIndex: chunk.chunkIndex,
|
|
606
|
+
totalChunks: chunk.totalChunks,
|
|
607
|
+
})),
|
|
608
|
+
);
|
|
609
|
+
|
|
610
|
+
expect(memories.length).toBe(1);
|
|
611
|
+
const memory = store.get(memories[0]!.id);
|
|
624
612
|
expect(memory).not.toBeNull();
|
|
625
613
|
expect(memory!.source).toBe("file_index");
|
|
626
614
|
expect(memory!.sourcePath).toBe("/workspace/personal/memory/ingest-test.md");
|
|
@@ -630,7 +618,7 @@ describe("Memory System", () => {
|
|
|
630
618
|
const path = "/workspace/personal/memory/dedup-test.md";
|
|
631
619
|
|
|
632
620
|
// First indexing
|
|
633
|
-
const m1 =
|
|
621
|
+
const m1 = store.store({
|
|
634
622
|
agentId: ingestAgent,
|
|
635
623
|
content: "Original content",
|
|
636
624
|
name: "dedup-test",
|
|
@@ -639,26 +627,24 @@ describe("Memory System", () => {
|
|
|
639
627
|
sourcePath: path,
|
|
640
628
|
});
|
|
641
629
|
|
|
642
|
-
// Re-index: delete old + create new
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
});
|
|
653
|
-
})();
|
|
630
|
+
// Re-index: delete old + create new
|
|
631
|
+
store.deleteBySourcePath(path, ingestAgent);
|
|
632
|
+
store.store({
|
|
633
|
+
agentId: ingestAgent,
|
|
634
|
+
content: "Updated content",
|
|
635
|
+
name: "dedup-test",
|
|
636
|
+
scope: "agent",
|
|
637
|
+
source: "file_index",
|
|
638
|
+
sourcePath: path,
|
|
639
|
+
});
|
|
654
640
|
|
|
655
641
|
// Old memory should be gone
|
|
656
|
-
expect(
|
|
642
|
+
expect(store.get(m1.id)).toBeNull();
|
|
657
643
|
|
|
658
644
|
// New memory should exist
|
|
659
|
-
const memories =
|
|
660
|
-
(
|
|
661
|
-
|
|
645
|
+
const memories = store
|
|
646
|
+
.list(ingestAgent, { scope: "agent" })
|
|
647
|
+
.filter((m) => m.sourcePath === path);
|
|
662
648
|
expect(memories.length).toBe(1);
|
|
663
649
|
expect(memories[0]!.content).toBe("Updated content");
|
|
664
650
|
});
|
|
@@ -670,25 +656,23 @@ describe("Memory System", () => {
|
|
|
670
656
|
const chunks = chunkContent(longContent);
|
|
671
657
|
expect(chunks.length).toBeGreaterThan(1);
|
|
672
658
|
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
});
|
|
686
|
-
}
|
|
687
|
-
})();
|
|
688
|
-
|
|
689
|
-
const memories = listMemoriesByAgent(ingestAgent, { scope: "agent" }).filter(
|
|
690
|
-
(m) => m.sourcePath === path,
|
|
659
|
+
store.deleteBySourcePath(path, ingestAgent);
|
|
660
|
+
store.storeBatch(
|
|
661
|
+
chunks.map((chunk) => ({
|
|
662
|
+
agentId: ingestAgent,
|
|
663
|
+
content: chunk.content,
|
|
664
|
+
name: "chunked-test",
|
|
665
|
+
scope: "agent" as const,
|
|
666
|
+
source: "file_index" as const,
|
|
667
|
+
sourcePath: path,
|
|
668
|
+
chunkIndex: chunk.chunkIndex,
|
|
669
|
+
totalChunks: chunk.totalChunks,
|
|
670
|
+
})),
|
|
691
671
|
);
|
|
672
|
+
|
|
673
|
+
const memories = store
|
|
674
|
+
.list(ingestAgent, { scope: "agent" })
|
|
675
|
+
.filter((m) => m.sourcePath === path);
|
|
692
676
|
expect(memories.length).toBe(chunks.length);
|
|
693
677
|
// Verify chunk metadata
|
|
694
678
|
for (const m of memories) {
|
|
@@ -696,8 +680,8 @@ describe("Memory System", () => {
|
|
|
696
680
|
}
|
|
697
681
|
});
|
|
698
682
|
|
|
699
|
-
test("memory created without
|
|
700
|
-
const memory =
|
|
683
|
+
test("memory created without embedding has null embedding in DB", () => {
|
|
684
|
+
const memory = store.store({
|
|
701
685
|
agentId: ingestAgent,
|
|
702
686
|
content: "No embedding needed",
|
|
703
687
|
name: "no-embed",
|
|
@@ -711,8 +695,8 @@ describe("Memory System", () => {
|
|
|
711
695
|
expect(row.embedding).toBeNull();
|
|
712
696
|
});
|
|
713
697
|
|
|
714
|
-
test("
|
|
715
|
-
const memory =
|
|
698
|
+
test("store.updateEmbedding stores and retrieves correctly", () => {
|
|
699
|
+
const memory = store.store({
|
|
716
700
|
agentId: ingestAgent,
|
|
717
701
|
content: "Embed me",
|
|
718
702
|
name: "embed-update",
|
|
@@ -721,7 +705,7 @@ describe("Memory System", () => {
|
|
|
721
705
|
});
|
|
722
706
|
|
|
723
707
|
const embedding = new Float32Array([0.5, -0.3, 0.8]);
|
|
724
|
-
|
|
708
|
+
store.updateEmbedding(memory.id, embedding, "test-model");
|
|
725
709
|
|
|
726
710
|
const row = getDb()
|
|
727
711
|
.prepare("SELECT embedding FROM agent_memory WHERE id = ?")
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { afterAll, describe, expect, setDefaultTimeout, test } from "bun:test";
|
|
2
|
+
import { execSync } from "node:child_process";
|
|
3
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
const REPO_ROOT = join(import.meta.dir, "../..");
|
|
8
|
+
const tempDir = mkdtempSync(join(tmpdir(), "agent-swarm-pack-"));
|
|
9
|
+
|
|
10
|
+
setDefaultTimeout(30_000);
|
|
11
|
+
|
|
12
|
+
afterAll(() => {
|
|
13
|
+
rmSync(tempDir, { force: true, recursive: true });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe("published package", () => {
|
|
17
|
+
test("version command works from an unpacked tarball", () => {
|
|
18
|
+
const tarballPath = join(tempDir, "agent-swarm.tgz");
|
|
19
|
+
const unpackDir = join(tempDir, "unpacked");
|
|
20
|
+
|
|
21
|
+
execSync(`bun pm pack --filename ${JSON.stringify(tarballPath)}`, {
|
|
22
|
+
cwd: REPO_ROOT,
|
|
23
|
+
stdio: "pipe",
|
|
24
|
+
});
|
|
25
|
+
execSync(
|
|
26
|
+
`mkdir -p ${JSON.stringify(unpackDir)} && tar -xzf ${JSON.stringify(tarballPath)} -C ${JSON.stringify(unpackDir)}`,
|
|
27
|
+
{
|
|
28
|
+
cwd: REPO_ROOT,
|
|
29
|
+
stdio: "pipe",
|
|
30
|
+
},
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// Symlink repo node_modules so top-level imports resolve without a network install
|
|
34
|
+
execSync(
|
|
35
|
+
`ln -s ${JSON.stringify(join(REPO_ROOT, "node_modules"))} ${JSON.stringify(join(unpackDir, "package", "node_modules"))}`,
|
|
36
|
+
{ stdio: "pipe" },
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
const output = execSync(`bun ./package/src/cli.tsx version`, {
|
|
40
|
+
cwd: unpackDir,
|
|
41
|
+
encoding: "utf-8",
|
|
42
|
+
stdio: "pipe",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
expect(output).toContain("agent-swarm v");
|
|
46
|
+
});
|
|
47
|
+
});
|