@melandlabs/memory-store 0.1.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/LICENSE +17 -0
- package/README.md +377 -0
- package/dist/config-MlK9f9CM.d.ts +147 -0
- package/dist/contracts.d.ts +62 -0
- package/dist/contracts.js +27 -0
- package/dist/contracts.js.map +1 -0
- package/dist/http.d.ts +38 -0
- package/dist/http.js +545 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +442 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp.d.ts +29 -0
- package/dist/mcp.js +589 -0
- package/dist/mcp.js.map +1 -0
- package/dist/policies/memory-graph-correction-policy.d.ts +14 -0
- package/dist/policies/memory-graph-correction-policy.js +41 -0
- package/dist/policies/memory-graph-correction-policy.js.map +1 -0
- package/dist/policies/memory-graph-write-policy.d.ts +35 -0
- package/dist/policies/memory-graph-write-policy.js +78 -0
- package/dist/policies/memory-graph-write-policy.js.map +1 -0
- package/dist/search/unified-search.d.ts +81 -0
- package/dist/search/unified-search.js +399 -0
- package/dist/search/unified-search.js.map +1 -0
- package/dist/server/cli-http.d.ts +1 -0
- package/dist/server/cli-http.js +584 -0
- package/dist/server/cli-http.js.map +1 -0
- package/dist/server/cli-mcp.d.ts +1 -0
- package/dist/server/cli-mcp.js +603 -0
- package/dist/server/cli-mcp.js.map +1 -0
- package/dist/storage/chroma-memory-index.d.ts +76 -0
- package/dist/storage/chroma-memory-index.js +249 -0
- package/dist/storage/chroma-memory-index.js.map +1 -0
- package/dist/storage/postgres-raw-message-factory.d.ts +48 -0
- package/dist/storage/postgres-raw-message-factory.js +19 -0
- package/dist/storage/postgres-raw-message-factory.js.map +1 -0
- package/dist/storage/raw-message-store.d.ts +47 -0
- package/dist/storage/raw-message-store.js +140 -0
- package/dist/storage/raw-message-store.js.map +1 -0
- package/dist/storage/sqlite-raw-message-store.d.ts +19 -0
- package/dist/storage/sqlite-raw-message-store.js +68 -0
- package/dist/storage/sqlite-raw-message-store.js.map +1 -0
- package/dist/storage/sqlite-vector-index.d.ts +42 -0
- package/dist/storage/sqlite-vector-index.js +92 -0
- package/dist/storage/sqlite-vector-index.js.map +1 -0
- package/package.json +87 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { M as MemoryStoreConfig } from './config-MlK9f9CM.js';
|
|
2
|
+
export { E as EmbedQueryFn, a as MemoryStoreDb, b as MemoryStoreEnv, U as UnifiedSearchInsightsResult, c as UnifiedSearchKnowledgeResult, V as VectorBackend } from './config-MlK9f9CM.js';
|
|
3
|
+
import { UnifiedSearch } from './search/unified-search.js';
|
|
4
|
+
export { UnifiedMemorySearchInput, UnifiedMemorySearchOutput, UnifiedMemorySearchResult, UnifiedMemorySearchSource, UnifiedMemorySearchWarning, clampUnifiedMemorySearchLimit, clampUnifiedMemorySearchThreshold, createUnifiedSearch, isRawMemorySemanticResult, mergeUnifiedMemorySearchResults, normalizeUnifiedMemorySearchSources, toKnowledgeResult, toMemoryResult } from './search/unified-search.js';
|
|
5
|
+
import { RawMessageStore, getRawMessageManager } from './storage/raw-message-store.js';
|
|
6
|
+
export { RawMessageStorageBackend, RawMessageStorageManagerWithSearch, closeRawMessageStore, createRawMessageStore, getRawMessageStorageBackend, isRawMessageStorageAvailable } from './storage/raw-message-store.js';
|
|
7
|
+
export { PostgresFactoryFn, PostgresRawMessageManagerLike, clearPostgresFactory, hasPostgresFactory, registerPostgresFactory, resolvePostgresFactory } from './storage/postgres-raw-message-factory.js';
|
|
8
|
+
export { RawMessage } from './contracts.js';
|
|
9
|
+
import '@melandlabs/indexeddb/storage';
|
|
10
|
+
import '@melandlabs/ai/memory';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @melandlabs/memory-store — SDK entry point.
|
|
14
|
+
*
|
|
15
|
+
* Wires up a top-level `MemoryStore` facade combining the raw message
|
|
16
|
+
* manager, the unified search facade, and vector index helpers. Hosts
|
|
17
|
+
* that want a non-web backend (CLI daemon, custom server) can use
|
|
18
|
+
* this as the only entry point.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
interface MemoryStore {
|
|
22
|
+
/** Underlying raw-message store (sqlite vs postgres). */
|
|
23
|
+
raw: RawMessageStore;
|
|
24
|
+
/** Unified semantic search facade (memory + insights + knowledge). */
|
|
25
|
+
search: UnifiedSearch;
|
|
26
|
+
/** Resolve the active raw-message manager. */
|
|
27
|
+
getRawMessageManager: typeof getRawMessageManager;
|
|
28
|
+
/** Run `searchUnifiedMemory` against the wired-up unified search. */
|
|
29
|
+
searchUnifiedMemory: UnifiedSearch["searchUnifiedMemory"];
|
|
30
|
+
/** Convenience: semantic search over raw messages only. */
|
|
31
|
+
searchRawMemorySemantically: UnifiedSearch["searchRawMemorySemantically"];
|
|
32
|
+
}
|
|
33
|
+
declare function createMemoryStore(config?: MemoryStoreConfig): Promise<MemoryStore>;
|
|
34
|
+
|
|
35
|
+
export { type MemoryStore, MemoryStoreConfig, UnifiedSearch, createMemoryStore, getRawMessageManager };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
import '@melandlabs/ai/memory';
|
|
2
|
+
import { ChromaVectorStore } from '@melandlabs/rag';
|
|
3
|
+
import { mkdirSync } from 'fs';
|
|
4
|
+
import { dirname } from 'path';
|
|
5
|
+
import { SQLiteRawMessageManager } from '@melandlabs/sqlite';
|
|
6
|
+
|
|
7
|
+
// src/storage/chroma-memory-index.ts
|
|
8
|
+
var DEFAULT_RAW_MESSAGES_COLLECTION = "opencontext_raw_messages";
|
|
9
|
+
var RAW_VECTOR_BACKEND_ENV_KEYS = [
|
|
10
|
+
"RAW_MESSAGE_VECTOR_STORE_BACKEND",
|
|
11
|
+
"MEMORY_VECTOR_STORE_BACKEND",
|
|
12
|
+
"VECTOR_STORE_BACKEND"
|
|
13
|
+
];
|
|
14
|
+
function getBackend(keys) {
|
|
15
|
+
for (const key of keys) {
|
|
16
|
+
const value = process.env[key]?.trim().toLowerCase();
|
|
17
|
+
if (value) {
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
function isRawMessageChromaEnabled() {
|
|
24
|
+
return getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === "chroma";
|
|
25
|
+
}
|
|
26
|
+
function getRawMessagesCollectionName() {
|
|
27
|
+
return process.env.CHROMA_RAW_MESSAGES_COLLECTION || process.env.CHROMA_MEMORY_COLLECTION || DEFAULT_RAW_MESSAGES_COLLECTION;
|
|
28
|
+
}
|
|
29
|
+
function getChromaStore(collectionName) {
|
|
30
|
+
return new ChromaVectorStore({
|
|
31
|
+
url: process.env.CHROMA_URL,
|
|
32
|
+
collectionName
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function toBooleanValue(value) {
|
|
36
|
+
return value === true || value === "true" || value === 1 || value === "1";
|
|
37
|
+
}
|
|
38
|
+
async function searchRawMessagesWithChroma(input) {
|
|
39
|
+
if (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
const store = getChromaStore(getRawMessagesCollectionName());
|
|
43
|
+
const results = await store.similaritySearch(
|
|
44
|
+
input.queryEmbedding,
|
|
45
|
+
Math.max(input.limit * 5, input.limit),
|
|
46
|
+
input.userId
|
|
47
|
+
);
|
|
48
|
+
return results.filter((result) => {
|
|
49
|
+
const metadata = result.metadata ?? {};
|
|
50
|
+
if (toBooleanValue(metadata.archived)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (input.botId && metadata.botId !== input.botId) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return result.score >= input.threshold;
|
|
57
|
+
}).map((result) => ({
|
|
58
|
+
id: result.id,
|
|
59
|
+
content: result.content,
|
|
60
|
+
similarity: result.score,
|
|
61
|
+
metadata: result.metadata ?? {}
|
|
62
|
+
})).slice(0, input.limit);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// src/storage/postgres-raw-message-factory.ts
|
|
66
|
+
var factory = null;
|
|
67
|
+
function registerPostgresFactory(fn) {
|
|
68
|
+
factory = fn;
|
|
69
|
+
}
|
|
70
|
+
function clearPostgresFactory() {
|
|
71
|
+
factory = null;
|
|
72
|
+
}
|
|
73
|
+
async function resolvePostgresFactory(env) {
|
|
74
|
+
if (!factory) return null;
|
|
75
|
+
return await factory(env);
|
|
76
|
+
}
|
|
77
|
+
function hasPostgresFactory() {
|
|
78
|
+
return factory !== null;
|
|
79
|
+
}
|
|
80
|
+
var manager = null;
|
|
81
|
+
function isSQLiteRawMessageStorageAvailable(env) {
|
|
82
|
+
return resolveEnv(env).isTauriMode();
|
|
83
|
+
}
|
|
84
|
+
async function getSQLiteRawMessageManager(env) {
|
|
85
|
+
const e = resolveEnv(env);
|
|
86
|
+
if (!e.isTauriMode()) {
|
|
87
|
+
throw new Error("SQLite raw message storage is only available in Tauri mode.");
|
|
88
|
+
}
|
|
89
|
+
if (!manager) {
|
|
90
|
+
const dbPath = e.getTauriDbPath?.() ?? process.env.TAURI_DB_PATH ?? "";
|
|
91
|
+
mkdirSync(dirname(dbPath), { recursive: true });
|
|
92
|
+
manager = new SQLiteRawMessageManager({
|
|
93
|
+
dbPath,
|
|
94
|
+
enableVectorSearch: !isRawMessageChromaEnabled()
|
|
95
|
+
});
|
|
96
|
+
await manager.init();
|
|
97
|
+
}
|
|
98
|
+
return manager;
|
|
99
|
+
}
|
|
100
|
+
async function closeSQLiteRawMessageManager() {
|
|
101
|
+
if (!manager) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
await manager.close();
|
|
105
|
+
manager = null;
|
|
106
|
+
}
|
|
107
|
+
function resolveEnv(env) {
|
|
108
|
+
if (env) return env;
|
|
109
|
+
return {
|
|
110
|
+
isTauriMode: () => process.env.IS_TAURI === "true" || typeof process.env.TAURI_MODE === "string",
|
|
111
|
+
getTauriDbPath: () => process.env.TAURI_DB_PATH ?? "",
|
|
112
|
+
getTauriDataDir: () => process.env.TAURI_DATA_DIR ?? ""
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/storage/raw-message-store.ts
|
|
117
|
+
function resolveEnv2(env) {
|
|
118
|
+
if (env) return env;
|
|
119
|
+
return {
|
|
120
|
+
isTauriMode: () => process.env.IS_TAURI === "true" || typeof process.env.TAURI_MODE === "string",
|
|
121
|
+
getTauriDbPath: () => process.env.TAURI_DB_PATH ?? "",
|
|
122
|
+
getTauriDataDir: () => process.env.TAURI_DATA_DIR ?? ""
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
function createRawMessageStore(options = {}) {
|
|
126
|
+
const env = resolveEnv2(options.env);
|
|
127
|
+
return {
|
|
128
|
+
getBackend() {
|
|
129
|
+
return isSQLiteRawMessageStorageAvailable(env) ? "sqlite" : "postgres";
|
|
130
|
+
},
|
|
131
|
+
isAvailable() {
|
|
132
|
+
return isSQLiteRawMessageStorageAvailable(env) || hasPostgresFactory();
|
|
133
|
+
},
|
|
134
|
+
async getManager() {
|
|
135
|
+
if (isSQLiteRawMessageStorageAvailable(env)) {
|
|
136
|
+
return await getSQLiteRawMessageManager(env);
|
|
137
|
+
}
|
|
138
|
+
const pg = await resolvePostgresFactory(env);
|
|
139
|
+
if (!pg) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
"No raw-message backend available. SQLite is disabled (not Tauri) and no Postgres factory is registered."
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
return pg;
|
|
145
|
+
},
|
|
146
|
+
async close() {
|
|
147
|
+
if (isSQLiteRawMessageStorageAvailable(env)) {
|
|
148
|
+
await closeSQLiteRawMessageManager();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
var moduleStore = null;
|
|
154
|
+
var moduleConfig = null;
|
|
155
|
+
function configureRawMessageStore(config) {
|
|
156
|
+
moduleConfig = config;
|
|
157
|
+
moduleStore = createRawMessageStore({ env: config.env });
|
|
158
|
+
return moduleStore;
|
|
159
|
+
}
|
|
160
|
+
function getRawMessageStorageBackend() {
|
|
161
|
+
if (!moduleStore) {
|
|
162
|
+
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
163
|
+
}
|
|
164
|
+
return moduleStore.getBackend();
|
|
165
|
+
}
|
|
166
|
+
function isRawMessageStorageAvailable() {
|
|
167
|
+
if (!moduleStore) {
|
|
168
|
+
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
169
|
+
}
|
|
170
|
+
return moduleStore.isAvailable();
|
|
171
|
+
}
|
|
172
|
+
async function getRawMessageManager() {
|
|
173
|
+
if (!moduleStore) {
|
|
174
|
+
moduleStore = createRawMessageStore({ env: moduleConfig?.env });
|
|
175
|
+
}
|
|
176
|
+
return moduleStore.getManager();
|
|
177
|
+
}
|
|
178
|
+
async function closeRawMessageStore() {
|
|
179
|
+
if (!moduleStore) return;
|
|
180
|
+
await moduleStore.close();
|
|
181
|
+
moduleStore = null;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/search/utilities.ts
|
|
185
|
+
var DEFAULT_LIMIT = 10;
|
|
186
|
+
var DEFAULT_THRESHOLD = 0.7;
|
|
187
|
+
var DEFAULT_SOURCES = ["memory", "insights", "knowledge"];
|
|
188
|
+
var SOURCE_SET = new Set(DEFAULT_SOURCES);
|
|
189
|
+
function normalizeUnifiedMemorySearchSources(sources) {
|
|
190
|
+
if (!Array.isArray(sources) || sources.length === 0) {
|
|
191
|
+
return [...DEFAULT_SOURCES];
|
|
192
|
+
}
|
|
193
|
+
const normalized = sources.filter((source) => typeof source === "string").map((source) => source.trim().toLowerCase()).filter(
|
|
194
|
+
(source) => SOURCE_SET.has(source)
|
|
195
|
+
);
|
|
196
|
+
return normalized.length > 0 ? Array.from(new Set(normalized)) : [...DEFAULT_SOURCES];
|
|
197
|
+
}
|
|
198
|
+
function clampUnifiedMemorySearchLimit(limit) {
|
|
199
|
+
const parsed = typeof limit === "number" ? limit : Number(limit ?? DEFAULT_LIMIT);
|
|
200
|
+
if (!Number.isFinite(parsed)) {
|
|
201
|
+
return DEFAULT_LIMIT;
|
|
202
|
+
}
|
|
203
|
+
return Math.min(50, Math.max(1, Math.floor(parsed)));
|
|
204
|
+
}
|
|
205
|
+
function clampUnifiedMemorySearchThreshold(threshold) {
|
|
206
|
+
const parsed = typeof threshold === "number" ? threshold : Number(threshold ?? DEFAULT_THRESHOLD);
|
|
207
|
+
if (!Number.isFinite(parsed)) {
|
|
208
|
+
return DEFAULT_THRESHOLD;
|
|
209
|
+
}
|
|
210
|
+
return Math.min(1, Math.max(-1, parsed));
|
|
211
|
+
}
|
|
212
|
+
function mergeUnifiedMemorySearchResults(results, limit) {
|
|
213
|
+
return [...results].sort((a, b) => {
|
|
214
|
+
const scoreDelta = b.similarity - a.similarity;
|
|
215
|
+
if (scoreDelta !== 0) {
|
|
216
|
+
return scoreDelta;
|
|
217
|
+
}
|
|
218
|
+
return a.type.localeCompare(b.type) || a.id.localeCompare(b.id);
|
|
219
|
+
}).slice(0, limit);
|
|
220
|
+
}
|
|
221
|
+
function toKnowledgeResult(result) {
|
|
222
|
+
return {
|
|
223
|
+
type: "knowledge",
|
|
224
|
+
id: result.chunkId,
|
|
225
|
+
content: result.content,
|
|
226
|
+
similarity: result.similarity,
|
|
227
|
+
metadata: {
|
|
228
|
+
documentId: result.documentId,
|
|
229
|
+
documentName: result.documentName,
|
|
230
|
+
chunkIndex: result.chunkIndex
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function toMemoryResult(result) {
|
|
235
|
+
return {
|
|
236
|
+
type: "memory",
|
|
237
|
+
id: result.id,
|
|
238
|
+
content: result.content,
|
|
239
|
+
similarity: result.similarity,
|
|
240
|
+
metadata: result.metadata
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function isRawMemorySemanticResult(result) {
|
|
244
|
+
if (!result || typeof result !== "object") {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
const item = result;
|
|
248
|
+
return typeof item.id === "string" && typeof item.content === "string" && typeof item.similarity === "number" && Boolean(item.metadata) && typeof item.metadata === "object";
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// src/search/unified-search.ts
|
|
252
|
+
function createUnifiedSearch(deps = {}) {
|
|
253
|
+
const logger = deps.logger ?? console;
|
|
254
|
+
async function searchUnifiedMemory(input) {
|
|
255
|
+
const query = input.query.trim();
|
|
256
|
+
const sources = normalizeUnifiedMemorySearchSources(input.sources);
|
|
257
|
+
const limit = clampUnifiedMemorySearchLimit(input.limit);
|
|
258
|
+
const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
|
|
259
|
+
const warnings = [];
|
|
260
|
+
const results = [];
|
|
261
|
+
if (!query) {
|
|
262
|
+
return {
|
|
263
|
+
query,
|
|
264
|
+
sources,
|
|
265
|
+
results: [],
|
|
266
|
+
count: 0,
|
|
267
|
+
warnings
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
if (sources.includes("memory")) {
|
|
271
|
+
if (isRawMessageStorageAvailable()) {
|
|
272
|
+
try {
|
|
273
|
+
const memoryHits = await runMemorySource(input, limit, threshold);
|
|
274
|
+
results.push(...memoryHits);
|
|
275
|
+
} catch (error) {
|
|
276
|
+
logger.warn?.("[memory-store] memory source failed:", error);
|
|
277
|
+
warnings.push({
|
|
278
|
+
source: "memory",
|
|
279
|
+
code: "memory_search_failed",
|
|
280
|
+
message: error.message ?? "memory_search_failed"
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
} else {
|
|
284
|
+
warnings.push({
|
|
285
|
+
source: "memory",
|
|
286
|
+
code: "raw_message_storage_unavailable",
|
|
287
|
+
message: "Raw memory storage is not available in this environment."
|
|
288
|
+
});
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
if (sources.includes("insights") && typeof deps.searchInsights === "function") {
|
|
292
|
+
try {
|
|
293
|
+
const insightHits = await deps.searchInsights({
|
|
294
|
+
userId: input.userId,
|
|
295
|
+
query: input.query,
|
|
296
|
+
limit,
|
|
297
|
+
threshold,
|
|
298
|
+
botIds: input.botIds,
|
|
299
|
+
includeArchived: input.includeArchivedInsights,
|
|
300
|
+
authToken: input.authToken
|
|
301
|
+
});
|
|
302
|
+
for (const hit of insightHits) {
|
|
303
|
+
results.push({
|
|
304
|
+
type: "insight",
|
|
305
|
+
id: hit.id,
|
|
306
|
+
content: hit.content,
|
|
307
|
+
similarity: hit.similarity,
|
|
308
|
+
metadata: hit.metadata
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
} catch (error) {
|
|
312
|
+
logger.warn?.("[memory-store] insights source failed:", error);
|
|
313
|
+
warnings.push({
|
|
314
|
+
source: "insights",
|
|
315
|
+
code: "insights_search_failed",
|
|
316
|
+
message: error.message ?? "insights_search_failed"
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
} else if (sources.includes("insights")) {
|
|
320
|
+
warnings.push({
|
|
321
|
+
source: "insights",
|
|
322
|
+
code: "insights_search_not_configured",
|
|
323
|
+
message: "Insights search is not configured for this host."
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
if (sources.includes("knowledge") && typeof deps.searchKnowledge === "function") {
|
|
327
|
+
try {
|
|
328
|
+
const knowledgeHits = await deps.searchKnowledge({
|
|
329
|
+
userId: input.userId,
|
|
330
|
+
query: input.query,
|
|
331
|
+
options: {
|
|
332
|
+
limit,
|
|
333
|
+
threshold,
|
|
334
|
+
documentIds: input.documentIds
|
|
335
|
+
},
|
|
336
|
+
authToken: input.authToken
|
|
337
|
+
});
|
|
338
|
+
for (const hit of knowledgeHits) {
|
|
339
|
+
results.push(toKnowledgeResult(hit));
|
|
340
|
+
}
|
|
341
|
+
} catch (error) {
|
|
342
|
+
logger.warn?.("[memory-store] knowledge source failed:", error);
|
|
343
|
+
warnings.push({
|
|
344
|
+
source: "knowledge",
|
|
345
|
+
code: "knowledge_search_failed",
|
|
346
|
+
message: error.message ?? "knowledge_search_failed"
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
} else if (sources.includes("knowledge")) {
|
|
350
|
+
warnings.push({
|
|
351
|
+
source: "knowledge",
|
|
352
|
+
code: "knowledge_search_not_configured",
|
|
353
|
+
message: "Knowledge search is not configured for this host."
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
const merged = mergeUnifiedMemorySearchResults(results, limit);
|
|
357
|
+
return {
|
|
358
|
+
query: input.query,
|
|
359
|
+
sources,
|
|
360
|
+
results: merged,
|
|
361
|
+
count: merged.length,
|
|
362
|
+
warnings
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
async function runMemorySource(input, limit, threshold) {
|
|
366
|
+
if (typeof deps.embedQuery !== "function") {
|
|
367
|
+
throw new Error("embedQuery is not configured");
|
|
368
|
+
}
|
|
369
|
+
const queryEmbedding = await deps.embedQuery({
|
|
370
|
+
userId: input.userId,
|
|
371
|
+
query: input.query,
|
|
372
|
+
authToken: input.authToken
|
|
373
|
+
});
|
|
374
|
+
const filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];
|
|
375
|
+
if (isRawMessageChromaEnabled()) {
|
|
376
|
+
try {
|
|
377
|
+
const chromaHits = (await Promise.all(
|
|
378
|
+
filters.map((filter) => {
|
|
379
|
+
const botId = "botId" in filter ? filter.botId : void 0;
|
|
380
|
+
return searchRawMessagesWithChroma({
|
|
381
|
+
userId: input.userId,
|
|
382
|
+
queryEmbedding,
|
|
383
|
+
limit,
|
|
384
|
+
threshold,
|
|
385
|
+
botId
|
|
386
|
+
});
|
|
387
|
+
})
|
|
388
|
+
)).flat().map(toMemoryResult);
|
|
389
|
+
logger.log?.("[memory-store] Raw message semantic search completed", {
|
|
390
|
+
backend: "chroma",
|
|
391
|
+
dimensions: queryEmbedding.length,
|
|
392
|
+
count: chromaHits.length
|
|
393
|
+
});
|
|
394
|
+
return chromaHits;
|
|
395
|
+
} catch (error) {
|
|
396
|
+
logger.warn?.(
|
|
397
|
+
"[memory-store] Chroma raw message search failed; falling back to database search:",
|
|
398
|
+
error
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
if (typeof deps.searchRawMessagesAnn === "function") {
|
|
403
|
+
const rows = (await Promise.all(
|
|
404
|
+
filters.map(
|
|
405
|
+
(filter) => deps.searchRawMessagesAnn({
|
|
406
|
+
userId: input.userId,
|
|
407
|
+
queryEmbedding,
|
|
408
|
+
limit,
|
|
409
|
+
threshold,
|
|
410
|
+
botId: "botId" in filter ? filter.botId : void 0
|
|
411
|
+
})
|
|
412
|
+
)
|
|
413
|
+
)).flat().filter(isRawMemorySemanticResult).map(toMemoryResult);
|
|
414
|
+
return rows;
|
|
415
|
+
}
|
|
416
|
+
return [];
|
|
417
|
+
}
|
|
418
|
+
async function searchRawMemorySemantically(input) {
|
|
419
|
+
const limit = clampUnifiedMemorySearchLimit(input.limit);
|
|
420
|
+
const threshold = clampUnifiedMemorySearchThreshold(input.threshold);
|
|
421
|
+
return runMemorySource(input, limit, threshold);
|
|
422
|
+
}
|
|
423
|
+
return { searchUnifiedMemory, searchRawMemorySemantically };
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// src/index.ts
|
|
427
|
+
async function createMemoryStore(config = {}) {
|
|
428
|
+
const raw = createRawMessageStore({ env: config.env });
|
|
429
|
+
const search = createUnifiedSearch(config.unified);
|
|
430
|
+
configureRawMessageStore(config);
|
|
431
|
+
return {
|
|
432
|
+
raw,
|
|
433
|
+
search,
|
|
434
|
+
getRawMessageManager,
|
|
435
|
+
searchUnifiedMemory: search.searchUnifiedMemory,
|
|
436
|
+
searchRawMemorySemantically: search.searchRawMemorySemantically
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
export { clampUnifiedMemorySearchLimit, clampUnifiedMemorySearchThreshold, clearPostgresFactory, closeRawMessageStore, createMemoryStore, createRawMessageStore, createUnifiedSearch, getRawMessageManager, getRawMessageStorageBackend, hasPostgresFactory, isRawMemorySemanticResult, isRawMessageStorageAvailable, mergeUnifiedMemorySearchResults, normalizeUnifiedMemorySearchSources, registerPostgresFactory, resolvePostgresFactory, toKnowledgeResult, toMemoryResult };
|
|
441
|
+
//# sourceMappingURL=index.js.map
|
|
442
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/storage/chroma-memory-index.ts","../src/storage/postgres-raw-message-factory.ts","../src/storage/sqlite-raw-message-store.ts","../src/storage/raw-message-store.ts","../src/search/utilities.ts","../src/search/unified-search.ts","../src/index.ts"],"names":["resolveEnv"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Chroma-backed raw-message + insight vector index.\n *\n * Detects the active backend at call time (defaults to sqlite-vec if\n * no env override is present). The actual URL/collection values come\n * from env vars so the standalone memory daemon can pick them up\n * without an injected config.\n */\n\nimport { buildMemoryRecordEmbeddingDocument } from \"@melandlabs/ai/memory\";\nimport { ChromaVectorStore } from \"@melandlabs/rag\";\nimport type { DocumentChunk } from \"@melandlabs/rag/vector-service\";\n\nimport { type RawMessage, rawMessageToMemoryRecord } from \"../contracts\";\n\nconst DEFAULT_RAW_MESSAGES_COLLECTION = \"opencontext_raw_messages\";\nconst DEFAULT_INSIGHTS_COLLECTION = \"opencontext_insights\";\nconst RAW_VECTOR_BACKEND_ENV_KEYS = [\n\t\"RAW_MESSAGE_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\nconst INSIGHT_VECTOR_BACKEND_ENV_KEYS = [\n\t\"INSIGHT_VECTOR_STORE_BACKEND\",\n\t\"MEMORY_VECTOR_STORE_BACKEND\",\n\t\"VECTOR_STORE_BACKEND\",\n] as const;\n\nexport interface ChromaInsightVectorInput {\n\tinsightId: string;\n\tuserId: string;\n\tbotId: string;\n\tcontent: string;\n\tcontentHash: string;\n\tembedding: number[];\n\tembeddingModel: string;\n\tembeddingDimensions: number;\n\ttitle?: unknown;\n\tdescription?: unknown;\n\ttaskLabel?: unknown;\n\timportance?: unknown;\n\turgency?: unknown;\n\tplatform?: unknown;\n\taccount?: unknown;\n\ttime?: unknown;\n\tarchived?: unknown;\n}\n\nexport interface ChromaInsightSearchResult {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: {\n\t\tbotId: string;\n\t\ttitle: string;\n\t\tdescription: string;\n\t\ttaskLabel: string;\n\t\timportance: string;\n\t\turgency: string;\n\t\tplatform: string | null;\n\t\taccount: string | null;\n\t\ttime: Date | null;\n\t\tembeddingModel: string;\n\t\tembeddingDimensions: number;\n\t\tcontentHash: string;\n\t};\n}\n\nfunction getBackend(keys: readonly string[]): string {\n\tfor (const key of keys) {\n\t\tconst value = process.env[key]?.trim().toLowerCase();\n\t\tif (value) {\n\t\t\treturn value;\n\t\t}\n\t}\n\treturn \"\";\n}\n\nexport function isRawMessageChromaEnabled(): boolean {\n\treturn getBackend(RAW_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nexport function isInsightChromaEnabled(): boolean {\n\treturn getBackend(INSIGHT_VECTOR_BACKEND_ENV_KEYS) === \"chroma\";\n}\n\nfunction getRawMessagesCollectionName(): string {\n\treturn (\n\t\tprocess.env.CHROMA_RAW_MESSAGES_COLLECTION ||\n\t\tprocess.env.CHROMA_MEMORY_COLLECTION ||\n\t\tDEFAULT_RAW_MESSAGES_COLLECTION\n\t);\n}\n\nfunction getInsightsCollectionName(): string {\n\treturn process.env.CHROMA_INSIGHTS_COLLECTION || DEFAULT_INSIGHTS_COLLECTION;\n}\n\nfunction getChromaStore(collectionName: string): ChromaVectorStore {\n\treturn new ChromaVectorStore({\n\t\turl: process.env.CHROMA_URL,\n\t\tcollectionName,\n\t});\n}\n\nfunction normalizeTimestampToMs(value: number | undefined): number {\n\tif (!Number.isFinite(value)) {\n\t\treturn 0;\n\t}\n\tif ((value as number) < 1e11) {\n\t\treturn Math.floor((value as number) * 1000);\n\t}\n\treturn Math.floor(value as number);\n}\n\nfunction toStringValue(value: unknown, fallback = \"\"): string {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : fallback;\n}\n\nfunction toNullableString(value: unknown): string | null {\n\treturn typeof value === \"string\" && value.trim().length > 0 ? value.trim() : null;\n}\n\nfunction toBooleanValue(value: unknown): boolean {\n\treturn value === true || value === \"true\" || value === 1 || value === \"1\";\n}\n\nfunction toDateValue(value: unknown): Date | null {\n\tif (value instanceof Date) {\n\t\treturn Number.isNaN(value.getTime()) ? null : value;\n\t}\n\tif (typeof value === \"string\" || typeof value === \"number\") {\n\t\tconst date = new Date(value);\n\t\treturn Number.isNaN(date.getTime()) ? null : date;\n\t}\n\treturn null;\n}\n\nfunction rawMessageToChunk(message: RawMessage): DocumentChunk | null {\n\tif (!message.embedding || message.embedding.length === 0) {\n\t\treturn null;\n\t}\n\n\tconst record = rawMessageToMemoryRecord(message);\n\tconst document = buildMemoryRecordEmbeddingDocument(record);\n\tif (!document.content) {\n\t\treturn null;\n\t}\n\n\treturn {\n\t\tid: message.messageId,\n\t\tdocumentId: message.messageId,\n\t\tcontent: document.content,\n\t\tembedding: message.embedding,\n\t\tmetadata: {\n\t\t\tsourceType: \"raw_message\",\n\t\t\tuserId: message.userId,\n\t\t\tplatform: message.platform,\n\t\t\tbotId: message.botId,\n\t\t\tchannel: message.channel,\n\t\t\tperson: message.person,\n\t\t\ttimestamp: normalizeTimestampToMs(message.timestamp),\n\t\t\tmemoryStage: message.memoryStage,\n\t\t\tembeddingModel: message.embeddingModel,\n\t\t\tembeddingDimensions: message.embeddingDimensions,\n\t\t\tcontentHash: message.embeddingContentHash,\n\t\t\tarchived: Boolean(message.archivedAt),\n\t\t\trole: typeof message.metadata?.role === \"string\" ? message.metadata.role : undefined,\n\t\t},\n\t};\n}\n\nexport async function upsertRawMessagesToChroma(messages: RawMessage[]): Promise<number> {\n\tif (!isRawMessageChromaEnabled() || messages.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = messages.map(rawMessageToChunk).filter((chunk): chunk is DocumentChunk => chunk !== null);\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchRawMessagesWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotId?: string;\n}): Promise<\n\tArray<{\n\t\tid: string;\n\t\tcontent: string;\n\t\tsimilarity: number;\n\t\tmetadata: Record<string, unknown>;\n\t}>\n> {\n\tif (!isRawMessageChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst store = getChromaStore(getRawMessagesCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (input.botId && metadata.botId !== input.botId) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => ({\n\t\t\tid: result.id,\n\t\t\tcontent: result.content,\n\t\t\tsimilarity: result.score,\n\t\t\tmetadata: result.metadata ?? {},\n\t\t}))\n\t\t.slice(0, input.limit);\n}\n\nexport async function upsertInsightsToChroma(insights: ChromaInsightVectorInput[]): Promise<number> {\n\tif (!isInsightChromaEnabled() || insights.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst chunks = insights\n\t\t.filter(\n\t\t\t(item) => item.content.trim().length > 0 && Array.isArray(item.embedding) && item.embedding.length > 0,\n\t\t)\n\t\t.map<DocumentChunk>((item) => ({\n\t\t\tid: item.insightId,\n\t\t\tdocumentId: item.insightId,\n\t\t\tcontent: item.content,\n\t\t\tembedding: item.embedding,\n\t\t\tmetadata: {\n\t\t\t\tsourceType: \"insight\",\n\t\t\t\tinsightId: item.insightId,\n\t\t\t\tuserId: item.userId,\n\t\t\t\tbotId: item.botId,\n\t\t\t\ttitle: toStringValue(item.title),\n\t\t\t\tdescription: toStringValue(item.description),\n\t\t\t\ttaskLabel: toStringValue(item.taskLabel),\n\t\t\t\timportance: toStringValue(item.importance),\n\t\t\t\turgency: toStringValue(item.urgency),\n\t\t\t\tplatform: toNullableString(item.platform),\n\t\t\t\taccount: toNullableString(item.account),\n\t\t\t\ttime: toDateValue(item.time)?.toISOString(),\n\t\t\t\tembeddingModel: item.embeddingModel,\n\t\t\t\tembeddingDimensions: item.embeddingDimensions,\n\t\t\t\tcontentHash: item.contentHash,\n\t\t\t\tarchived: toBooleanValue(item.archived),\n\t\t\t},\n\t\t}));\n\n\tif (chunks.length === 0) {\n\t\treturn 0;\n\t}\n\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tawait store.addChunks(chunks);\n\treturn chunks.length;\n}\n\nexport async function searchInsightsWithChroma(input: {\n\tuserId: string;\n\tqueryEmbedding: number[];\n\tlimit: number;\n\tthreshold: number;\n\tbotIds?: string[];\n\tincludeArchived?: boolean;\n}): Promise<ChromaInsightSearchResult[]> {\n\tif (!isInsightChromaEnabled() || input.queryEmbedding.length === 0) {\n\t\treturn [];\n\t}\n\n\tconst botIdSet = input.botIds && input.botIds.length > 0 ? new Set(input.botIds) : null;\n\tconst store = getChromaStore(getInsightsCollectionName());\n\tconst results = await store.similaritySearch(\n\t\tinput.queryEmbedding,\n\t\tMath.max(input.limit * 5, input.limit),\n\t\tinput.userId,\n\t);\n\n\treturn results\n\t\t.filter((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\tif (!input.includeArchived && toBooleanValue(metadata.archived)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (botIdSet && !botIdSet.has(String(metadata.botId ?? \"\"))) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn result.score >= input.threshold;\n\t\t})\n\t\t.map((result) => {\n\t\t\tconst metadata = result.metadata ?? {};\n\t\t\treturn {\n\t\t\t\tid: result.id,\n\t\t\t\tcontent: result.content,\n\t\t\t\tsimilarity: result.score,\n\t\t\t\tmetadata: {\n\t\t\t\t\tbotId: toStringValue(metadata.botId),\n\t\t\t\t\ttitle: toStringValue(metadata.title),\n\t\t\t\t\tdescription: toStringValue(metadata.description),\n\t\t\t\t\ttaskLabel: toStringValue(metadata.taskLabel),\n\t\t\t\t\timportance: toStringValue(metadata.importance),\n\t\t\t\t\turgency: toStringValue(metadata.urgency),\n\t\t\t\t\tplatform: toNullableString(metadata.platform),\n\t\t\t\t\taccount: toNullableString(metadata.account),\n\t\t\t\t\ttime: toDateValue(metadata.time),\n\t\t\t\t\tembeddingModel: toStringValue(metadata.embeddingModel),\n\t\t\t\t\tembeddingDimensions: Number(metadata.embeddingDimensions ?? 0),\n\t\t\t\t\tcontentHash: toStringValue(metadata.contentHash),\n\t\t\t\t},\n\t\t\t};\n\t\t})\n\t\t.slice(0, input.limit);\n}\n","/**\n * Lazy registration slot for the host's Postgres-backed raw message\n * manager. The actual `PostgresRawMessageManager` implementation lives\n * in the host application because it owns the schema-bound Drizzle\n * table references.\n *\n * The package ships this factory so consumers can wire up their own\n * postgres implementation without forcing the package to take a\n * hard dependency on Drizzle schema files.\n */\n\nimport type { MemoryStoreEnv } from \"../config\";\n\nexport interface PostgresRawMessageManagerLike {\n\tinit?(): Promise<void>;\n\tclose?(): Promise<void>;\n\tupsertRawMessages?(input: {\n\t\tuserId: string;\n\t\tmessages: unknown[];\n\t}): Promise<unknown>;\n\tgetMessageById?(input: {\n\t\tuserId: string;\n\t\tmessageId: string;\n\t}): Promise<unknown>;\n\tsearchMessagesSemantically?(input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tincludeDeprecated?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}): Promise<unknown[]>;\n}\n\nexport type PostgresFactoryFn = (env?: MemoryStoreEnv) => Promise<PostgresRawMessageManagerLike>;\n\nlet factory: PostgresFactoryFn | null = null;\n\nexport function registerPostgresFactory(fn: PostgresFactoryFn): void {\n\tfactory = fn;\n}\n\nexport function clearPostgresFactory(): void {\n\tfactory = null;\n}\n\nexport async function resolvePostgresFactory(\n\tenv?: MemoryStoreEnv,\n): Promise<PostgresRawMessageManagerLike | null> {\n\tif (!factory) return null;\n\treturn await factory(env);\n}\n\nexport function hasPostgresFactory(): boolean {\n\treturn factory !== null;\n}\n","/**\n * SQLite-backed raw message store.\n *\n * Singleton manager used in Tauri (local) mode. The Tauri env is\n * sourced from the injected `MemoryStoreConfig.env`.\n */\n\nimport { mkdirSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { SQLiteRawMessageManager } from \"@melandlabs/sqlite\";\nimport type { MemoryStoreEnv } from \"../config\";\nimport { isRawMessageChromaEnabled } from \"./chroma-memory-index\";\n\nlet manager: SQLiteRawMessageManager | null = null;\n\nexport function isSQLiteRawMessageStorageAvailable(env?: MemoryStoreEnv): boolean {\n\treturn resolveEnv(env).isTauriMode();\n}\n\nexport async function getSQLiteRawMessageManager(env?: MemoryStoreEnv): Promise<SQLiteRawMessageManager> {\n\tconst e = resolveEnv(env);\n\tif (!e.isTauriMode()) {\n\t\tthrow new Error(\"SQLite raw message storage is only available in Tauri mode.\");\n\t}\n\n\tif (!manager) {\n\t\tconst dbPath = e.getTauriDbPath?.() ?? process.env.TAURI_DB_PATH ?? \"\";\n\t\tmkdirSync(dirname(dbPath), { recursive: true });\n\t\tmanager = new SQLiteRawMessageManager({\n\t\t\tdbPath,\n\t\t\tenableVectorSearch: !isRawMessageChromaEnabled(),\n\t\t});\n\t\tawait manager.init();\n\t}\n\n\treturn manager;\n}\n\nexport async function closeSQLiteRawMessageManager(): Promise<void> {\n\tif (!manager) {\n\t\treturn;\n\t}\n\tawait manager.close();\n\tmanager = null;\n}\n\n/**\n * Test-only: reset the singleton. Used by vitest between test cases.\n */\nexport function __resetSQLiteRawMessageManagerForTests(): void {\n\tmanager = null;\n}\n\nfunction resolveEnv(env?: MemoryStoreEnv): MemoryStoreEnv {\n\tif (env) return env;\n\treturn {\n\t\tisTauriMode: () => process.env.IS_TAURI === \"true\" || typeof process.env.TAURI_MODE === \"string\",\n\t\tgetTauriDbPath: () => process.env.TAURI_DB_PATH ?? \"\",\n\t\tgetTauriDataDir: () => process.env.TAURI_DATA_DIR ?? \"\",\n\t};\n}\n","/**\n * Top-level raw-message store facade.\n *\n * Selects between sqlite (Tauri) and postgres (host-registered)\n * backends based on `MemoryStoreEnv.isTauriMode()`. The facade exposes\n * the common `RawMessageStorageManager` contract plus a typed\n * `searchMessagesSemantically` extension when present.\n */\n\nimport type { RawMessageStorageManager } from \"@melandlabs/indexeddb/storage\";\nimport type { MemoryStoreConfig, MemoryStoreEnv } from \"../config\";\nimport { hasPostgresFactory, resolvePostgresFactory } from \"./postgres-raw-message-factory\";\nimport {\n\tcloseSQLiteRawMessageManager,\n\tgetSQLiteRawMessageManager,\n\tisSQLiteRawMessageStorageAvailable,\n} from \"./sqlite-raw-message-store\";\n\nexport type RawMessageStorageBackend = \"sqlite\" | \"postgres\";\n\nexport type RawMessageStorageManagerWithSearch = RawMessageStorageManager & {\n\tsearchMessagesSemantically?: (input: {\n\t\tuserId: string;\n\t\tqueryEmbedding: number[];\n\t\tembeddingModel?: string;\n\t\tlimit?: number;\n\t\tscanLimit?: number;\n\t\tthreshold?: number;\n\t\tincludeArchived?: boolean;\n\t\tplatform?: string;\n\t\tbotId?: string;\n\t\tchannel?: string;\n\t\tperson?: string;\n\t\tstartTime?: number;\n\t\tendTime?: number;\n\t}) => Promise<unknown[]>;\n};\n\nexport interface CreateRawMessageStoreOptions {\n\tenv?: MemoryStoreEnv;\n}\n\nexport interface RawMessageStore {\n\tgetManager(): Promise<RawMessageStorageManagerWithSearch>;\n\tgetBackend(): RawMessageStorageBackend;\n\tisAvailable(): boolean;\n\tclose(): Promise<void>;\n}\n\nfunction resolveEnv(env?: MemoryStoreEnv): MemoryStoreEnv {\n\tif (env) return env;\n\treturn {\n\t\tisTauriMode: () => process.env.IS_TAURI === \"true\" || typeof process.env.TAURI_MODE === \"string\",\n\t\tgetTauriDbPath: () => process.env.TAURI_DB_PATH ?? \"\",\n\t\tgetTauriDataDir: () => process.env.TAURI_DATA_DIR ?? \"\",\n\t};\n}\n\nexport function createRawMessageStore(options: CreateRawMessageStoreOptions = {}): RawMessageStore {\n\tconst env = resolveEnv(options.env);\n\n\treturn {\n\t\tgetBackend(): RawMessageStorageBackend {\n\t\t\treturn isSQLiteRawMessageStorageAvailable(env) ? \"sqlite\" : \"postgres\";\n\t\t},\n\t\tisAvailable(): boolean {\n\t\t\treturn isSQLiteRawMessageStorageAvailable(env) || hasPostgresFactory();\n\t\t},\n\t\tasync getManager(): Promise<RawMessageStorageManagerWithSearch> {\n\t\t\tif (isSQLiteRawMessageStorageAvailable(env)) {\n\t\t\t\treturn (await getSQLiteRawMessageManager(env)) as unknown as RawMessageStorageManagerWithSearch;\n\t\t\t}\n\t\t\tconst pg = await resolvePostgresFactory(env);\n\t\t\tif (!pg) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"No raw-message backend available. SQLite is disabled (not Tauri) and no Postgres factory is registered.\",\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn pg as unknown as RawMessageStorageManagerWithSearch;\n\t\t},\n\t\tasync close(): Promise<void> {\n\t\t\tif (isSQLiteRawMessageStorageAvailable(env)) {\n\t\t\t\tawait closeSQLiteRawMessageManager();\n\t\t\t}\n\t\t},\n\t};\n}\n\n// Module-level singleton so existing call sites that imported the\n// legacy `getRawMessageManager()` keep working without a refactor.\nlet moduleStore: RawMessageStore | null = null;\nlet moduleConfig: MemoryStoreConfig | null = null;\n\nexport function configureRawMessageStore(config: MemoryStoreConfig): RawMessageStore {\n\tmoduleConfig = config;\n\tmoduleStore = createRawMessageStore({ env: config.env });\n\treturn moduleStore;\n}\n\nexport function getRawMessageStorageBackend(): RawMessageStorageBackend {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getBackend();\n}\n\nexport function isRawMessageStorageAvailable(): boolean {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.isAvailable();\n}\n\nexport async function getRawMessageManager(): Promise<RawMessageStorageManagerWithSearch> {\n\tif (!moduleStore) {\n\t\tmoduleStore = createRawMessageStore({ env: moduleConfig?.env });\n\t}\n\treturn moduleStore.getManager();\n}\n\nexport async function closeRawMessageStore(): Promise<void> {\n\tif (!moduleStore) return;\n\tawait moduleStore.close();\n\tmoduleStore = null;\n}\n","/**\n * Pure helpers used by the unified memory search pipeline.\n *\n * Kept side-effect free so they can be reused by tests, MCP tools,\n * and the HTTP daemon without pulling in any of the heavier\n * storage/search implementations.\n */\n\nexport type UnifiedMemorySearchSource = \"memory\" | \"insights\" | \"knowledge\";\n\nexport interface UnifiedMemorySearchWarning {\n\tsource: UnifiedMemorySearchSource;\n\tcode: string;\n\tmessage: string;\n}\n\nexport interface UnifiedMemorySearchInput {\n\tuserId: string;\n\tquery: string;\n\tsources?: UnifiedMemorySearchSource[];\n\tlimit?: number;\n\tthreshold?: number;\n\tauthToken?: string;\n\tincludeArchivedInsights?: boolean;\n\tbotIds?: string[];\n\tdocumentIds?: string[];\n}\n\nexport interface UnifiedMemorySearchResult {\n\ttype: \"memory\" | \"insight\" | \"knowledge\";\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n}\n\nexport interface UnifiedMemorySearchOutput {\n\tquery: string;\n\tsources: UnifiedMemorySearchSource[];\n\tresults: UnifiedMemorySearchResult[];\n\tcount: number;\n\twarnings: UnifiedMemorySearchWarning[];\n}\n\nconst DEFAULT_LIMIT = 10;\nconst DEFAULT_THRESHOLD = 0.7;\nconst DEFAULT_SOURCES: UnifiedMemorySearchSource[] = [\"memory\", \"insights\", \"knowledge\"];\nconst SOURCE_SET = new Set<UnifiedMemorySearchSource>(DEFAULT_SOURCES);\n\nexport function normalizeUnifiedMemorySearchSources(sources: unknown): UnifiedMemorySearchSource[] {\n\tif (!Array.isArray(sources) || sources.length === 0) {\n\t\treturn [...DEFAULT_SOURCES];\n\t}\n\n\tconst normalized = sources\n\t\t.filter((source): source is string => typeof source === \"string\")\n\t\t.map((source) => source.trim().toLowerCase())\n\t\t.filter((source): source is UnifiedMemorySearchSource =>\n\t\t\tSOURCE_SET.has(source as UnifiedMemorySearchSource),\n\t\t);\n\n\treturn normalized.length > 0 ? Array.from(new Set(normalized)) : [...DEFAULT_SOURCES];\n}\n\nexport function clampUnifiedMemorySearchLimit(limit: unknown): number {\n\tconst parsed = typeof limit === \"number\" ? limit : Number(limit ?? DEFAULT_LIMIT);\n\tif (!Number.isFinite(parsed)) {\n\t\treturn DEFAULT_LIMIT;\n\t}\n\treturn Math.min(50, Math.max(1, Math.floor(parsed)));\n}\n\nexport function clampUnifiedMemorySearchThreshold(threshold: unknown): number {\n\tconst parsed = typeof threshold === \"number\" ? threshold : Number(threshold ?? DEFAULT_THRESHOLD);\n\tif (!Number.isFinite(parsed)) {\n\t\treturn DEFAULT_THRESHOLD;\n\t}\n\treturn Math.min(1, Math.max(-1, parsed));\n}\n\nexport function mergeUnifiedMemorySearchResults(\n\tresults: UnifiedMemorySearchResult[],\n\tlimit: number,\n): UnifiedMemorySearchResult[] {\n\treturn [...results]\n\t\t.sort((a, b) => {\n\t\t\tconst scoreDelta = b.similarity - a.similarity;\n\t\t\tif (scoreDelta !== 0) {\n\t\t\t\treturn scoreDelta;\n\t\t\t}\n\t\t\treturn a.type.localeCompare(b.type) || a.id.localeCompare(b.id);\n\t\t})\n\t\t.slice(0, limit);\n}\n\nexport function toKnowledgeResult(result: {\n\tchunkId: string;\n\tdocumentId: string;\n\tdocumentName: string;\n\tcontent: string;\n\tsimilarity: number;\n\tchunkIndex: number;\n}): UnifiedMemorySearchResult {\n\treturn {\n\t\ttype: \"knowledge\",\n\t\tid: result.chunkId,\n\t\tcontent: result.content,\n\t\tsimilarity: result.similarity,\n\t\tmetadata: {\n\t\t\tdocumentId: result.documentId,\n\t\t\tdocumentName: result.documentName,\n\t\t\tchunkIndex: result.chunkIndex,\n\t\t},\n\t};\n}\n\nexport function toMemoryResult(result: {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n}): UnifiedMemorySearchResult {\n\treturn {\n\t\ttype: \"memory\",\n\t\tid: result.id,\n\t\tcontent: result.content,\n\t\tsimilarity: result.similarity,\n\t\tmetadata: result.metadata,\n\t};\n}\n\nexport function isRawMemorySemanticResult(result: unknown): result is {\n\tid: string;\n\tcontent: string;\n\tsimilarity: number;\n\tmetadata: Record<string, unknown>;\n} {\n\tif (!result || typeof result !== \"object\") {\n\t\treturn false;\n\t}\n\tconst item = result as Record<string, unknown>;\n\treturn (\n\t\ttypeof item.id === \"string\" &&\n\t\ttypeof item.content === \"string\" &&\n\t\ttypeof item.similarity === \"number\" &&\n\t\tBoolean(item.metadata) &&\n\t\ttypeof item.metadata === \"object\"\n\t);\n}\n","/**\n * Unified semantic search facade.\n *\n * Cross-source search over raw messages (always), insights, and\n * uploaded knowledge documents. The host wires up the cross-domain\n * dependencies via `UnifiedSearchDeps` so this module stays\n * framework-agnostic.\n */\n\nimport type { UnifiedSearchDeps } from \"../config\";\nimport { isRawMessageChromaEnabled, searchRawMessagesWithChroma } from \"../storage/chroma-memory-index\";\nimport { isRawMessageStorageAvailable } from \"../storage/raw-message-store\";\nimport {\n\ttype UnifiedMemorySearchInput,\n\ttype UnifiedMemorySearchOutput,\n\ttype UnifiedMemorySearchResult,\n\ttype UnifiedMemorySearchWarning,\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./utilities\";\n\nexport type {\n\tUnifiedMemorySearchInput,\n\tUnifiedMemorySearchOutput,\n\tUnifiedMemorySearchResult,\n\tUnifiedMemorySearchSource,\n\tUnifiedMemorySearchWarning,\n} from \"./utilities\";\n\nexport {\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./utilities\";\n\nexport interface UnifiedSearch {\n\tsearchUnifiedMemory(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchOutput>;\n\tsearchRawMemorySemantically(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchResult[]>;\n}\n\nexport function createUnifiedSearch(deps: UnifiedSearchDeps = {}): UnifiedSearch {\n\tconst logger = (deps as { logger?: Console }).logger ?? console;\n\n\tasync function searchUnifiedMemory(input: UnifiedMemorySearchInput): Promise<UnifiedMemorySearchOutput> {\n\t\tconst query = input.query.trim();\n\t\tconst sources = normalizeUnifiedMemorySearchSources(input.sources);\n\t\tconst limit = clampUnifiedMemorySearchLimit(input.limit);\n\t\tconst threshold = clampUnifiedMemorySearchThreshold(input.threshold);\n\t\tconst warnings: UnifiedMemorySearchWarning[] = [];\n\t\tconst results: UnifiedMemorySearchResult[] = [];\n\n\t\tif (!query) {\n\t\t\treturn {\n\t\t\t\tquery,\n\t\t\t\tsources,\n\t\t\t\tresults: [],\n\t\t\t\tcount: 0,\n\t\t\t\twarnings,\n\t\t\t};\n\t\t}\n\n\t\tif (sources.includes(\"memory\")) {\n\t\t\tif (isRawMessageStorageAvailable()) {\n\t\t\t\ttry {\n\t\t\t\t\tconst memoryHits = await runMemorySource(input, limit, threshold);\n\t\t\t\t\tresults.push(...memoryHits);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tlogger.warn?.(\"[memory-store] memory source failed:\", error);\n\t\t\t\t\twarnings.push({\n\t\t\t\t\t\tsource: \"memory\",\n\t\t\t\t\t\tcode: \"memory_search_failed\",\n\t\t\t\t\t\tmessage: (error as Error).message ?? \"memory_search_failed\",\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"memory\",\n\t\t\t\t\tcode: \"raw_message_storage_unavailable\",\n\t\t\t\t\tmessage: \"Raw memory storage is not available in this environment.\",\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (sources.includes(\"insights\") && typeof deps.searchInsights === \"function\") {\n\t\t\ttry {\n\t\t\t\tconst insightHits = await deps.searchInsights({\n\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\tquery: input.query,\n\t\t\t\t\tlimit,\n\t\t\t\t\tthreshold,\n\t\t\t\t\tbotIds: input.botIds,\n\t\t\t\t\tincludeArchived: input.includeArchivedInsights,\n\t\t\t\t\tauthToken: input.authToken,\n\t\t\t\t});\n\t\t\t\tfor (const hit of insightHits) {\n\t\t\t\t\tresults.push({\n\t\t\t\t\t\ttype: \"insight\",\n\t\t\t\t\t\tid: hit.id,\n\t\t\t\t\t\tcontent: hit.content,\n\t\t\t\t\t\tsimilarity: hit.similarity,\n\t\t\t\t\t\tmetadata: hit.metadata,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\"[memory-store] insights source failed:\", error);\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"insights\",\n\t\t\t\t\tcode: \"insights_search_failed\",\n\t\t\t\t\tmessage: (error as Error).message ?? \"insights_search_failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (sources.includes(\"insights\")) {\n\t\t\twarnings.push({\n\t\t\t\tsource: \"insights\",\n\t\t\t\tcode: \"insights_search_not_configured\",\n\t\t\t\tmessage: \"Insights search is not configured for this host.\",\n\t\t\t});\n\t\t}\n\n\t\tif (sources.includes(\"knowledge\") && typeof deps.searchKnowledge === \"function\") {\n\t\t\ttry {\n\t\t\t\tconst knowledgeHits = await deps.searchKnowledge({\n\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\tquery: input.query,\n\t\t\t\t\toptions: {\n\t\t\t\t\t\tlimit,\n\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\tdocumentIds: input.documentIds,\n\t\t\t\t\t},\n\t\t\t\t\tauthToken: input.authToken,\n\t\t\t\t});\n\t\t\t\tfor (const hit of knowledgeHits) {\n\t\t\t\t\tresults.push(toKnowledgeResult(hit));\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\"[memory-store] knowledge source failed:\", error);\n\t\t\t\twarnings.push({\n\t\t\t\t\tsource: \"knowledge\",\n\t\t\t\t\tcode: \"knowledge_search_failed\",\n\t\t\t\t\tmessage: (error as Error).message ?? \"knowledge_search_failed\",\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (sources.includes(\"knowledge\")) {\n\t\t\twarnings.push({\n\t\t\t\tsource: \"knowledge\",\n\t\t\t\tcode: \"knowledge_search_not_configured\",\n\t\t\t\tmessage: \"Knowledge search is not configured for this host.\",\n\t\t\t});\n\t\t}\n\n\t\tconst merged = mergeUnifiedMemorySearchResults(results, limit);\n\n\t\treturn {\n\t\t\tquery: input.query,\n\t\t\tsources,\n\t\t\tresults: merged,\n\t\t\tcount: merged.length,\n\t\t\twarnings,\n\t\t};\n\t}\n\n\tasync function runMemorySource(\n\t\tinput: UnifiedMemorySearchInput,\n\t\tlimit: number,\n\t\tthreshold: number,\n\t): Promise<UnifiedMemorySearchResult[]> {\n\t\tif (typeof deps.embedQuery !== \"function\") {\n\t\t\tthrow new Error(\"embedQuery is not configured\");\n\t\t}\n\n\t\tconst queryEmbedding = await deps.embedQuery({\n\t\t\tuserId: input.userId,\n\t\t\tquery: input.query,\n\t\t\tauthToken: input.authToken,\n\t\t});\n\n\t\tconst filters = input.botIds && input.botIds.length > 0 ? input.botIds.map((botId) => ({ botId })) : [{}];\n\n\t\tif (isRawMessageChromaEnabled()) {\n\t\t\ttry {\n\t\t\t\tconst chromaHits = (\n\t\t\t\t\tawait Promise.all(\n\t\t\t\t\t\tfilters.map((filter) => {\n\t\t\t\t\t\t\tconst botId = \"botId\" in filter ? filter.botId : undefined;\n\t\t\t\t\t\t\treturn searchRawMessagesWithChroma({\n\t\t\t\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\t\t\t\tqueryEmbedding,\n\t\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\t\t\tbotId,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}),\n\t\t\t\t\t)\n\t\t\t\t)\n\t\t\t\t\t.flat()\n\t\t\t\t\t.map(toMemoryResult);\n\t\t\t\tlogger.log?.(\"[memory-store] Raw message semantic search completed\", {\n\t\t\t\t\tbackend: \"chroma\",\n\t\t\t\t\tdimensions: queryEmbedding.length,\n\t\t\t\t\tcount: chromaHits.length,\n\t\t\t\t});\n\t\t\t\treturn chromaHits;\n\t\t\t} catch (error) {\n\t\t\t\tlogger.warn?.(\n\t\t\t\t\t\"[memory-store] Chroma raw message search failed; falling back to database search:\",\n\t\t\t\t\terror,\n\t\t\t\t);\n\t\t\t\t// fall through to the ANN/database search below\n\t\t\t}\n\t\t}\n\n\t\tif (typeof deps.searchRawMessagesAnn === \"function\") {\n\t\t\tconst rows = (\n\t\t\t\tawait Promise.all(\n\t\t\t\t\tfilters.map((filter) =>\n\t\t\t\t\t\tdeps.searchRawMessagesAnn!({\n\t\t\t\t\t\t\tuserId: input.userId,\n\t\t\t\t\t\t\tqueryEmbedding,\n\t\t\t\t\t\t\tlimit,\n\t\t\t\t\t\t\tthreshold,\n\t\t\t\t\t\t\tbotId: \"botId\" in filter ? filter.botId : undefined,\n\t\t\t\t\t\t}),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t)\n\t\t\t\t.flat()\n\t\t\t\t.filter(isRawMemorySemanticResult)\n\t\t\t\t.map(toMemoryResult);\n\t\t\treturn rows;\n\t\t}\n\n\t\treturn [];\n\t}\n\n\tasync function searchRawMemorySemantically(\n\t\tinput: UnifiedMemorySearchInput,\n\t): Promise<UnifiedMemorySearchResult[]> {\n\t\tconst limit = clampUnifiedMemorySearchLimit(input.limit);\n\t\tconst threshold = clampUnifiedMemorySearchThreshold(input.threshold);\n\t\treturn runMemorySource(input, limit, threshold);\n\t}\n\n\treturn { searchUnifiedMemory, searchRawMemorySemantically };\n}\n","/**\n * @melandlabs/memory-store — SDK entry point.\n *\n * Wires up a top-level `MemoryStore` facade combining the raw message\n * manager, the unified search facade, and vector index helpers. Hosts\n * that want a non-web backend (CLI daemon, custom server) can use\n * this as the only entry point.\n */\n\nimport type { MemoryStoreConfig } from \"./config\";\nimport { type UnifiedSearch, createUnifiedSearch } from \"./search/unified-search\";\nimport {\n\ttype RawMessageStore,\n\tconfigureRawMessageStore,\n\tcreateRawMessageStore,\n\tgetRawMessageManager,\n} from \"./storage/raw-message-store\";\n\nexport interface MemoryStore {\n\t/** Underlying raw-message store (sqlite vs postgres). */\n\traw: RawMessageStore;\n\t/** Unified semantic search facade (memory + insights + knowledge). */\n\tsearch: UnifiedSearch;\n\t/** Resolve the active raw-message manager. */\n\tgetRawMessageManager: typeof getRawMessageManager;\n\t/** Run `searchUnifiedMemory` against the wired-up unified search. */\n\tsearchUnifiedMemory: UnifiedSearch[\"searchUnifiedMemory\"];\n\t/** Convenience: semantic search over raw messages only. */\n\tsearchRawMemorySemantically: UnifiedSearch[\"searchRawMemorySemantically\"];\n}\n\nexport async function createMemoryStore(config: MemoryStoreConfig = {}): Promise<MemoryStore> {\n\tconst raw = createRawMessageStore({ env: config.env });\n\tconst search = createUnifiedSearch(config.unified);\n\n\t// Make the legacy `getRawMessageManager()` module-level facade\n\t// point at this configuration so callers that don't go through\n\t// `createMemoryStore` still get the right backend.\n\tconfigureRawMessageStore(config);\n\n\treturn {\n\t\traw,\n\t\tsearch,\n\t\tgetRawMessageManager,\n\t\tsearchUnifiedMemory: search.searchUnifiedMemory,\n\t\tsearchRawMemorySemantically: search.searchRawMemorySemantically,\n\t};\n}\n\nexport type { MemoryStoreConfig };\nexport {\n\tcreateRawMessageStore,\n\tgetRawMessageManager,\n\tisRawMessageStorageAvailable,\n\tgetRawMessageStorageBackend,\n\tcloseRawMessageStore,\n\ttype RawMessageStorageBackend,\n\ttype RawMessageStorageManagerWithSearch,\n} from \"./storage/raw-message-store\";\nexport {\n\tregisterPostgresFactory,\n\tclearPostgresFactory,\n\thasPostgresFactory,\n\tresolvePostgresFactory,\n\ttype PostgresFactoryFn,\n\ttype PostgresRawMessageManagerLike,\n} from \"./storage/postgres-raw-message-factory\";\nexport {\n\tcreateUnifiedSearch,\n\ttype UnifiedSearch,\n} from \"./search/unified-search\";\nexport type {\n\tUnifiedMemorySearchInput,\n\tUnifiedMemorySearchOutput,\n\tUnifiedMemorySearchResult,\n\tUnifiedMemorySearchSource,\n\tUnifiedMemorySearchWarning,\n} from \"./search/utilities\";\nexport {\n\tclampUnifiedMemorySearchLimit,\n\tclampUnifiedMemorySearchThreshold,\n\tisRawMemorySemanticResult,\n\tmergeUnifiedMemorySearchResults,\n\tnormalizeUnifiedMemorySearchSources,\n\ttoKnowledgeResult,\n\ttoMemoryResult,\n} from \"./search/utilities\";\nexport type {\n\tMemoryStoreDb,\n\tMemoryStoreEnv,\n\tVectorBackend,\n\tEmbedQueryFn,\n\tUnifiedSearchKnowledgeResult,\n\tUnifiedSearchInsightsResult,\n} from \"./config\";\nexport type { RawMessage } from \"./config\";\n"]}
|
package/dist/mcp.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { M as MemoryStoreConfig } from './config-MlK9f9CM.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @melandlabs/memory-store/mcp — MCP server entry.
|
|
6
|
+
*
|
|
7
|
+
* Spawns an MCP server (stdio transport by default) that exposes the
|
|
8
|
+
* memory-store as tools any MCP client (Claude Code, etc.) can invoke.
|
|
9
|
+
*
|
|
10
|
+
* Tools registered:
|
|
11
|
+
* - memory.searchUnified → UnifiedMemorySearchOutput
|
|
12
|
+
* - memory.writeRawMessage → { ok: boolean }
|
|
13
|
+
* - memory.getRawMessage → RawMessage | null
|
|
14
|
+
* - memory.health → { ok: true }
|
|
15
|
+
*
|
|
16
|
+
* Usage:
|
|
17
|
+
* import { startMcpServer } from "@melandlabs/memory-store/mcp";
|
|
18
|
+
* await startMcpServer({ db: { getDb }, env: { isTauriMode } });
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
interface StartMcpServerOptions extends MemoryStoreConfig {
|
|
22
|
+
/** Server name surfaced to the MCP client. */
|
|
23
|
+
name?: string;
|
|
24
|
+
/** Server version surfaced to the MCP client. */
|
|
25
|
+
version?: string;
|
|
26
|
+
}
|
|
27
|
+
declare function startMcpServer(options?: StartMcpServerOptions): Promise<McpServer>;
|
|
28
|
+
|
|
29
|
+
export { MemoryStoreConfig, type StartMcpServerOptions, startMcpServer };
|