1919from ..errors import (
2020 BatchTransformFailedException ,
2121 BatchTransformNotCompleteException ,
22+ ContextGroundingIndexNotFoundError ,
2223 IngestionInProgressException ,
2324 UnsupportedDataSourceException ,
2425)
@@ -256,37 +257,107 @@ async def retrieve_across_folders_async(
256257 ContextGroundingIndex .model_validate (item ) for item in response ["value" ]
257258 ]
258259
260+ @traced (name = "contextgrounding_retrieve_system_indexes" , run_type = "uipath" )
261+ def retrieve_system_indexes (
262+ self ,
263+ name : Optional [str ] = None ,
264+ ) -> List [ContextGroundingIndex ]:
265+ """Retrieve tenant-wide system context grounding indexes.
266+
267+ System indexes are shared across all folders and tenants and do not
268+ require a folder key. They are typically used by bundled StudioWeb
269+ templates that reference shared indexes.
270+
271+ Args:
272+ name (Optional[str]): Optional name filter. If provided, only indexes
273+ matching this name will be returned.
274+
275+ Returns:
276+ List[ContextGroundingIndex]: A list of system indexes.
277+ """
278+ spec = self ._retrieve_system_indexes_spec (name = name )
279+
280+ response = self .request (
281+ spec .method ,
282+ spec .endpoint ,
283+ params = spec .params ,
284+ ).json ()
285+
286+ return [
287+ ContextGroundingIndex .model_validate (item ) for item in response ["value" ]
288+ ]
289+
290+ @traced (name = "contextgrounding_retrieve_system_indexes" , run_type = "uipath" )
291+ async def retrieve_system_indexes_async (
292+ self ,
293+ name : Optional [str ] = None ,
294+ ) -> List [ContextGroundingIndex ]:
295+ """Asynchronously retrieve tenant-wide system context grounding indexes.
296+
297+ System indexes are shared across all folders and tenants and do not
298+ require a folder key. They are typically used by bundled StudioWeb
299+ templates that reference shared indexes.
300+
301+ Args:
302+ name (Optional[str]): Optional name filter. If provided, only indexes
303+ matching this name will be returned.
304+
305+ Returns:
306+ List[ContextGroundingIndex]: A list of system indexes.
307+ """
308+ spec = self ._retrieve_system_indexes_spec (name = name )
309+
310+ response = (
311+ await self .request_async (
312+ spec .method ,
313+ spec .endpoint ,
314+ params = spec .params ,
315+ )
316+ ).json ()
317+
318+ return [
319+ ContextGroundingIndex .model_validate (item ) for item in response ["value" ]
320+ ]
321+
259322 @resource_override (resource_type = "index" )
260323 @traced (name = "contextgrounding_retrieve" , run_type = "uipath" )
261324 def retrieve (
262325 self ,
263326 name : str ,
264327 folder_key : Optional [str ] = None ,
265328 folder_path : Optional [str ] = None ,
329+ include_system_indexes : bool = False ,
266330 ) -> ContextGroundingIndex :
267331 """Retrieve context grounding index information by its name.
268332
269333 If no folder_key or folder_path is provided and no folder context is
270- configured, falls back to searching across all folders.
334+ configured, falls back to searching across all folders. When
335+ ``include_system_indexes`` is True, an additional fallback against
336+ system indexes is attempted before raising not-found.
271337
272338 Args:
273339 name (str): The name of the context index to retrieve.
274340 folder_key (Optional[str]): The key of the folder where the index resides.
275341 folder_path (Optional[str]): The path of the folder where the index resides.
342+ include_system_indexes (bool): If True, fall back to system indexes
343+ when the index is not found in the per-folder or across-folders listings.
344+ Defaults to False.
276345
277346 Returns:
278347 ContextGroundingIndex: The index information, including its configuration and metadata if found.
279348
280349 Raises:
281- Exception : If no index with the given name is found.
350+ ContextGroundingIndexNotFoundError : If no index with the given name is found.
282351 """
283352 resolved_folder_key = self ._resolve_folder_key (folder_key , folder_path )
284353 if not resolved_folder_key :
285354 indexes = self .retrieve_across_folders (name = name )
286355 try :
287356 return next (index for index in indexes if index .name == name )
288- except StopIteration as e :
289- raise Exception ("ContextGroundingIndex not found" ) from e
357+ except StopIteration :
358+ if include_system_indexes :
359+ return self ._retrieve_from_system_indexes (name )
360+ raise ContextGroundingIndexNotFoundError (name ) from None
290361
291362 spec = self ._retrieve_spec (
292363 name ,
@@ -305,8 +376,10 @@ def retrieve(
305376 for item in response ["value" ]
306377 if item ["name" ] == name
307378 )
308- except StopIteration as e :
309- raise Exception ("ContextGroundingIndex not found" ) from e
379+ except StopIteration :
380+ if include_system_indexes :
381+ return self ._retrieve_from_system_indexes (name )
382+ raise ContextGroundingIndexNotFoundError (name ) from None
310383
311384 @resource_override (resource_type = "index" )
312385 @traced (name = "contextgrounding_retrieve" , run_type = "uipath" )
@@ -315,30 +388,38 @@ async def retrieve_async(
315388 name : str ,
316389 folder_key : Optional [str ] = None ,
317390 folder_path : Optional [str ] = None ,
391+ include_system_indexes : bool = False ,
318392 ) -> ContextGroundingIndex :
319393 """Asynchronously retrieve context grounding index information by its name.
320394
321395 If no folder_key or folder_path is provided and no folder context is
322- configured, falls back to searching across all folders.
396+ configured, falls back to searching across all folders. When
397+ ``include_system_indexes`` is True, an additional fallback against
398+ system indexes is attempted before raising not-found.
323399
324400 Args:
325401 name (str): The name of the context index to retrieve.
326402 folder_key (Optional[str]): The key of the folder where the index resides.
327403 folder_path (Optional[str]): The path of the folder where the index resides.
404+ include_system_indexes (bool): If True, fall back to system indexes when
405+ the index is not found in the per-folder or across-folders listings.
406+ Defaults to False.
328407
329408 Returns:
330409 ContextGroundingIndex: The index information, including its configuration and metadata if found.
331410
332411 Raises:
333- Exception : If no index with the given name is found.
412+ ContextGroundingIndexNotFoundError : If no index with the given name is found.
334413 """
335414 resolved_folder_key = self ._resolve_folder_key (folder_key , folder_path )
336415 if not resolved_folder_key :
337416 indexes = await self .retrieve_across_folders_async (name = name )
338417 try :
339418 return next (index for index in indexes if index .name == name )
340- except StopIteration as e :
341- raise Exception ("ContextGroundingIndex not found" ) from e
419+ except StopIteration :
420+ if include_system_indexes :
421+ return await self ._retrieve_from_system_indexes_async (name )
422+ raise ContextGroundingIndexNotFoundError (name ) from None
342423
343424 spec = self ._retrieve_spec (
344425 name ,
@@ -359,8 +440,26 @@ async def retrieve_async(
359440 for item in response ["value" ]
360441 if item ["name" ] == name
361442 )
362- except StopIteration as e :
363- raise Exception ("ContextGroundingIndex not found" ) from e
443+ except StopIteration :
444+ if include_system_indexes :
445+ return await self ._retrieve_from_system_indexes_async (name )
446+ raise ContextGroundingIndexNotFoundError (name ) from None
447+
448+ def _retrieve_from_system_indexes (self , name : str ) -> ContextGroundingIndex :
449+ indexes = self .retrieve_system_indexes (name = name )
450+ try :
451+ return next (index for index in indexes if index .name == name )
452+ except StopIteration :
453+ raise ContextGroundingIndexNotFoundError (name ) from None
454+
455+ async def _retrieve_from_system_indexes_async (
456+ self , name : str
457+ ) -> ContextGroundingIndex :
458+ indexes = await self .retrieve_system_indexes_async (name = name )
459+ try :
460+ return next (index for index in indexes if index .name == name )
461+ except StopIteration :
462+ raise ContextGroundingIndexNotFoundError (name ) from None
364463
365464 @traced (name = "contextgrounding_list" , run_type = "uipath" )
366465 def list (
@@ -1489,6 +1588,7 @@ def unified_search(
14891588 scope : Optional [UnifiedSearchScope ] = None ,
14901589 folder_key : Optional [str ] = None ,
14911590 folder_path : Optional [str ] = None ,
1591+ include_system_indexes : bool = False ,
14921592 ) -> UnifiedQueryResult :
14931593 """Perform a unified search on a context grounding index.
14941594
@@ -1504,11 +1604,19 @@ def unified_search(
15041604 scope (Optional[UnifiedSearchScope]): Optional search scope (folder, extension).
15051605 folder_key (Optional[str]): The key of the folder where the index resides.
15061606 folder_path (Optional[str]): The path of the folder where the index resides.
1607+ include_system_indexes (bool): If True, fall back to tenant-wide
1608+ system indexes when the index is not found in folder or
1609+ across-folders listings. Defaults to False.
15071610
15081611 Returns:
15091612 UnifiedQueryResult: The unified search result containing semantic and/or tabular results.
15101613 """
1511- index = self .retrieve (name , folder_key = folder_key , folder_path = folder_path )
1614+ index = self .retrieve (
1615+ name ,
1616+ folder_key = folder_key ,
1617+ folder_path = folder_path ,
1618+ include_system_indexes = include_system_indexes ,
1619+ )
15121620
15131621 folder_key = folder_key or index .folder_key
15141622
@@ -1544,6 +1652,7 @@ async def unified_search_async(
15441652 scope : Optional [UnifiedSearchScope ] = None ,
15451653 folder_key : Optional [str ] = None ,
15461654 folder_path : Optional [str ] = None ,
1655+ include_system_indexes : bool = False ,
15471656 ) -> UnifiedQueryResult :
15481657 """Asynchronously perform a unified search on a context grounding index.
15491658
@@ -1559,12 +1668,18 @@ async def unified_search_async(
15591668 scope (Optional[UnifiedSearchScope]): Optional search scope (folder, extension).
15601669 folder_key (Optional[str]): The key of the folder where the index resides.
15611670 folder_path (Optional[str]): The path of the folder where the index resides.
1671+ include_system_indexes (bool): If True, fall back to tenant-wide
1672+ system indexes when the index is not found in folder or
1673+ across-folders listings. Defaults to False.
15621674
15631675 Returns:
15641676 UnifiedQueryResult: The unified search result containing semantic and/or tabular results.
15651677 """
15661678 index = await self .retrieve_async (
1567- name , folder_key = folder_key , folder_path = folder_path
1679+ name ,
1680+ folder_key = folder_key ,
1681+ folder_path = folder_path ,
1682+ include_system_indexes = include_system_indexes ,
15681683 )
15691684 if index and index .in_progress_ingestion ():
15701685 raise IngestionInProgressException (index_name = name )
@@ -1911,6 +2026,16 @@ def _ingest_spec(
19112026 },
19122027 )
19132028
2029+ @staticmethod
2030+ def _odata_name_filter (name : str ) -> str :
2031+ """Build an OData ``Name eq '<name>'`` filter with single quotes escaped.
2032+
2033+ OData string literals escape ``'`` by doubling it. URL encoding of the
2034+ resulting filter is handled by the HTTP client when params are passed
2035+ as a dict.
2036+ """
2037+ return "Name eq '{}'" .format (name .replace ("'" , "''" ))
2038+
19142039 def _retrieve_across_folders_spec (
19152040 self ,
19162041 name : Optional [str ] = None ,
@@ -1919,14 +2044,30 @@ def _retrieve_across_folders_spec(
19192044 "$expand" : "dataSource" ,
19202045 }
19212046 if name :
1922- params ["$filter" ] = f"Name eq ' { name } '"
2047+ params ["$filter" ] = self . _odata_name_filter ( name )
19232048
19242049 return RequestSpec (
19252050 method = "GET" ,
19262051 endpoint = Endpoint ("/ecs_/v2/indexes/allacrossfolders" ),
19272052 params = params ,
19282053 )
19292054
2055+ def _retrieve_system_indexes_spec (
2056+ self ,
2057+ name : Optional [str ] = None ,
2058+ ) -> RequestSpec :
2059+ params : Dict [str , str ] = {
2060+ "$expand" : "dataSource" ,
2061+ }
2062+ if name :
2063+ params ["$filter" ] = self ._odata_name_filter (name )
2064+
2065+ return RequestSpec (
2066+ method = "GET" ,
2067+ endpoint = Endpoint ("/ecs_/v2/indexes/allsystemindexes" ),
2068+ params = params ,
2069+ )
2070+
19302071 def _list_spec (
19312072 self ,
19322073 folder_key : Optional [str ] = None ,
@@ -1954,7 +2095,7 @@ def _retrieve_spec(
19542095 method = "GET" ,
19552096 endpoint = Endpoint ("/ecs_/v2/indexes" ),
19562097 params = {
1957- "$filter" : f"Name eq ' { name } '" ,
2098+ "$filter" : self . _odata_name_filter ( name ) ,
19582099 "$expand" : "dataSource" ,
19592100 },
19602101 headers = {
0 commit comments