@aitytech/agentkits-memory 1.0.1 → 2.0.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/README.md +54 -5
- package/dist/better-sqlite3-backend.d.ts +192 -0
- package/dist/better-sqlite3-backend.d.ts.map +1 -0
- package/dist/better-sqlite3-backend.js +801 -0
- package/dist/better-sqlite3-backend.js.map +1 -0
- package/dist/cli/save.js +0 -0
- package/dist/cli/setup.d.ts +6 -2
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +289 -42
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/viewer.js +25 -56
- package/dist/cli/viewer.js.map +1 -1
- package/dist/cli/web-viewer.d.ts +2 -1
- package/dist/cli/web-viewer.d.ts.map +1 -1
- package/dist/cli/web-viewer.js +791 -141
- package/dist/cli/web-viewer.js.map +1 -1
- package/dist/embeddings/embedding-cache.d.ts +131 -0
- package/dist/embeddings/embedding-cache.d.ts.map +1 -0
- package/dist/embeddings/embedding-cache.js +217 -0
- package/dist/embeddings/embedding-cache.js.map +1 -0
- package/dist/embeddings/index.d.ts +11 -0
- package/dist/embeddings/index.d.ts.map +1 -0
- package/dist/embeddings/index.js +11 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/embeddings/local-embeddings.d.ts +140 -0
- package/dist/embeddings/local-embeddings.d.ts.map +1 -0
- package/dist/embeddings/local-embeddings.js +293 -0
- package/dist/embeddings/local-embeddings.js.map +1 -0
- package/dist/hooks/context.d.ts +6 -1
- package/dist/hooks/context.d.ts.map +1 -1
- package/dist/hooks/context.js +12 -2
- package/dist/hooks/context.js.map +1 -1
- package/dist/hooks/observation.d.ts +6 -1
- package/dist/hooks/observation.d.ts.map +1 -1
- package/dist/hooks/observation.js +12 -2
- package/dist/hooks/observation.js.map +1 -1
- package/dist/hooks/service.d.ts +1 -6
- package/dist/hooks/service.d.ts.map +1 -1
- package/dist/hooks/service.js +33 -85
- package/dist/hooks/service.js.map +1 -1
- package/dist/hooks/session-init.d.ts +6 -1
- package/dist/hooks/session-init.d.ts.map +1 -1
- package/dist/hooks/session-init.js +12 -2
- package/dist/hooks/session-init.js.map +1 -1
- package/dist/hooks/summarize.d.ts +6 -1
- package/dist/hooks/summarize.d.ts.map +1 -1
- package/dist/hooks/summarize.js +12 -2
- package/dist/hooks/summarize.js.map +1 -1
- package/dist/index.d.ts +10 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +172 -94
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +17 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/migration.js +3 -3
- package/dist/migration.js.map +1 -1
- package/dist/search/hybrid-search.d.ts +262 -0
- package/dist/search/hybrid-search.d.ts.map +1 -0
- package/dist/search/hybrid-search.js +688 -0
- package/dist/search/hybrid-search.js.map +1 -0
- package/dist/search/index.d.ts +13 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +13 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/token-economics.d.ts +161 -0
- package/dist/search/token-economics.d.ts.map +1 -0
- package/dist/search/token-economics.js +239 -0
- package/dist/search/token-economics.js.map +1 -0
- package/dist/types.d.ts +0 -68
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +5 -3
- package/src/__tests__/better-sqlite3-backend.test.ts +1466 -0
- package/src/__tests__/cache-manager.test.ts +499 -0
- package/src/__tests__/embedding-integration.test.ts +481 -0
- package/src/__tests__/hnsw-index.test.ts +727 -0
- package/src/__tests__/index.test.ts +432 -0
- package/src/better-sqlite3-backend.ts +1000 -0
- package/src/cli/setup.ts +358 -47
- package/src/cli/viewer.ts +28 -63
- package/src/cli/web-viewer.ts +936 -182
- package/src/embeddings/__tests__/embedding-cache.test.ts +269 -0
- package/src/embeddings/__tests__/local-embeddings.test.ts +495 -0
- package/src/embeddings/embedding-cache.ts +318 -0
- package/src/embeddings/index.ts +20 -0
- package/src/embeddings/local-embeddings.ts +419 -0
- package/src/hooks/__tests__/handlers.test.ts +58 -17
- package/src/hooks/__tests__/integration.test.ts +77 -26
- package/src/hooks/context.ts +13 -2
- package/src/hooks/observation.ts +13 -2
- package/src/hooks/service.ts +39 -100
- package/src/hooks/session-init.ts +13 -2
- package/src/hooks/summarize.ts +13 -2
- package/src/index.ts +210 -116
- package/src/mcp/server.ts +20 -3
- package/src/search/__tests__/hybrid-search.test.ts +669 -0
- package/src/search/__tests__/token-economics.test.ts +276 -0
- package/src/search/hybrid-search.ts +968 -0
- package/src/search/index.ts +29 -0
- package/src/search/token-economics.ts +367 -0
- package/src/types.ts +0 -96
- package/src/__tests__/sqljs-backend.test.ts +0 -410
- package/src/migration.ts +0 -574
- package/src/sql.js.d.ts +0 -70
- package/src/sqljs-backend.ts +0 -789
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import {
|
|
3
|
+
TokenEconomicsTracker,
|
|
4
|
+
createTokenEconomicsTracker,
|
|
5
|
+
} from '../token-economics.js';
|
|
6
|
+
|
|
7
|
+
describe('TokenEconomicsTracker', () => {
|
|
8
|
+
let tracker: TokenEconomicsTracker;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
tracker = new TokenEconomicsTracker();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
describe('token estimation', () => {
|
|
15
|
+
it('should estimate tokens (~4 chars per token)', () => {
|
|
16
|
+
const text = 'This is a test'; // 14 chars
|
|
17
|
+
const tokens = tracker.estimateTokens(text);
|
|
18
|
+
expect(tokens).toBe(4); // ceil(14/4) = 4
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should handle empty string', () => {
|
|
22
|
+
expect(tracker.estimateTokens('')).toBe(0);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('should handle long text', () => {
|
|
26
|
+
const text = 'a'.repeat(1000);
|
|
27
|
+
expect(tracker.estimateTokens(text)).toBe(250);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('recording creation', () => {
|
|
32
|
+
it('should record memory creation', () => {
|
|
33
|
+
tracker.recordCreation('entry1', 'Test content here');
|
|
34
|
+
|
|
35
|
+
const stats = tracker.getStats();
|
|
36
|
+
expect(stats.totalObservations).toBe(1);
|
|
37
|
+
expect(stats.totalDiscoveryTokens).toBeGreaterThan(0);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should track multiple creations', () => {
|
|
41
|
+
tracker.recordCreation('entry1', 'First content');
|
|
42
|
+
tracker.recordCreation('entry2', 'Second content');
|
|
43
|
+
tracker.recordCreation('entry3', 'Third content');
|
|
44
|
+
|
|
45
|
+
const stats = tracker.getStats();
|
|
46
|
+
expect(stats.totalObservations).toBe(3);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should track per-entry metrics', () => {
|
|
50
|
+
tracker.recordCreation('entry1', 'Test content');
|
|
51
|
+
|
|
52
|
+
const metrics = tracker.getEntryMetrics('entry1');
|
|
53
|
+
expect(metrics.length).toBe(1);
|
|
54
|
+
expect(metrics[0].entryId).toBe('entry1');
|
|
55
|
+
expect(metrics[0].discoveryTokens).toBeGreaterThan(0);
|
|
56
|
+
expect(metrics[0].accessCount).toBe(0);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('recording retrieval', () => {
|
|
61
|
+
it('should record memory retrieval', () => {
|
|
62
|
+
tracker.recordCreation('entry1', 'Test content');
|
|
63
|
+
tracker.recordRetrieval('entry1', 'Test content');
|
|
64
|
+
|
|
65
|
+
const stats = tracker.getStats();
|
|
66
|
+
expect(stats.totalReadTokens).toBeGreaterThan(0);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should update access count', () => {
|
|
70
|
+
tracker.recordCreation('entry1', 'Test content');
|
|
71
|
+
tracker.recordRetrieval('entry1', 'Test content');
|
|
72
|
+
tracker.recordRetrieval('entry1', 'Test content');
|
|
73
|
+
|
|
74
|
+
const metrics = tracker.getEntryMetrics('entry1');
|
|
75
|
+
expect(metrics[0].accessCount).toBe(2);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should calculate value score', () => {
|
|
79
|
+
tracker.recordCreation('entry1', 'A'.repeat(100)); // 25 discovery tokens
|
|
80
|
+
tracker.recordRetrieval('entry1', 'B'.repeat(40)); // 10 read tokens
|
|
81
|
+
|
|
82
|
+
const metrics = tracker.getEntryMetrics('entry1');
|
|
83
|
+
// savings = 25 - 10 = 15
|
|
84
|
+
// valueScore = 15 * 1 = 15
|
|
85
|
+
expect(metrics[0].savings).toBe(15);
|
|
86
|
+
expect(metrics[0].valueScore).toBe(15);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('statistics', () => {
|
|
91
|
+
it('should calculate savings', () => {
|
|
92
|
+
tracker.recordCreation('entry1', 'A'.repeat(100));
|
|
93
|
+
tracker.recordRetrieval('entry1', 'B'.repeat(40));
|
|
94
|
+
|
|
95
|
+
const stats = tracker.getStats();
|
|
96
|
+
expect(stats.totalSavings).toBe(15); // 25 - 10
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should calculate savings percentage', () => {
|
|
100
|
+
tracker.recordCreation('entry1', 'A'.repeat(100));
|
|
101
|
+
tracker.recordRetrieval('entry1', 'B'.repeat(40));
|
|
102
|
+
|
|
103
|
+
const stats = tracker.getStats();
|
|
104
|
+
// (25 - 10) / 25 * 100 = 60%
|
|
105
|
+
expect(stats.savingsPercent).toBe(60);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should handle zero discovery tokens', () => {
|
|
109
|
+
const stats = tracker.getStats();
|
|
110
|
+
expect(stats.savingsPercent).toBe(0);
|
|
111
|
+
expect(stats.avgTokensPerObservation).toBe(0);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('should calculate average tokens per observation', () => {
|
|
115
|
+
tracker.recordCreation('entry1', 'A'.repeat(40)); // 10 tokens
|
|
116
|
+
tracker.recordCreation('entry2', 'B'.repeat(80)); // 20 tokens
|
|
117
|
+
|
|
118
|
+
const stats = tracker.getStats();
|
|
119
|
+
expect(stats.avgTokensPerObservation).toBe(15); // (10 + 20) / 2
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
describe('top/low value entries', () => {
|
|
124
|
+
beforeEach(() => {
|
|
125
|
+
// Create entries with different value scores
|
|
126
|
+
tracker.recordCreation('high-value', 'A'.repeat(200));
|
|
127
|
+
tracker.recordRetrieval('high-value', 'B'.repeat(40));
|
|
128
|
+
tracker.recordRetrieval('high-value', 'B'.repeat(40));
|
|
129
|
+
tracker.recordRetrieval('high-value', 'B'.repeat(40));
|
|
130
|
+
|
|
131
|
+
tracker.recordCreation('low-value', 'A'.repeat(40));
|
|
132
|
+
// No retrievals - never accessed
|
|
133
|
+
|
|
134
|
+
tracker.recordCreation('medium-value', 'A'.repeat(100));
|
|
135
|
+
tracker.recordRetrieval('medium-value', 'B'.repeat(40));
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should return top value entries', () => {
|
|
139
|
+
const top = tracker.getTopValueEntries(2);
|
|
140
|
+
|
|
141
|
+
expect(top.length).toBe(2);
|
|
142
|
+
expect(top[0].entryId).toBe('high-value');
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should return low value entries', () => {
|
|
146
|
+
const low = tracker.getLowValueEntries(2);
|
|
147
|
+
|
|
148
|
+
expect(low.length).toBeGreaterThanOrEqual(1);
|
|
149
|
+
// low-value has 0 access count
|
|
150
|
+
expect(low.some((e) => e.entryId === 'low-value')).toBe(true);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe('session tracking', () => {
|
|
155
|
+
it('should track session input tokens', () => {
|
|
156
|
+
tracker.recordSessionInput('session1', 500);
|
|
157
|
+
|
|
158
|
+
const summary = tracker.getSessionSummary('session1');
|
|
159
|
+
expect(summary).toBeDefined();
|
|
160
|
+
expect(summary?.inputTokens).toBe(500);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should track session recalls', () => {
|
|
164
|
+
tracker.recordCreation('entry1', 'Test content');
|
|
165
|
+
tracker.recordRetrieval('entry1', 'Test content', 'session1');
|
|
166
|
+
|
|
167
|
+
const summary = tracker.getSessionSummary('session1');
|
|
168
|
+
expect(summary).toBeDefined();
|
|
169
|
+
expect(summary?.memoriesRecalled).toBe(1);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should get all session summaries', () => {
|
|
173
|
+
tracker.recordSessionInput('session1', 100);
|
|
174
|
+
tracker.recordSessionInput('session2', 200);
|
|
175
|
+
|
|
176
|
+
const summaries = tracker.getAllSessionSummaries();
|
|
177
|
+
expect(summaries.length).toBe(2);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe('export/import', () => {
|
|
182
|
+
it('should export metrics', () => {
|
|
183
|
+
tracker.recordCreation('entry1', 'Test content');
|
|
184
|
+
tracker.recordRetrieval('entry1', 'Test content');
|
|
185
|
+
|
|
186
|
+
const exported = tracker.export();
|
|
187
|
+
|
|
188
|
+
expect(exported.stats).toBeDefined();
|
|
189
|
+
expect(exported.entries).toBeDefined();
|
|
190
|
+
expect(exported.entries.length).toBe(1);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
it('should import metrics', () => {
|
|
194
|
+
const data = {
|
|
195
|
+
entries: [
|
|
196
|
+
{
|
|
197
|
+
entryId: 'imported1',
|
|
198
|
+
discoveryTokens: 100,
|
|
199
|
+
readTokens: 50,
|
|
200
|
+
savings: 50,
|
|
201
|
+
accessCount: 5,
|
|
202
|
+
valueScore: 250,
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
tracker.import(data);
|
|
208
|
+
|
|
209
|
+
const metrics = tracker.getEntryMetrics('imported1');
|
|
210
|
+
expect(metrics.length).toBe(1);
|
|
211
|
+
expect(metrics[0].discoveryTokens).toBe(100);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('reset', () => {
|
|
216
|
+
it('should reset all metrics', () => {
|
|
217
|
+
tracker.recordCreation('entry1', 'Test content');
|
|
218
|
+
tracker.recordRetrieval('entry1', 'Test content');
|
|
219
|
+
|
|
220
|
+
tracker.reset();
|
|
221
|
+
|
|
222
|
+
const stats = tracker.getStats();
|
|
223
|
+
expect(stats.totalObservations).toBe(0);
|
|
224
|
+
expect(stats.totalDiscoveryTokens).toBe(0);
|
|
225
|
+
expect(stats.totalReadTokens).toBe(0);
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
describe('formatStats', () => {
|
|
230
|
+
it('should format stats for display', () => {
|
|
231
|
+
tracker.recordCreation('entry1', 'Test content for display');
|
|
232
|
+
|
|
233
|
+
const formatted = tracker.formatStats();
|
|
234
|
+
|
|
235
|
+
expect(formatted).toContain('Token Economics');
|
|
236
|
+
expect(formatted).toContain('Observations');
|
|
237
|
+
expect(formatted).toContain('Discovery Tokens');
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
describe('createTokenEconomicsTracker factory', () => {
|
|
242
|
+
it('should create tracker with default config', () => {
|
|
243
|
+
const tracker = createTokenEconomicsTracker();
|
|
244
|
+
expect(tracker).toBeInstanceOf(TokenEconomicsTracker);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('should create tracker with custom config', () => {
|
|
248
|
+
const tracker = createTokenEconomicsTracker({ charsPerToken: 5 });
|
|
249
|
+
// 10 chars / 5 = 2 tokens
|
|
250
|
+
expect(tracker.estimateTokens('1234567890')).toBe(2);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
describe('configuration', () => {
|
|
255
|
+
it('should use default chars per token', () => {
|
|
256
|
+
const tracker = new TokenEconomicsTracker();
|
|
257
|
+
expect(tracker.estimateTokens('1234')).toBe(1);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it('should accept custom chars per token', () => {
|
|
261
|
+
const tracker = new TokenEconomicsTracker({ charsPerToken: 2 });
|
|
262
|
+
expect(tracker.estimateTokens('1234')).toBe(2);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it('should include metadata tokens when configured', () => {
|
|
266
|
+
const tracker = new TokenEconomicsTracker({ includeMetadata: true });
|
|
267
|
+
tracker.recordCreation('entry1', 'content', { key: 'value' });
|
|
268
|
+
|
|
269
|
+
const metrics = tracker.getEntryMetrics('entry1');
|
|
270
|
+
// Should include metadata tokens
|
|
271
|
+
expect(metrics[0].discoveryTokens).toBeGreaterThan(
|
|
272
|
+
Math.ceil('content'.length / 4)
|
|
273
|
+
);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
});
|