async def _rag(
        self,
        query: str,
        *args,
        **kwargs,
    ) -> dict[str, Any]:
        """Execute a search using an internal RAG agent."""
        # Create a copy of the current configuration for the RAG agent
        config_copy = copy(self.config)
        config_copy.max_iterations = 10  # Could be configurable

        # Always include critical web search tools
        default_tools = ["web_search", "web_scrape"]

        # Get the configured RAG tools from the original config
        configured_tools = set(self.config.rag_tools or default_tools)

        # Combine default tools with all configured tools, ensuring no duplicates
        config_copy.rag_tools = list(
            set(default_tools + list(configured_tools))
        )

        logger.debug(f"Using RAG tools: {config_copy.rag_tools}")

        # Create a generation config for the RAG agent
        generation_config = GenerationConfig(
            model=self.app_config.quality_llm,
            max_tokens_to_sample=16000,
        )

        # Create a new RAG agent - we'll use the non-streaming variant for consistent results
        rag_agent = R2RRAGAgent(
            database_provider=self.database_provider,
            llm_provider=self.llm_provider,
            config=config_copy,
            search_settings=self.search_settings,
            rag_generation_config=generation_config,
            knowledge_search_method=self.knowledge_search_method,
            content_method=self.content_method,
            file_search_method=self.file_search_method,
            max_tool_context_length=self.max_tool_context_length,
        )

        # Run the RAG agent with the query
        user_message = Message(role="user", content=query)
        response = await rag_agent.arun(messages=[user_message])

        # Get the content from the response
        structured_content = response[-1].get("structured_content")
        if structured_content:
            possible_text = structured_content[-1].get("text")
            content = response[-1].get("content") or possible_text
        else:
            content = response[-1].get("content")

        # Extract citations and transfer search results from RAG agent to research agent
        short_ids = extract_citations(content)
        if short_ids:
            logger.info(f"Found citations in RAG response: {short_ids}")

            for short_id in short_ids:
                result = rag_agent.search_results_collector.find_by_short_id(
                    short_id
                )
                if result:
                    self.search_results_collector.add_result(result)

            # Log confirmation for successful transfer
            logger.info(
                "Transferred search results from RAG agent to research agent for citations"
            )
        return content
Execute a search using an internal RAG agent.
py/core/agent/research.py