mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-08-28 05:25:33 +00:00
Merge 275d5c8b16 into 3f7b9667c6
This commit is contained in:
commit
c1ec0aba8e
2 changed files with 116 additions and 12 deletions
81
apps/browser-extension/entrypoints/content/grok.test.ts
Normal file
81
apps/browser-extension/entrypoints/content/grok.test.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import { describe, expect, it } from "bun:test"
|
||||
import { removeGrokMemoryUiElements, sanitizeGrokMemoryText } from "./grok"
|
||||
|
||||
describe("sanitizeGrokMemoryText", () => {
|
||||
it("removes Grok interface text when it occupies a full line", () => {
|
||||
const text = [
|
||||
"Memory from your chats",
|
||||
"This summary is regenerated periodically from your conversations.",
|
||||
"Save to supermemory",
|
||||
"Close",
|
||||
"Delete memory",
|
||||
" Edit ",
|
||||
"The user prefers TypeScript.",
|
||||
].join("\r\n")
|
||||
|
||||
expect(sanitizeGrokMemoryText(text)).toBe("The user prefers TypeScript.")
|
||||
})
|
||||
|
||||
it("preserves interface words when they are part of user memories", () => {
|
||||
const text = [
|
||||
"Editor: VS Code",
|
||||
"I use the Edit command every day.",
|
||||
"Close friends know I prefer tea.",
|
||||
"Delete memory leaks before deploying.",
|
||||
"Memory from your chats can be useful.",
|
||||
].join("\n")
|
||||
|
||||
expect(sanitizeGrokMemoryText(text)).toBe(text)
|
||||
})
|
||||
|
||||
it("trims lines and removes empty whitespace", () => {
|
||||
expect(
|
||||
sanitizeGrokMemoryText("\n First memory \n\t\n Second memory \n"),
|
||||
).toBe("First memory\nSecond memory")
|
||||
})
|
||||
|
||||
it("removes UI elements without deleting formatted memory text", () => {
|
||||
const memory = createTextElement("Editor: VS Code")
|
||||
const heading = createTextElement("Memory from your chats")
|
||||
const description = createTextElement(
|
||||
"This summary is regenerated periodically from your conversations.",
|
||||
)
|
||||
const editButton = createTextElement("Edit")
|
||||
const deleteButton = createTextElement("Delete memory")
|
||||
const inlineEdit = createTextElement("Edit")
|
||||
const elements = [
|
||||
memory,
|
||||
heading,
|
||||
description,
|
||||
editButton,
|
||||
deleteButton,
|
||||
inlineEdit,
|
||||
]
|
||||
|
||||
removeGrokMemoryUiElements({
|
||||
querySelectorAll: (selector) => {
|
||||
if (selector.includes("div")) return [heading, description]
|
||||
if (selector.startsWith("button")) return [editButton, deleteButton]
|
||||
return []
|
||||
},
|
||||
})
|
||||
|
||||
const collapsedText = elements
|
||||
.filter((element) => !element.removed)
|
||||
.map((element) => element.textContent)
|
||||
.join("")
|
||||
expect(collapsedText).toBe("Editor: VS CodeEdit")
|
||||
expect(memory.removed).toBe(false)
|
||||
expect(inlineEdit.removed).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
function createTextElement(textContent: string) {
|
||||
return {
|
||||
textContent,
|
||||
removed: false,
|
||||
remove() {
|
||||
this.removed = true
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -265,33 +265,55 @@ function getGrokMemoryDialog(): HTMLElement | null {
|
|||
return candidates[0] || null
|
||||
}
|
||||
|
||||
const GROK_MEMORY_UI_TEXT = [
|
||||
const GROK_MEMORY_UI_TEXT = new Set([
|
||||
"Memory from your chats",
|
||||
"This summary is regenerated periodically from your conversations.",
|
||||
"Save to supermemory",
|
||||
"Close",
|
||||
"Delete memory",
|
||||
"Edit",
|
||||
])
|
||||
|
||||
const GROK_MEMORY_UI_ELEMENT_RULES = [
|
||||
{
|
||||
selector:
|
||||
"h1, h2, h3, h4, h5, h6, p, div, section, [role='heading'], [role='note']",
|
||||
text: new Set([
|
||||
"Memory from your chats",
|
||||
"This summary is regenerated periodically from your conversations.",
|
||||
]),
|
||||
},
|
||||
{
|
||||
selector:
|
||||
"button, [role='button'], [role='menuitem'], [role='tab'], [tabindex]",
|
||||
text: new Set(["Save to supermemory", "Close", "Delete memory", "Edit"]),
|
||||
},
|
||||
] as const
|
||||
|
||||
function escapeRegExp(text: string) {
|
||||
return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
||||
interface GrokMemoryTextElement {
|
||||
textContent: string | null
|
||||
remove(): void
|
||||
}
|
||||
|
||||
function sanitizeGrokMemoryText(text: string) {
|
||||
let sanitizedText = text
|
||||
interface GrokMemoryTextRoot {
|
||||
querySelectorAll(selectors: string): Iterable<GrokMemoryTextElement>
|
||||
}
|
||||
|
||||
for (const uiText of GROK_MEMORY_UI_TEXT) {
|
||||
sanitizedText = sanitizedText.replace(
|
||||
new RegExp(escapeRegExp(uiText), "g"),
|
||||
"\n",
|
||||
)
|
||||
export function removeGrokMemoryUiElements(root: GrokMemoryTextRoot) {
|
||||
for (const rule of GROK_MEMORY_UI_ELEMENT_RULES) {
|
||||
for (const element of root.querySelectorAll(rule.selector)) {
|
||||
if (rule.text.has(element.textContent?.trim() || "")) {
|
||||
element.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sanitizedText
|
||||
export function sanitizeGrokMemoryText(text: string) {
|
||||
return text
|
||||
.split("\n")
|
||||
.map((line) => line.trim())
|
||||
.filter((line) => line)
|
||||
.filter((line) => line && !GROK_MEMORY_UI_TEXT.has(line))
|
||||
.join("\n")
|
||||
.trim()
|
||||
}
|
||||
|
|
@ -299,6 +321,7 @@ function sanitizeGrokMemoryText(text: string) {
|
|||
function getGrokMemoryText(dialog: HTMLElement): string {
|
||||
const clonedDialog = dialog.cloneNode(true) as HTMLElement
|
||||
clonedDialog.querySelector("#supermemory-save-button")?.remove()
|
||||
removeGrokMemoryUiElements(clonedDialog)
|
||||
|
||||
const possibleMemoryContainers = Array.from(
|
||||
clonedDialog.querySelectorAll<HTMLElement>(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue