@@ -525,6 +525,48 @@ async def test_semantic_search_uses_execution_folder_path(self, semantic_config)
525525 call_kwargs = mock_retriever_class .call_args [1 ]
526526 assert call_kwargs ["folder_path" ] == "/Shared/TestFolder"
527527
528+ @pytest .mark .asyncio
529+ async def test_semantic_search_enables_system_index_fallback_in_studio_project (
530+ self ,
531+ semantic_config ,
532+ monkeypatch : pytest .MonkeyPatch ,
533+ ) -> None :
534+ monkeypatch .setenv ("UIPATH_PROJECT_ID" , "some-project-id" )
535+ with patch (
536+ "uipath_langchain.agent.tools.context_tool.ContextGroundingRetriever"
537+ ) as mock_retriever_class :
538+ mock_retriever = AsyncMock ()
539+ mock_retriever .ainvoke .return_value = []
540+ mock_retriever_class .return_value = mock_retriever
541+
542+ tool = handle_semantic_search ("semantic_tool" , semantic_config )
543+ assert tool .coroutine is not None
544+ await tool .coroutine (query = "test query" )
545+
546+ call_kwargs = mock_retriever_class .call_args .kwargs
547+ assert call_kwargs ["include_system_indexes" ] is True
548+
549+ @pytest .mark .asyncio
550+ async def test_semantic_search_disables_system_index_fallback_outside_studio_project (
551+ self ,
552+ semantic_config ,
553+ monkeypatch : pytest .MonkeyPatch ,
554+ ) -> None :
555+ monkeypatch .delenv ("UIPATH_PROJECT_ID" , raising = False )
556+ with patch (
557+ "uipath_langchain.agent.tools.context_tool.ContextGroundingRetriever"
558+ ) as mock_retriever_class :
559+ mock_retriever = AsyncMock ()
560+ mock_retriever .ainvoke .return_value = []
561+ mock_retriever_class .return_value = mock_retriever
562+
563+ tool = handle_semantic_search ("semantic_tool" , semantic_config )
564+ assert tool .coroutine is not None
565+ await tool .coroutine (query = "test query" )
566+
567+ call_kwargs = mock_retriever_class .call_args .kwargs
568+ assert call_kwargs ["include_system_indexes" ] is False
569+
528570
529571class TestHandleBatchTransform :
530572 """Test cases for handle_batch_transform function."""
@@ -1095,3 +1137,87 @@ async def test_non_400_enriched_exception_propagates(
10951137
10961138 with pytest .raises (EnrichedException ):
10971139 await tool .coroutine (query = "test query" )
1140+
1141+
1142+ class TestSemanticSearchSystemIndexFallbackIntegration :
1143+ """End-to-end mocked test that exercises the full SDK chain.
1144+
1145+ Verifies that when running as a Studio project (debug run), the agent's
1146+ semantic-search tool resolves the index via the system-indexes
1147+ endpoint after the across-folders listing returns empty, and
1148+ successfully runs the unified search against the resolved id.
1149+ """
1150+
1151+ @pytest .mark .asyncio
1152+ async def test_resolves_system_index_and_runs_unified_search (
1153+ self ,
1154+ httpx_mock ,
1155+ monkeypatch : pytest .MonkeyPatch ,
1156+ ) -> None :
1157+ monkeypatch .setenv ("UIPATH_URL" , "https://cloud.uipath.com/org/tenant" )
1158+ monkeypatch .setenv ("UIPATH_ACCESS_TOKEN" , "test-token" )
1159+ monkeypatch .setenv ("UIPATH_ORGANIZATION_ID" , "org-id" )
1160+ monkeypatch .setenv ("UIPATH_TENANT_ID" , "tenant-id" )
1161+ monkeypatch .setenv ("UIPATH_TRACING_ENABLED" , "False" )
1162+ monkeypatch .setenv ("UIPATH_PROJECT_ID" , "studio-project-id" )
1163+ monkeypatch .delenv ("UIPATH_FOLDER_PATH" , raising = False )
1164+ monkeypatch .delenv ("UIPATH_FOLDER_KEY" , raising = False )
1165+
1166+ base = "https://cloud.uipath.com/org/tenant"
1167+ httpx_mock .add_response (
1168+ url = f"{ base } /ecs_/v2/indexes/allacrossfolders?$expand=dataSource&$filter=Name eq 'system-template-index'" ,
1169+ status_code = 200 ,
1170+ json = {"value" : []},
1171+ )
1172+ httpx_mock .add_response (
1173+ url = f"{ base } /ecs_/v2/indexes/allsystemindexes?$expand=dataSource&$filter=Name eq 'system-template-index'" ,
1174+ status_code = 200 ,
1175+ json = {
1176+ "value" : [
1177+ {
1178+ "id" : "sys-1" ,
1179+ "name" : "system-template-index" ,
1180+ "lastIngestionStatus" : "Completed" ,
1181+ }
1182+ ]
1183+ },
1184+ )
1185+ httpx_mock .add_response (
1186+ url = f"{ base } /ecs_/v1.2/search/sys-1" ,
1187+ status_code = 200 ,
1188+ json = {
1189+ "semanticResults" : {
1190+ "metadata" : {"operation_id" : "op-1" , "strategy" : "semantic" },
1191+ "values" : [
1192+ {
1193+ "id" : "doc-1" ,
1194+ "source" : "src" ,
1195+ "page_number" : 1 ,
1196+ "content" : "hello world" ,
1197+ "score" : 0.9 ,
1198+ }
1199+ ],
1200+ }
1201+ },
1202+ )
1203+
1204+ resource = _make_context_resource (
1205+ name = "semantic_tool" ,
1206+ description = "Semantic search tool" ,
1207+ index_name = "system-template-index" ,
1208+ retrieval_mode = AgentContextRetrievalMode .SEMANTIC ,
1209+ query_variant = "dynamic" ,
1210+ )
1211+
1212+ tool = handle_semantic_search ("semantic_tool" , resource )
1213+ assert tool .coroutine is not None
1214+ result = await tool .coroutine (query = "hi" )
1215+
1216+ assert "documents" in result
1217+ assert len (result ["documents" ]) == 1
1218+ assert result ["documents" ][0 ]["page_content" ] == "hello world"
1219+
1220+ urls = [str (r .url ) for r in httpx_mock .get_requests ()]
1221+ assert any ("/v2/indexes/allacrossfolders" in u for u in urls )
1222+ assert any ("/v2/indexes/allsystemindexes" in u for u in urls )
1223+ assert any ("/v1.2/search/sys-1" in u for u in urls )
0 commit comments