From f38ea779400a2405d710ff19272bd85b9085e28f Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Thu, 9 Apr 2026 18:10:34 +0530 Subject: [PATCH] chore: ran linting --- .../versions/122_drop_old_memory_tables.py | 32 +++++++++---- .../app/agents/new_chat/memory_extraction.py | 8 +--- .../new_chat/middleware/memory_injection.py | 8 +--- .../app/agents/new_chat/tools/registry.py | 8 +++- .../agents/new_chat/tools/update_memory.py | 38 +++++++-------- .../app/routes/search_spaces_routes.py | 5 +- .../app/tasks/chat/stream_new_chat.py | 2 +- .../components/MemoryContent.tsx | 15 +++--- .../components/assistant-ui/thread.tsx | 46 +++++++++---------- .../settings/search-space-settings-dialog.tsx | 17 ++++++- .../settings/team-memory-manager.tsx | 26 +++++------ .../settings/user-settings-dialog.tsx | 33 +++++++------ .../components/tool-ui/user-memory.tsx | 4 +- .../components/ui/floating-toolbar.tsx | 6 +-- 14 files changed, 137 insertions(+), 111 deletions(-) diff --git a/surfsense_backend/alembic/versions/122_drop_old_memory_tables.py b/surfsense_backend/alembic/versions/122_drop_old_memory_tables.py index 8f63c022b..163af6133 100644 --- a/surfsense_backend/alembic/versions/122_drop_old_memory_tables.py +++ b/surfsense_backend/alembic/versions/122_drop_old_memory_tables.py @@ -60,11 +60,21 @@ def downgrade() -> None: ); """ ) - op.execute("CREATE INDEX IF NOT EXISTS ix_user_memories_user_id ON user_memories(user_id);") - op.execute("CREATE INDEX IF NOT EXISTS ix_user_memories_search_space_id ON user_memories(search_space_id);") - op.execute("CREATE INDEX IF NOT EXISTS ix_user_memories_updated_at ON user_memories(updated_at);") - op.execute("CREATE INDEX IF NOT EXISTS ix_user_memories_category ON user_memories(category);") - op.execute("CREATE INDEX IF NOT EXISTS ix_user_memories_user_search_space ON user_memories(user_id, search_space_id);") + op.execute( + "CREATE INDEX IF NOT EXISTS ix_user_memories_user_id ON user_memories(user_id);" + ) + op.execute( + "CREATE INDEX IF NOT EXISTS ix_user_memories_search_space_id ON user_memories(search_space_id);" + ) + op.execute( + "CREATE INDEX IF NOT EXISTS ix_user_memories_updated_at ON user_memories(updated_at);" + ) + op.execute( + "CREATE INDEX IF NOT EXISTS ix_user_memories_category ON user_memories(category);" + ) + op.execute( + "CREATE INDEX IF NOT EXISTS ix_user_memories_user_search_space ON user_memories(user_id, search_space_id);" + ) op.execute( "CREATE INDEX IF NOT EXISTS user_memories_vector_index ON user_memories USING hnsw (embedding public.vector_cosine_ops);" ) @@ -83,9 +93,15 @@ def downgrade() -> None: ); """ ) - op.execute("CREATE INDEX IF NOT EXISTS ix_shared_memories_search_space_id ON shared_memories(search_space_id);") - op.execute("CREATE INDEX IF NOT EXISTS ix_shared_memories_updated_at ON shared_memories(updated_at);") - op.execute("CREATE INDEX IF NOT EXISTS ix_shared_memories_created_by_id ON shared_memories(created_by_id);") + op.execute( + "CREATE INDEX IF NOT EXISTS ix_shared_memories_search_space_id ON shared_memories(search_space_id);" + ) + op.execute( + "CREATE INDEX IF NOT EXISTS ix_shared_memories_updated_at ON shared_memories(updated_at);" + ) + op.execute( + "CREATE INDEX IF NOT EXISTS ix_shared_memories_created_by_id ON shared_memories(created_by_id);" + ) op.execute( "CREATE INDEX IF NOT EXISTS shared_memories_vector_index ON shared_memories USING hnsw (embedding public.vector_cosine_ops);" ) diff --git a/surfsense_backend/app/agents/new_chat/memory_extraction.py b/surfsense_backend/app/agents/new_chat/memory_extraction.py index 12ba560f3..5fcd0fb08 100644 --- a/surfsense_backend/app/agents/new_chat/memory_extraction.py +++ b/surfsense_backend/app/agents/new_chat/memory_extraction.py @@ -106,9 +106,7 @@ async def _call_extraction_llm( config={"tags": ["surfsense:internal", "memory-extraction"]}, ) text = ( - response.content - if isinstance(response.content, str) - else str(response.content) + response.content if isinstance(response.content, str) else str(response.content) ).strip() if text == "NO_UPDATE" or not text: @@ -155,9 +153,7 @@ async def _extract_user_memory( uid = UUID(user_id) if isinstance(user_id, str) else user_id async with shielded_async_session() as session: - result = await session.execute( - select(User).where(User.id == uid) - ) + result = await session.execute(select(User).where(User.id == uid)) user = result.scalars().first() if not user: return diff --git a/surfsense_backend/app/agents/new_chat/middleware/memory_injection.py b/surfsense_backend/app/agents/new_chat/middleware/memory_injection.py index 043eb05fe..8e692dfcb 100644 --- a/surfsense_backend/app/agents/new_chat/middleware/memory_injection.py +++ b/surfsense_backend/app/agents/new_chat/middleware/memory_injection.py @@ -91,9 +91,7 @@ class MemoryInjectionMiddleware(AgentMiddleware): # type: ignore[type-arg] return {"messages": new_messages} - async def _load_user_memory( - self, session: AsyncSession - ) -> tuple[str | None, bool]: + async def _load_user_memory(self, session: AsyncSession) -> tuple[str | None, bool]: """Return (memory_content, is_persisted). When the user has no saved memory but has a display name, a seed @@ -102,9 +100,7 @@ class MemoryInjectionMiddleware(AgentMiddleware): # type: ignore[type-arg] """ try: result = await session.execute( - select(User.memory_md, User.display_name).where( - User.id == self.user_id - ) + select(User.memory_md, User.display_name).where(User.id == self.user_id) ) row = result.one_or_none() if row is None: diff --git a/surfsense_backend/app/agents/new_chat/tools/registry.py b/surfsense_backend/app/agents/new_chat/tools/registry.py index 04f359a50..db15105ae 100644 --- a/surfsense_backend/app/agents/new_chat/tools/registry.py +++ b/surfsense_backend/app/agents/new_chat/tools/registry.py @@ -228,7 +228,13 @@ BUILTIN_TOOLS: list[ToolDefinition] = [ llm=deps.get("llm"), ) ), - requires=["user_id", "search_space_id", "db_session", "thread_visibility", "llm"], + requires=[ + "user_id", + "search_space_id", + "db_session", + "thread_visibility", + "llm", + ], ), # ========================================================================= # LINEAR TOOLS - create, update, delete issues diff --git a/surfsense_backend/app/agents/new_chat/tools/update_memory.py b/surfsense_backend/app/agents/new_chat/tools/update_memory.py index cbc9b67a4..d8172bfcd 100644 --- a/surfsense_backend/app/agents/new_chat/tools/update_memory.py +++ b/surfsense_backend/app/agents/new_chat/tools/update_memory.py @@ -42,6 +42,7 @@ _SECTION_HEADING_RE = re.compile(r"^##\s+(.+)$", re.MULTILINE) # Pinned-section helpers # --------------------------------------------------------------------------- + def _extract_pinned_headings(memory: str) -> set[str]: """Return the set of ``## …`` headings that contain ``(pinned)``.""" return set(_PINNED_RE.findall(memory)) @@ -59,9 +60,7 @@ def _extract_section_map(memory: str) -> dict[str, str]: return sections -def _validate_pinned_preserved( - old_memory: str | None, new_memory: str -) -> str | None: +def _validate_pinned_preserved(old_memory: str | None, new_memory: str) -> str | None: """Return an error message if pinned headings from *old_memory* are missing in *new_memory*, else ``None``.""" if not old_memory: @@ -81,9 +80,7 @@ def _validate_pinned_preserved( return None -def _restore_missing_pinned( - old_memory: str, consolidated: str -) -> str: +def _restore_missing_pinned(old_memory: str, consolidated: str) -> str: """Prepend any pinned sections from *old_memory* that are absent in *consolidated*.""" old_pinned = _extract_pinned_headings(old_memory) @@ -109,14 +106,13 @@ def _restore_missing_pinned( # Diff validation # --------------------------------------------------------------------------- + def _extract_headings(memory: str) -> set[str]: """Return all ``## …`` heading texts (without the ``## `` prefix).""" return set(_SECTION_HEADING_RE.findall(memory)) -def _validate_diff( - old_memory: str | None, new_memory: str -) -> list[str]: +def _validate_diff(old_memory: str | None, new_memory: str) -> list[str]: """Return a list of warning strings about suspicious changes.""" if not old_memory: return [] @@ -146,6 +142,7 @@ def _validate_diff( # Size validation & soft warning # --------------------------------------------------------------------------- + def _validate_memory_size(content: str) -> dict[str, Any] | None: """Return an error/warning dict if *content* is too large, else None.""" length = len(content) @@ -199,17 +196,13 @@ RULES: """ -async def _auto_consolidate( - content: str, llm: Any -) -> str | None: +async def _auto_consolidate(content: str, llm: Any) -> str | None: """Use a focused LLM call to consolidate *content* under the soft limit. Returns the consolidated string, or ``None`` if consolidation fails. """ try: - prompt = _CONSOLIDATION_PROMPT.format( - target=MEMORY_SOFT_LIMIT, content=content - ) + prompt = _CONSOLIDATION_PROMPT.format(target=MEMORY_SOFT_LIMIT, content=content) response = await llm.ainvoke( [HumanMessage(content=prompt)], config={"tags": ["surfsense:internal"]}, @@ -229,6 +222,7 @@ async def _auto_consolidate( # Shared save-and-respond logic # --------------------------------------------------------------------------- + async def _save_memory( *, updated_memory: str, @@ -295,12 +289,13 @@ async def _save_memory( return {"status": "error", "message": f"Failed to update {label}: {e}"} # --- build response --- - resp: dict[str, Any] = {"status": "saved", "message": f"{label.capitalize()} updated."} + resp: dict[str, Any] = { + "status": "saved", + "message": f"{label.capitalize()} updated.", + } if content is not updated_memory: - resp["notice"] = ( - "Memory was automatically consolidated to fit within limits." - ) + resp["notice"] = "Memory was automatically consolidated to fit within limits." diff_warnings = _validate_diff(old_memory, content) if diff_warnings: @@ -317,6 +312,7 @@ async def _save_memory( # Tool factories # --------------------------------------------------------------------------- + def create_update_memory_tool( user_id: str | UUID, db_session: AsyncSession, @@ -338,9 +334,7 @@ def create_update_memory_tool( updated_memory: The FULL updated markdown document (not a diff). """ try: - result = await db_session.execute( - select(User).where(User.id == uid) - ) + result = await db_session.execute(select(User).where(User.id == uid)) user = result.scalars().first() if not user: return {"status": "error", "message": "User not found."} diff --git a/surfsense_backend/app/routes/search_spaces_routes.py b/surfsense_backend/app/routes/search_spaces_routes.py index 6fd92fd18..0650b8dfe 100644 --- a/surfsense_backend/app/routes/search_spaces_routes.py +++ b/surfsense_backend/app/routes/search_spaces_routes.py @@ -257,7 +257,10 @@ async def update_search_space( update_data = search_space_update.model_dump(exclude_unset=True) - if "shared_memory_md" in update_data and len(update_data["shared_memory_md"] or "") > MEMORY_HARD_LIMIT: + if ( + "shared_memory_md" in update_data + and len(update_data["shared_memory_md"] or "") > MEMORY_HARD_LIMIT + ): raise HTTPException( status_code=400, detail=f"Team memory exceeds {MEMORY_HARD_LIMIT:,} character limit.", diff --git a/surfsense_backend/app/tasks/chat/stream_new_chat.py b/surfsense_backend/app/tasks/chat/stream_new_chat.py index 1cb858c51..d49400c18 100644 --- a/surfsense_backend/app/tasks/chat/stream_new_chat.py +++ b/surfsense_backend/app/tasks/chat/stream_new_chat.py @@ -29,7 +29,6 @@ from sqlalchemy.future import select from sqlalchemy.orm import selectinload from app.agents.new_chat.chat_deepagent import create_surfsense_deep_agent -from app.agents.new_chat.memory_extraction import extract_and_save_memory from app.agents.new_chat.checkpointer import get_checkpointer from app.agents.new_chat.llm_config import ( AgentConfig, @@ -38,6 +37,7 @@ from app.agents.new_chat.llm_config import ( load_agent_config, load_llm_config_from_yaml, ) +from app.agents.new_chat.memory_extraction import extract_and_save_memory from app.db import ( ChatVisibility, NewChatMessage, diff --git a/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/MemoryContent.tsx b/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/MemoryContent.tsx index 479e5a031..e8c632eb3 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/MemoryContent.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/MemoryContent.tsx @@ -4,9 +4,9 @@ import { Info } from "lucide-react"; import { useCallback, useEffect, useState } from "react"; import { toast } from "sonner"; import { z } from "zod"; +import { PlateEditor } from "@/components/editor/plate-editor"; import { Alert, AlertDescription } from "@/components/ui/alert"; import { Button } from "@/components/ui/button"; -import { PlateEditor } from "@/components/editor/plate-editor"; import { Spinner } from "@/components/ui/spinner"; import { baseApiService } from "@/lib/apis/base-api.service"; @@ -99,7 +99,10 @@ export function MemoryContent() { -

SurfSense uses this personal memory to personalize your responses across all conversations. Supports Markdown formatting.

+

+ SurfSense uses this personal memory to personalize your responses across all + conversations. Supports Markdown formatting. +

@@ -139,10 +142,10 @@ export function MemoryContent() { variant="outline" onClick={handleSave} disabled={saving || !hasChanges || isOverLimit} - className="relative gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200 items-center justify-center" - > - Save - {saving && } + className="relative gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200 items-center justify-center" + > + Save + {saving && } diff --git a/surfsense_web/components/assistant-ui/thread.tsx b/surfsense_web/components/assistant-ui/thread.tsx index 1188ed32a..7fb01401f 100644 --- a/surfsense_web/components/assistant-ui/thread.tsx +++ b/surfsense_web/components/assistant-ui/thread.tsx @@ -1021,29 +1021,29 @@ const ComposerAction: FC = ({ isBlockedByOtherUser = false })} )} - {!filteredTools?.length && ( -
- - {["t1", "t2", "t3", "t4"].map((k) => ( -
- - - -
- ))} - - {["c1", "c2", "c3"].map((k) => ( -
- - - -
- ))} -
- )} - - - + {!filteredTools?.length && ( +
+ + {["t1", "t2", "t3", "t4"].map((k) => ( +
+ + + +
+ ))} + + {["c1", "c2", "c3"].map((k) => ( +
+ + + +
+ ))} +
+ )} + + + @@ -143,10 +141,10 @@ export function TeamMemoryManager({ searchSpaceId }: TeamMemoryManagerProps) { variant="outline" onClick={handleSave} disabled={saving || !hasChanges || isOverLimit} - className="relative gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200 items-center justify-center" - > - Save - {saving && } + className="relative gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200 items-center justify-center" + > + Save + {saving && } diff --git a/surfsense_web/components/settings/user-settings-dialog.tsx b/surfsense_web/components/settings/user-settings-dialog.tsx index c82a64e06..1229e56a7 100644 --- a/surfsense_web/components/settings/user-settings-dialog.tsx +++ b/surfsense_web/components/settings/user-settings-dialog.tsx @@ -52,7 +52,10 @@ const DesktopContent = dynamic( { ssr: false } ); const MemoryContent = dynamic( - () => import("@/app/dashboard/[search_space_id]/user-settings/components/MemoryContent").then(m => ({ default: m.MemoryContent })), + () => + import("@/app/dashboard/[search_space_id]/user-settings/components/MemoryContent").then( + (m) => ({ default: m.MemoryContent }) + ), { ssr: false } ); @@ -79,17 +82,17 @@ export function UserSettingsDialog() { label: "Community Prompts", icon: , }, - { - value: "memory", - label: "Memory", - icon: , - }, - { - value: "purchases", - label: "Purchase History", - icon: , - }, - ...(isDesktop + { + value: "memory", + label: "Memory", + icon: , + }, + { + value: "purchases", + label: "Purchase History", + icon: , + }, + ...(isDesktop ? [{ value: "desktop", label: "Desktop", icon: }] : []), ], @@ -110,9 +113,9 @@ export function UserSettingsDialog() { {state.initialTab === "api-key" && } {state.initialTab === "prompts" && } {state.initialTab === "community-prompts" && } - {state.initialTab === "memory" && } - {state.initialTab === "purchases" && } - {state.initialTab === "desktop" && } + {state.initialTab === "memory" && } + {state.initialTab === "purchases" && } + {state.initialTab === "desktop" && } ); diff --git a/surfsense_web/components/tool-ui/user-memory.tsx b/surfsense_web/components/tool-ui/user-memory.tsx index 800b9e601..f7c446806 100644 --- a/surfsense_web/components/tool-ui/user-memory.tsx +++ b/surfsense_web/components/tool-ui/user-memory.tsx @@ -54,9 +54,7 @@ export const UpdateMemoryToolUI = ({
Failed to update memory - {result?.message && ( -

{result.message}

- )} + {result?.message &&

{result.message}

}
); diff --git a/surfsense_web/components/ui/floating-toolbar.tsx b/surfsense_web/components/ui/floating-toolbar.tsx index 409a063b9..3d5a73787 100644 --- a/surfsense_web/components/ui/floating-toolbar.tsx +++ b/surfsense_web/components/ui/floating-toolbar.tsx @@ -65,9 +65,9 @@ export function FloatingToolbar({ {...rootProps} ref={ref} className={cn( - "scrollbar-hide absolute z-50 overflow-x-auto whitespace-nowrap rounded-md border dark:border-neutral-700 bg-muted p-1 opacity-100 shadow-md print:hidden", - "max-w-[80vw]", - "[&_button:hover]:bg-neutral-200 dark:[&_button:hover]:bg-neutral-700", + "scrollbar-hide absolute z-50 overflow-x-auto whitespace-nowrap rounded-md border dark:border-neutral-700 bg-muted p-1 opacity-100 shadow-md print:hidden", + "max-w-[80vw]", + "[&_button:hover]:bg-neutral-200 dark:[&_button:hover]:bg-neutral-700", className )} >