forked from Lilly-Protocol/agentlily-runtime
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmemory-store.test.ts
More file actions
105 lines (96 loc) · 3.44 KB
/
Copy pathmemory-store.test.ts
File metadata and controls
105 lines (96 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import fc from "fast-check";
import { describe, expect, it } from "vitest";
import { InMemoryMemoryStore, type MemoryEntry } from "../src/index.js";
const AGENT_IDS = [
"agent-alpha",
"agent-beta",
"agent-gamma",
"agent-delta"
] as const;
const entryArb: fc.Arbitrary<MemoryEntry> = fc.record({
agentId: fc.constantFrom(...AGENT_IDS),
taskId: fc.string({ maxLength: 32 }),
input: fc.string({ maxLength: 64 }),
output: fc.oneof(fc.string({ maxLength: 64 }), fc.integer(), fc.boolean()),
recordedAt: fc
.date()
.filter((date) => !Number.isNaN(date.getTime()))
.map((date) => date.toISOString())
});
describe("InMemoryMemoryStore property-based invariants", () => {
it("listByAgent returns exactly the appended entries for the agent, in append order", async () => {
await fc.assert(
fc.asyncProperty(
fc.array(entryArb, { maxLength: 150 }),
fc.constantFrom(...AGENT_IDS),
async (entries, probeAgent) => {
const store = new InMemoryMemoryStore();
for (const entry of entries) {
await store.append(entry);
}
const actual = await store.listByAgent(probeAgent);
const expected = entries.filter(
(entry) => entry.agentId === probeAgent
);
// Per-agent filter correctness: entries from other agents never leak in.
expect(actual.every((entry) => entry.agentId === probeAgent)).toBe(
true
);
// Append-order invariant: results keep the relative append sequence.
expect(actual).toEqual(expected);
}
),
{ numRuns: 100 }
);
});
it("later appends extend earlier snapshots without reordering them", async () => {
await fc.assert(
fc.asyncProperty(
fc.array(entryArb, { maxLength: 120 }),
fc.constantFrom(...AGENT_IDS),
async (entries, probeAgent) => {
const store = new InMemoryMemoryStore();
const splitAt = Math.floor(entries.length / 2);
for (const entry of entries.slice(0, splitAt)) {
await store.append(entry);
}
const snapshot = await store.listByAgent(probeAgent);
expect(snapshot).toEqual(
entries
.slice(0, splitAt)
.filter((entry) => entry.agentId === probeAgent)
);
for (const entry of entries.slice(splitAt)) {
await store.append(entry);
}
const later = await store.listByAgent(probeAgent);
// Previously observed entries stay in front, in the same relative order.
expect(later.slice(0, snapshot.length)).toEqual(snapshot);
expect(later).toEqual(
entries.filter((entry) => entry.agentId === probeAgent)
);
}
),
{ numRuns: 100 }
);
});
it("returns an empty list for agents with no entries, even after appends", async () => {
await fc.assert(
fc.asyncProperty(
fc.array(entryArb, { maxLength: 80 }),
async (entries) => {
const store = new InMemoryMemoryStore();
for (const entry of entries) {
await store.append(entry);
}
const used = new Set(entries.map((entry) => entry.agentId));
const unused = AGENT_IDS.find((id) => !used.has(id));
if (unused !== undefined) {
expect(await store.listByAgent(unused)).toEqual([]);
}
}
),
{ numRuns: 50 }
);
});
});