@aeriondyseti/vector-memory-mcp 0.5.0 → 0.9.0-dev.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.
- package/README.md +58 -374
- package/hooks/session-start.ts +100 -0
- package/package.json +15 -3
- package/scripts/publish.ts +61 -0
- package/scripts/warmup.ts +1 -2
- package/src/config/index.ts +52 -14
- package/src/db/memory.repository.ts +21 -0
- package/src/db/schema.ts +1 -0
- package/src/http/mcp-transport.ts +255 -0
- package/src/http/server.ts +56 -39
- package/src/index.ts +39 -6
- package/src/mcp/handlers.ts +169 -33
- package/src/mcp/server.ts +1 -1
- package/src/mcp/tools.ts +207 -62
- package/src/services/embeddings.service.ts +5 -3
- package/src/services/memory.service.ts +109 -31
- package/src/types/memory.ts +0 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
import type { Memory } from "../types/memory.js";
|
|
3
|
-
import {
|
|
3
|
+
import { isDeleted } from "../types/memory.js";
|
|
4
4
|
import type { MemoryRepository } from "../db/memory.repository.js";
|
|
5
5
|
import type { EmbeddingsService } from "./embeddings.service.js";
|
|
6
6
|
|
|
@@ -42,33 +42,64 @@ export class MemoryService {
|
|
|
42
42
|
return await this.repository.markDeleted(id);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
|
|
46
|
+
async update(
|
|
47
|
+
id: string,
|
|
48
|
+
updates: {
|
|
49
|
+
content?: string;
|
|
50
|
+
embeddingText?: string;
|
|
51
|
+
metadata?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
): Promise<Memory | null> {
|
|
54
|
+
const existing = await this.repository.findById(id);
|
|
55
|
+
if (!existing) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const newContent = updates.content ?? existing.content;
|
|
60
|
+
const newMetadata = updates.metadata ?? existing.metadata;
|
|
61
|
+
|
|
62
|
+
// Regenerate embedding if content or embeddingText changed
|
|
63
|
+
let newEmbedding = existing.embedding;
|
|
64
|
+
if (updates.content !== undefined || updates.embeddingText !== undefined) {
|
|
65
|
+
const textToEmbed = updates.embeddingText ?? newContent;
|
|
66
|
+
newEmbedding = await this.embeddings.embed(textToEmbed);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const updatedMemory: Memory = {
|
|
70
|
+
...existing,
|
|
71
|
+
content: newContent,
|
|
72
|
+
embedding: newEmbedding,
|
|
73
|
+
metadata: newMetadata,
|
|
74
|
+
updatedAt: new Date(),
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
await this.repository.upsert(updatedMemory);
|
|
78
|
+
return updatedMemory;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async search(
|
|
82
|
+
query: string,
|
|
83
|
+
limit: number = 10,
|
|
84
|
+
includeDeleted: boolean = false
|
|
85
|
+
): Promise<Memory[]> {
|
|
46
86
|
const queryEmbedding = await this.embeddings.embed(query);
|
|
47
87
|
const fetchLimit = limit * 3;
|
|
48
88
|
|
|
49
89
|
const rows = await this.repository.findSimilar(queryEmbedding, fetchLimit);
|
|
50
90
|
|
|
51
91
|
const results: Memory[] = [];
|
|
52
|
-
const seenIds = new Set<string>();
|
|
53
92
|
|
|
54
93
|
for (const row of rows) {
|
|
55
|
-
|
|
94
|
+
const memory = await this.repository.findById(row.id);
|
|
56
95
|
|
|
57
96
|
if (!memory) {
|
|
58
97
|
continue;
|
|
59
98
|
}
|
|
60
99
|
|
|
61
|
-
if (
|
|
62
|
-
memory = await this.followSupersessionChain(row.id);
|
|
63
|
-
if (!memory) {
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (seenIds.has(memory.id)) {
|
|
100
|
+
if (!includeDeleted && isDeleted(memory)) {
|
|
69
101
|
continue;
|
|
70
102
|
}
|
|
71
|
-
seenIds.add(memory.id);
|
|
72
103
|
|
|
73
104
|
results.push(memory);
|
|
74
105
|
if (results.length >= limit) {
|
|
@@ -79,29 +110,76 @@ export class MemoryService {
|
|
|
79
110
|
return results;
|
|
80
111
|
}
|
|
81
112
|
|
|
82
|
-
private
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
113
|
+
private static readonly UUID_ZERO =
|
|
114
|
+
"00000000-0000-0000-0000-000000000000";
|
|
115
|
+
|
|
116
|
+
async storeHandoff(args: {
|
|
117
|
+
project: string;
|
|
118
|
+
branch?: string;
|
|
119
|
+
summary: string;
|
|
120
|
+
completed?: string[];
|
|
121
|
+
in_progress_blocked?: string[];
|
|
122
|
+
key_decisions?: string[];
|
|
123
|
+
next_steps?: string[];
|
|
124
|
+
memory_ids?: string[];
|
|
125
|
+
metadata?: Record<string, unknown>;
|
|
126
|
+
}): Promise<Memory> {
|
|
127
|
+
const now = new Date();
|
|
128
|
+
const date = now.toISOString().slice(0, 10);
|
|
129
|
+
const time = now.toISOString().slice(11, 16);
|
|
89
130
|
|
|
90
|
-
|
|
91
|
-
|
|
131
|
+
const list = (items: string[] | undefined) => {
|
|
132
|
+
if (!items || items.length === 0) {
|
|
133
|
+
return "- (none)";
|
|
92
134
|
}
|
|
135
|
+
return items.map((i) => `- ${i}`).join("\n");
|
|
136
|
+
};
|
|
93
137
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
138
|
+
const content = `# Handoff - ${args.project}
|
|
139
|
+
**Date:** ${date} ${time} | **Branch:** ${args.branch ?? "unknown"}
|
|
97
140
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
141
|
+
## Summary
|
|
142
|
+
${args.summary}
|
|
101
143
|
|
|
102
|
-
|
|
103
|
-
|
|
144
|
+
## Completed
|
|
145
|
+
${list(args.completed)}
|
|
146
|
+
|
|
147
|
+
## In Progress / Blocked
|
|
148
|
+
${list(args.in_progress_blocked)}
|
|
149
|
+
|
|
150
|
+
## Key Decisions
|
|
151
|
+
${list(args.key_decisions)}
|
|
152
|
+
|
|
153
|
+
## Next Steps
|
|
154
|
+
${list(args.next_steps)}
|
|
155
|
+
|
|
156
|
+
## Memory IDs
|
|
157
|
+
${list(args.memory_ids)}`;
|
|
158
|
+
|
|
159
|
+
const metadata: Record<string, unknown> = {
|
|
160
|
+
...(args.metadata ?? {}),
|
|
161
|
+
type: "handoff",
|
|
162
|
+
project: args.project,
|
|
163
|
+
date,
|
|
164
|
+
branch: args.branch ?? "unknown",
|
|
165
|
+
memory_ids: args.memory_ids ?? [],
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const memory: Memory = {
|
|
169
|
+
id: MemoryService.UUID_ZERO,
|
|
170
|
+
content,
|
|
171
|
+
embedding: new Array(this.embeddings.dimension).fill(0),
|
|
172
|
+
metadata,
|
|
173
|
+
createdAt: now,
|
|
174
|
+
updatedAt: now,
|
|
175
|
+
supersededBy: null,
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
await this.repository.upsert(memory);
|
|
179
|
+
return memory;
|
|
180
|
+
}
|
|
104
181
|
|
|
105
|
-
|
|
182
|
+
async getLatestHandoff(): Promise<Memory | null> {
|
|
183
|
+
return await this.get(MemoryService.UUID_ZERO);
|
|
106
184
|
}
|
|
107
185
|
}
|
package/src/types/memory.ts
CHANGED
|
@@ -19,10 +19,6 @@ export function isDeleted(memory: Memory): boolean {
|
|
|
19
19
|
return memory.supersededBy === DELETED_TOMBSTONE;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
export function isSuperseded(memory: Memory): boolean {
|
|
23
|
-
return memory.supersededBy !== null;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
22
|
export function memoryToDict(memory: Memory): Record<string, unknown> {
|
|
27
23
|
return {
|
|
28
24
|
id: memory.id,
|