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 e39a78633..782c98ce3 100644 --- a/surfsense_backend/app/agents/new_chat/middleware/memory_injection.py +++ b/surfsense_backend/app/agents/new_chat/middleware/memory_injection.py @@ -19,8 +19,8 @@ from langgraph.runtime import Runtime from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession -from app.db import ChatVisibility, SearchSpace, User, shielded_async_session from app.agents.new_chat.tools.update_memory import MEMORY_HARD_LIMIT +from app.db import ChatVisibility, SearchSpace, User, shielded_async_session logger = logging.getLogger(__name__) @@ -96,10 +96,9 @@ class MemoryInjectionMiddleware(AgentMiddleware): # type: ignore[type-arg] ) -> tuple[str | None, bool]: """Return (memory_content, is_persisted). - When the user has saved memory in the database, ``is_persisted`` is - ``True``. When we fall back to a seed (first-name only), it is - ``False`` — the system prompt instructs the LLM to call - ``update_memory`` once to persist it. + When the user has no saved memory but has a display name, a seed + document is created and **persisted to the database immediately** + so the LLM doesn't need to make a tool call to save it. """ try: result = await session.execute( @@ -118,7 +117,15 @@ class MemoryInjectionMiddleware(AgentMiddleware): # type: ignore[type-arg] if display_name: first_name = display_name.split()[0] - return f"## About the user\n- Name: {first_name}", False + seed = f"## About the user\n- Name: {first_name}" + await session.execute( + User.__table__.update() + .where(User.id == self.user_id) + .values(memory_md=seed) + ) + await session.commit() + logger.info("Auto-persisted memory seed for user %s", self.user_id) + return seed, True return None, True except Exception: 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 007f45feb..cee450788 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 @@ -134,10 +134,10 @@ export function MemoryContent() { variant="outline" onClick={handleSave} disabled={saving || !hasChanges || isOverLimit} - className="gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200" - > - {saving && } - Save + 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/team-memory-manager.tsx b/surfsense_web/components/settings/team-memory-manager.tsx index 8fc33efcf..4162b272c 100644 --- a/surfsense_web/components/settings/team-memory-manager.tsx +++ b/surfsense_web/components/settings/team-memory-manager.tsx @@ -140,10 +140,10 @@ export function TeamMemoryManager({ searchSpaceId }: TeamMemoryManagerProps) { variant="outline" onClick={handleSave} disabled={saving || !hasChanges || isOverLimit} - className="gap-2 bg-white text-black hover:bg-neutral-100 dark:bg-white dark:text-black dark:hover:bg-neutral-200" - > - {saving && } - Save + 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 && }