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

Method serveTaskSearch

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

Source from the content-addressed store, hash-verified

764 }
765
766 private async serveTaskSearch(res: http.ServerResponse, url: URL): Promise<void> {
767 const q = (url.searchParams.get("q") ?? "").trim();
768 if (!q) { this.jsonResponse(res, { tasks: [], total: 0 }); return; }
769
770 const owner = url.searchParams.get("owner") ?? undefined;
771 const maxResults = Math.min(50, Math.max(1, Number(url.searchParams.get("limit")) || 20));
772
773 const scoreMap = new Map<string, number>();
774
775 if (this.embedder) {
776 try {
777 const [queryVec] = await this.embedder.embed([q]);
778 const allEmb = this.store.getTaskEmbeddings(owner);
779 for (const { taskId, vector } of allEmb) {
780 let dot = 0, normA = 0, normB = 0;
781 for (let i = 0; i < queryVec.length && i < vector.length; i++) {
782 dot += queryVec[i] * vector[i];
783 normA += queryVec[i] * queryVec[i];
784 normB += vector[i] * vector[i];
785 }
786 const sim = normA > 0 && normB > 0 ? dot / (Math.sqrt(normA) * Math.sqrt(normB)) : 0;
787 if (sim > 0.3) scoreMap.set(taskId, sim);
788 }
789 } catch { /* embedding unavailable, fall through to FTS */ }
790 }
791
792 const ftsResults = this.store.taskFtsSearch(q, maxResults, owner);
793 for (const { taskId, score } of ftsResults) {
794 const existing = scoreMap.get(taskId) ?? 0;
795 scoreMap.set(taskId, Math.max(existing, score * 0.8));
796 }
797
798 const sorted = [...scoreMap.entries()]
799 .sort((a, b) => b[1] - a[1])
800 .slice(0, maxResults);
801
802 const db = (this.store as any).db;
803 const tasks = sorted.map(([taskId, score]) => {
804 const t = this.store.getTask(taskId);
805 if (!t) return null;
806 const meta = db.prepare("SELECT skill_status, owner FROM tasks WHERE id = ?").get(taskId) as { skill_status: string | null; owner: string | null } | undefined;
807 const hubTask = this.getHubTaskForLocal(taskId);
808 const ts = this.resolveTaskTeamShareForApi(taskId, hubTask);
809 return {
810 id: t.id, sessionKey: t.sessionKey, title: t.title,
811 summary: t.summary ?? "", status: t.status,
812 startedAt: t.startedAt, endedAt: t.endedAt,
813 chunkCount: this.store.countChunksByTask(t.id),
814 skillStatus: meta?.skill_status ?? null,
815 owner: meta?.owner ?? "agent:main",
816 sharingVisibility: ts.visibility,
817 score,
818 };
819 }).filter(Boolean);
820
821 this.jsonResponse(res, { tasks, total: tasks.length });
822 }
823

Callers 1

handleRequestMethod · 0.95

Calls 13

jsonResponseMethod · 0.95
getHubTaskForLocalMethod · 0.95
filterMethod · 0.80
mapMethod · 0.80
prepareMethod · 0.80
getMethod · 0.65
embedMethod · 0.65
setMethod · 0.65
getTaskEmbeddingsMethod · 0.45
taskFtsSearchMethod · 0.45
getTaskMethod · 0.45

Tested by

no test coverage detected