From 5e84a92de260c7e07a68b092c1cd5c62984770e7 Mon Sep 17 00:00:00 2001 From: octo-patch Date: Mon, 20 Apr 2026 11:29:27 +0800 Subject: [PATCH] fix: propagate search_settings filters through agent tools and system context builder Fixes #2244 and #2245. Two related bugs caused search filter scoping (e.g. collection_ids) to be silently ignored, allowing agents to access documents outside the intended collection boundary: 1. _build_documents_context did not accept or forward filter_collection_ids to get_documents_overview, so the dynamic RAG system prompt listed all documents regardless of collection filters (#2245). 2. GetFileContentTool constructed a bare {"id": ...} filter, completely discarding any search_settings.filters (collection_ids etc.) set by the caller. A document_id returned by the LLM could therefore resolve to content from a different collection (#2244). Changes: - _build_documents_context now accepts filter_collection_ids and passes it to get_documents_overview. - _build_aware_system_instruction forwards filter_collection_ids when calling _build_documents_context. - GetFileContentTool.execute merges context.search_settings.filters into an $and compound filter alongside the document_id predicate. --- .../base/agent/tools/built_in/get_file_content.py | 14 +++++++++++++- py/core/main/services/retrieval_service.py | 3 +++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/py/core/base/agent/tools/built_in/get_file_content.py b/py/core/base/agent/tools/built_in/get_file_content.py index ce4e08181..e624dd41d 100644 --- a/py/core/base/agent/tools/built_in/get_file_content.py +++ b/py/core/base/agent/tools/built_in/get_file_content.py @@ -61,11 +61,23 @@ async def execute( try: doc_uuid = UUID(document_id) - filters = {"id": {"$eq": doc_uuid}} + doc_id_filter = {"id": {"$eq": doc_uuid}} except ValueError: logger.error(f"Invalid document_id format received: {document_id}") return AggregateSearchResult(document_search_results=[]) + # Merge search_settings filters (e.g., collection_ids) with the + # document_id filter so that collection-scoped queries are respected. + search_filters = ( + getattr(context.search_settings, "filters", None) + if hasattr(context, "search_settings") + else None + ) + if search_filters: + filters: dict[str, Any] = {"$and": [doc_id_filter, search_filters]} + else: + filters = doc_id_filter + options = options or {} try: diff --git a/py/core/main/services/retrieval_service.py b/py/core/main/services/retrieval_service.py index 29332cfde..1c8b667bd 100644 --- a/py/core/main/services/retrieval_service.py +++ b/py/core/main/services/retrieval_service.py @@ -1821,6 +1821,7 @@ def _parse_user_and_collection_filters( async def _build_documents_context( self, filter_user_id: Optional[UUID] = None, + filter_collection_ids: Optional[list[UUID]] = None, max_summary_length: int = 128, limit: int = 25, reverse_order: bool = True, @@ -1834,6 +1835,7 @@ async def _build_documents_context( offset=0, limit=limit, filter_user_ids=[filter_user_id] if filter_user_id else None, + filter_collection_ids=filter_collection_ids if filter_collection_ids else None, include_summary_embedding=False, sort_order="DESC" if reverse_order else "ASC", ) @@ -1910,6 +1912,7 @@ async def _build_aware_system_instruction( if use_system_context: doc_context_str = await self._build_documents_context( filter_user_id=filter_user_id, + filter_collection_ids=filter_collection_ids, ) logger.debug(f"Loading prompt {prompt_name}") # Now fetch the prompt from the database prompts handler