MCPcopy Create free account
hub / github.com/MemTensor/MemOS / serveSearch

Method serveSearch

packages/memos-core/src/viewer/server.ts:987–1080  ·  view source on GitHub ↗
(_req: http.IncomingMessage, res: http.ServerResponse, url: URL)

Source from the content-addressed store, hash-verified

985 }
986
987 private async serveSearch(_req: http.IncomingMessage, res: http.ServerResponse, url: URL): Promise<void> {
988 const q = url.searchParams.get("q") ?? "";
989 if (!q.trim()) { this.jsonResponse(res, { results: [], query: q }); return; }
990
991 const role = url.searchParams.get("role") ?? undefined;
992 const session = url.searchParams.get("session") ?? undefined;
993 const owner = url.searchParams.get("owner") ?? undefined;
994 const dateFrom = url.searchParams.get("dateFrom") ?? undefined;
995 const dateTo = url.searchParams.get("dateTo") ?? undefined;
996
997 const passesFilter = (r: any): boolean => {
998 if (role && r.role !== role) return false;
999 if (session && r.session_key !== session) return false;
1000 if (owner && r.owner !== owner) return false;
1001 if (dateFrom && r.created_at < new Date(dateFrom).getTime()) return false;
1002 if (dateTo && r.created_at > new Date(dateTo).getTime()) return false;
1003 return true;
1004 };
1005
1006 const ftsFilters: string[] = [];
1007 const likeFilters: string[] = [];
1008 const sqlParams: any[] = [];
1009 if (session) { ftsFilters.push("c.session_key = ?"); likeFilters.push("session_key = ?"); sqlParams.push(session); }
1010 if (owner) { ftsFilters.push("c.owner = ?"); likeFilters.push("owner = ?"); sqlParams.push(owner); }
1011 const ftsWhere = ftsFilters.length > 0 ? " AND " + ftsFilters.join(" AND ") : "";
1012 const likeWhere = likeFilters.length > 0 ? " AND " + likeFilters.join(" AND ") : "";
1013
1014 const db = (this.store as any).db;
1015 let ftsResults: any[] = [];
1016 try {
1017 ftsResults = db.prepare(
1018 `SELECT c.* FROM chunks_fts f JOIN chunks c ON f.rowid = c.rowid WHERE chunks_fts MATCH ?${ftsWhere} ORDER BY rank LIMIT 100`,
1019 ).all(q, ...sqlParams).filter(passesFilter);
1020 } catch { /* FTS syntax error, fall through */ }
1021 if (ftsResults.length === 0) {
1022 try {
1023 ftsResults = db.prepare(
1024 `SELECT * FROM chunks WHERE (content LIKE ? OR summary LIKE ?)${likeWhere} ORDER BY created_at DESC LIMIT 100`,
1025 ).all(`%${q}%`, `%${q}%`, ...sqlParams).filter(passesFilter);
1026 } catch (err) {
1027 this.log.warn(`LIKE search failed: ${err}`);
1028 }
1029 }
1030
1031 const SEMANTIC_THRESHOLD = 0.64;
1032 const VECTOR_TIMEOUT_MS = 8000;
1033 let vectorResults: any[] = [];
1034 let scoreMap = new Map<string, number>();
1035 try {
1036 const vecPromise = (async () => {
1037 const queryVec = await this.embedder.embedQuery(q);
1038 return vectorSearch(this.store, queryVec, 40);
1039 })();
1040 const hits = await Promise.race([
1041 vecPromise,
1042 new Promise<null>((resolve) => setTimeout(() => resolve(null), VECTOR_TIMEOUT_MS)),
1043 ]);
1044 if (hits) {

Callers 1

handleRequestMethod · 0.95

Calls 14

jsonResponseMethod · 0.95
vectorSearchFunction · 0.90
resolveFunction · 0.85
filterMethod · 0.80
allMethod · 0.80
prepareMethod · 0.80
mapMethod · 0.80
getMethod · 0.65
warnMethod · 0.65
hasMethod · 0.65
joinMethod · 0.45
embedQueryMethod · 0.45

Tested by

no test coverage detected