From 3660b91e6312921d0ba7398a274012145980110b Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Wed, 24 Dec 2025 20:12:40 +0200 Subject: [PATCH 1/4] refact: follow the structure of document returned from retriever --- .../app/tasks/chat/stream_new_chat.py | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/surfsense_backend/app/tasks/chat/stream_new_chat.py b/surfsense_backend/app/tasks/chat/stream_new_chat.py index 2038e85dc..940538bff 100644 --- a/surfsense_backend/app/tasks/chat/stream_new_chat.py +++ b/surfsense_backend/app/tasks/chat/stream_new_chat.py @@ -59,11 +59,28 @@ def format_mentioned_documents_as_context(documents: list[Document]) -> str: "These documents are directly relevant to the query and should be prioritized as primary sources." ) for i, doc in enumerate(documents, 1): - context_parts.append( - f"" - ) - context_parts.append(f"") - context_parts.append("") + # Prepare retriever-style structure + doc_metadata = doc.document_metadata if doc.document_metadata else {} + xml_doc = f""" + + {doc.id} + + 1.0 + + + {doc.id}-full + + + + + {doc.id} + <![CDATA[{doc.title}]]> + {doc.document_type.value} + + + {doc.document_type.value} + """ + context_parts.append(xml_doc.strip()) context_parts.append("") return "\n".join(context_parts) From ef9e9b65df42eb829c8dc0f20f9bc61a3fe4a612 Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Wed, 24 Dec 2025 23:35:20 +0200 Subject: [PATCH 2/4] fix: mentioned documents xml structure --- .../app/tasks/chat/stream_new_chat.py | 65 ++++++++++--------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/surfsense_backend/app/tasks/chat/stream_new_chat.py b/surfsense_backend/app/tasks/chat/stream_new_chat.py index 940538bff..23c3daee2 100644 --- a/surfsense_backend/app/tasks/chat/stream_new_chat.py +++ b/surfsense_backend/app/tasks/chat/stream_new_chat.py @@ -52,38 +52,41 @@ def format_mentioned_documents_as_context(documents: list[Document]) -> str: """Format mentioned documents as context for the agent.""" if not documents: return "" + import json - context_parts = [""] - context_parts.append( - "The user has explicitly mentioned the following documents from their knowledge base. " - "These documents are directly relevant to the query and should be prioritized as primary sources." - ) - for i, doc in enumerate(documents, 1): - # Prepare retriever-style structure - doc_metadata = doc.document_metadata if doc.document_metadata else {} - xml_doc = f""" - - {doc.id} - - 1.0 - - - {doc.id}-full - - - - - {doc.id} - <![CDATA[{doc.title}]]> - {doc.document_type.value} - - - {doc.document_type.value} - """ - context_parts.append(xml_doc.strip()) - context_parts.append("") - - return "\n".join(context_parts) + parts = [] + for doc in documents: + metadata = doc.document_metadata or {} + chunks = ( + [ + {"chunk_id": c.id, "content": c.content} + for c in getattr(doc, "chunks", []) + ] + if hasattr(doc, "chunks") and doc.chunks + else [{"chunk_id": doc.id, "content": doc.content}] + ) + metadata_json = json.dumps(metadata, ensure_ascii=False) + parts.append("") + parts.append("") + parts.append(f" {doc.id}") + parts.append(f" {doc.document_type.value}") + parts.append(f" <![CDATA[{doc.title}]]>") + parts.append(" ") + parts.append(f" ") + parts.append("") + parts.append("") + parts.append("") + for ch in chunks: + ch_content = ch["content"] + ch_id = ch["chunk_id"] + if ch_id is None: + parts.append(f" ") + else: + parts.append(f" ") + parts.append("") + parts.append("") + parts.append("") + return "\n".join(parts).strip() async def stream_new_chat( From b4b7059035794a97821d6a48bd1eebe065cef464 Mon Sep 17 00:00:00 2001 From: "DESKTOP-RTLN3BA\\$punk" Date: Wed, 24 Dec 2025 18:00:03 -0800 Subject: [PATCH 3/4] Revert "Merge pull request #622 from CREDO23/documents-mentions" This reverts commit fb719faa0de2c8a121ce805395e91545c8d289e8, reversing changes made to efd20ea20837c9020821717cdb3bced0dd05d003. --- .../app/tasks/chat/stream_new_chat.py | 46 ++++++------------- 1 file changed, 13 insertions(+), 33 deletions(-) diff --git a/surfsense_backend/app/tasks/chat/stream_new_chat.py b/surfsense_backend/app/tasks/chat/stream_new_chat.py index 23c3daee2..2038e85dc 100644 --- a/surfsense_backend/app/tasks/chat/stream_new_chat.py +++ b/surfsense_backend/app/tasks/chat/stream_new_chat.py @@ -52,41 +52,21 @@ def format_mentioned_documents_as_context(documents: list[Document]) -> str: """Format mentioned documents as context for the agent.""" if not documents: return "" - import json - parts = [] - for doc in documents: - metadata = doc.document_metadata or {} - chunks = ( - [ - {"chunk_id": c.id, "content": c.content} - for c in getattr(doc, "chunks", []) - ] - if hasattr(doc, "chunks") and doc.chunks - else [{"chunk_id": doc.id, "content": doc.content}] + context_parts = [""] + context_parts.append( + "The user has explicitly mentioned the following documents from their knowledge base. " + "These documents are directly relevant to the query and should be prioritized as primary sources." + ) + for i, doc in enumerate(documents, 1): + context_parts.append( + f"" ) - metadata_json = json.dumps(metadata, ensure_ascii=False) - parts.append("") - parts.append("") - parts.append(f" {doc.id}") - parts.append(f" {doc.document_type.value}") - parts.append(f" <![CDATA[{doc.title}]]>") - parts.append(" ") - parts.append(f" ") - parts.append("") - parts.append("") - parts.append("") - for ch in chunks: - ch_content = ch["content"] - ch_id = ch["chunk_id"] - if ch_id is None: - parts.append(f" ") - else: - parts.append(f" ") - parts.append("") - parts.append("") - parts.append("") - return "\n".join(parts).strip() + context_parts.append(f"") + context_parts.append("") + context_parts.append("") + + return "\n".join(context_parts) async def stream_new_chat( From 2603db74eb7ff39bcd1f6fe53564fec416640802 Mon Sep 17 00:00:00 2001 From: "DESKTOP-RTLN3BA\\$punk" Date: Wed, 24 Dec 2025 18:03:22 -0800 Subject: [PATCH 4/4] feat: released 0.0.9 changelog --- surfsense_web/app/(home)/changelog/page.tsx | 116 ++++++++++++++++++ .../changelog/content/2025-12-24.mdx | 44 +++++++ surfsense_web/components/homepage/navbar.tsx | 1 + surfsense_web/lib/utils.ts | 8 ++ surfsense_web/mdx-components.tsx | 19 +++ surfsense_web/public/demo.mp4 | Bin 0 -> 17999800 bytes surfsense_web/source.config.ts | 21 +++- 7 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 surfsense_web/app/(home)/changelog/page.tsx create mode 100644 surfsense_web/changelog/content/2025-12-24.mdx create mode 100644 surfsense_web/public/demo.mp4 diff --git a/surfsense_web/app/(home)/changelog/page.tsx b/surfsense_web/app/(home)/changelog/page.tsx new file mode 100644 index 000000000..42c120048 --- /dev/null +++ b/surfsense_web/app/(home)/changelog/page.tsx @@ -0,0 +1,116 @@ +import { loader } from "fumadocs-core/source"; +import { changelog } from "@/.source/server"; +import { formatDate } from "@/lib/utils"; +import { getMDXComponents } from "@/mdx-components"; + +const source = loader({ + baseUrl: "/changelog", + source: changelog.toFumadocsSource(), +}); + +interface ChangelogData { + title: string; + date: string; + version?: string; + tags?: string[]; + body: React.ComponentType<{ components?: Record }>; +} + +interface ChangelogPageItem { + url: string; + data: ChangelogData; +} + +export default async function ChangelogPage() { + const allPages = source.getPages() as ChangelogPageItem[]; + const sortedChangelogs = allPages.sort((a, b) => { + const dateA = new Date(a.data.date).getTime(); + const dateB = new Date(b.data.date).getTime(); + return dateB - dateA; + }); + + return ( +
+ {/* Header */} +
+
+
+
+

+ Changelog +

+

+ Stay up to date with the latest updates and improvements to SurfSense. +

+
+
+
+
+ + {/* Timeline */} +
+
+ {sortedChangelogs.map((changelog) => { + const MDX = changelog.data.body; + const date = new Date(changelog.data.date); + const formattedDate = formatDate(date); + + return ( +
+
+
+
+ + + {changelog.data.version && ( +
+ {changelog.data.version} +
+ )} +
+
+ + {/* Right side - Content */} +
+ {/* Vertical timeline line */} +
+ {/* Timeline dot */} +
+
+ +
+
+

+ {changelog.data.title} +

+ + {/* Tags */} + {changelog.data.tags && changelog.data.tags.length > 0 && ( +
+ {changelog.data.tags.map((tag: string) => ( + + {tag} + + ))} +
+ )} +
+
+ +
+
+
+
+
+ ); + })} +
+
+
+ ); +} diff --git a/surfsense_web/changelog/content/2025-12-24.mdx b/surfsense_web/changelog/content/2025-12-24.mdx new file mode 100644 index 000000000..b4de6829c --- /dev/null +++ b/surfsense_web/changelog/content/2025-12-24.mdx @@ -0,0 +1,44 @@ +--- +title: "SurfSense v0.0.9 - Introducing the Agentic Architecture" +description: "SurfSense v0.0.9 introduces a new agentic architecture with intelligent source selection, temporal query understanding, and MCP compatibility." +date: "2025-12-24" +tags: ["Agentic", "Agent", "MCP"] +version: "0.0.9" +--- + +