my harness for niri
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

idk ill do embeddings later

+49
+12
src/memory.test.ts
··· 103 103 assert.ok(profile.tokens.includes("ana")) 104 104 }) 105 105 106 + test("buildSearchProfile body informativeness short-circuits on body-people", async () => { 107 + const withPerson = await __memoryTest.buildSearchProfile({ 108 + sender: "meowskullz", 109 + source: "DM", 110 + body: "yayy, who is rea", 111 + }) 112 + assert.equal(withPerson.bodyInformative, true) 113 + 114 + const empty = await __memoryTest.buildSearchProfile({ sender: "meowskullz", source: "DM", body: "" }) 115 + assert.equal(empty.bodyInformative, false) 116 + }) 117 + 106 118 test("buildSearchProfile detects people mentioned in body", async () => { 107 119 const profile = await __memoryTest.buildSearchProfile({ 108 120 sender: "meowskullz",
+37
src/memory.ts
··· 130 130 tokens: string[] 131 131 personQuery: boolean 132 132 eventQuery: boolean 133 + bodyInformative: boolean 133 134 } 134 135 135 136 type MemoryHitSignal = { ··· 583 584 return tokensFromText(raw) 584 585 } 585 586 587 + const BODY_INFORMATIVE_BM25_THRESHOLD = -5 588 + 589 + function bestBodyBm25(bodyTokens: string[]): number | null { 590 + if (bodyTokens.length === 0) return null 591 + const query = bodyTokens.map((token) => `"${token.replace(/"/g, '""')}"*`).join(" OR ") 592 + try { 593 + const row = getDb() 594 + .prepare( 595 + "select bm25(memory_chunks_fts, 5.0, 2.0, 1.0, 0.5) as r from memory_chunks_fts where memory_chunks_fts match ? order by r limit 1", 596 + ) 597 + .get(query) as { r: number } | undefined 598 + return row?.r ?? null 599 + } catch { 600 + return null 601 + } 602 + } 603 + 604 + function computeBodyInformativeness(bodyTokens: string[], bodyPeople: string[]): boolean { 605 + if (bodyPeople.length > 0) return true 606 + if (bodyTokens.length === 0) return false 607 + const top = bestBodyBm25(bodyTokens) 608 + if (top === null) return false 609 + return top <= BODY_INFORMATIVE_BM25_THRESHOLD 610 + } 611 + 586 612 async function knownPeopleHandles(aliasMap: AliasMap): Promise<Set<string>> { 587 613 const handles = new Set<string>() 588 614 if (await pathExists(PEOPLE_DIR)) { ··· 642 668 .filter(Boolean) 643 669 .join(" ") 644 670 .toLowerCase() 671 + 672 + const bodyInformative = computeBodyInformativeness(bodyTokens, bodyPeopleResolved) 645 673 646 674 return { 647 675 normalized, ··· 650 678 bodyTokens, 651 679 bodyPeople: bodyPeopleResolved, 652 680 tokens: combined.slice(0, MEMORY_QUERY_TOKEN_LIMIT), 681 + bodyInformative, 653 682 personQuery: 654 683 Boolean(sender) || 655 684 bodyPeopleResolved.length > 0 || ··· 865 894 const topSignal = memoryHitSignal(hits[0]!, profile) 866 895 867 896 if (profile.sender || profile.bodyPeople.length > 0) { 897 + if (!profile.bodyInformative) return false 868 898 if (topSignal.senderMatch) return true 869 899 if (topSignal.bodyOverlap >= 2) return true 870 900 if (topSignal.bodyOverlap >= 1 && topSignal.strongOverlap) return true ··· 1013 1043 1014 1044 const profile = await buildSearchProfile(queryParts) 1015 1045 if (profile.tokens.length === 0) return { messages: conversation, recalledChunkIds: [] } 1046 + 1047 + if ((profile.sender || profile.bodyPeople.length > 0) && !profile.bodyInformative) { 1048 + console.log( 1049 + `[memory] skipped query=${JSON.stringify(trimForPrompt(normalizeText(memoryQuery), 120))} sender=${profile.sender ?? "-"} reason=trivial-body`, 1050 + ) 1051 + return { messages: conversation, recalledChunkIds: [] } 1052 + } 1016 1053 1017 1054 const personCount = allPersonHandles(profile).length 1018 1055 const recallLimit = Math.min(