Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "uipath"
version = "2.6.0"
version = "2.6.1"
description = "Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools."
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.11"
Expand Down
18 changes: 18 additions & 0 deletions src/uipath/platform/common/interrupt_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,17 @@

from pydantic import BaseModel, ConfigDict, Field, model_validator

from uipath.platform.context_grounding.context_grounding_index import (
ContextGroundingIndex,
)

from ..action_center.tasks import Task, TaskRecipient
from ..context_grounding import (
BatchTransformCreationResponse,
BatchTransformOutputColumn,
CitationMode,
DeepRagCreationResponse,
EphemeralIndexUsage,
)
from ..documents import FileContent, StartExtractionResponse
from ..orchestrator.job import Job
Expand Down Expand Up @@ -85,6 +90,19 @@ class WaitDeepRag(BaseModel):
index_folder_key: str | None = None


class CreateEphemeralIndex(BaseModel):
"""Model representing a Ephemeral Index task creation."""

usage: EphemeralIndexUsage
attachments: list[str]


class WaitEphemeralIndex(BaseModel):
"""Model representing a wait Ephemeral Index task."""

index: ContextGroundingIndex


class CreateBatchTransform(BaseModel):
"""Model representing a Batch Transform task creation."""

Expand Down
4 changes: 4 additions & 0 deletions src/uipath/platform/context_grounding/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
DeepRagCreationResponse,
DeepRagResponse,
DeepRagStatus,
EphemeralIndexUsage,
IndexStatus,
)
from .context_grounding_index import ContextGroundingIndex
from .context_grounding_payloads import (
Expand Down Expand Up @@ -52,8 +54,10 @@
"DeepRagCreationResponse",
"DeepRagResponse",
"DeepRagStatus",
"IndexStatus",
"DropboxDataSource",
"DropboxSourceConfig",
"EphemeralIndexUsage",
"GoogleDriveDataSource",
"GoogleDriveSourceConfig",
"Indexer",
Expand Down
113 changes: 107 additions & 6 deletions src/uipath/platform/context_grounding/_context_grounding_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import httpx
from pydantic import Field, TypeAdapter
from typing_extensions import deprecated

from ..._utils import Endpoint, RequestSpec, header_folder, resource_override
from ..._utils._ssl_context import get_httpx_client_kwargs
Expand All @@ -30,13 +29,16 @@
ContextGroundingQueryResponse,
DeepRagCreationResponse,
DeepRagResponse,
EphemeralIndexUsage,
)
from .context_grounding_index import ContextGroundingIndex
from .context_grounding_payloads import (
AttachmentsDataSource,
BucketDataSource,
BucketSourceConfig,
ConfluenceDataSource,
ConfluenceSourceConfig,
CreateEphemeralIndexPayload,
CreateIndexPayload,
DropboxDataSource,
DropboxSourceConfig,
Expand Down Expand Up @@ -276,7 +278,6 @@ async def retrieve_async(
raise Exception("ContextGroundingIndex not found") from e

@traced(name="contextgrounding_retrieve_by_id", run_type="uipath")
@deprecated("Use retrieve instead")
def retrieve_by_id(
self,
id: str,
Expand Down Expand Up @@ -309,7 +310,6 @@ def retrieve_by_id(
).json()

@traced(name="contextgrounding_retrieve_by_id", run_type="uipath")
@deprecated("Use retrieve_async instead")
async def retrieve_by_id_async(
self,
id: str,
Expand Down Expand Up @@ -453,6 +453,66 @@ async def create_index_async(

return ContextGroundingIndex.model_validate(response.json())

@resource_override(resource_type="index")
@traced(name="contextgrounding_create_ephemeral_index", run_type="uipath")
def create_ephemeral_index(
self,
usage: EphemeralIndexUsage,
attachments: list[str],
) -> ContextGroundingIndex:
"""Create a new ephemeral context grounding index.

Args:
usage (EphemeralIndexUsage): The task type for the ephemeral index (DeepRAG or BatchRAG)
attachments (list[str]): The list of attachments ids from which the ephemeral index will be created

Returns:
ContextGroundingIndex: The created index information.
"""
spec = self._create_ephemeral_spec(
usage,
attachments,
)

response = self.request(
spec.method,
spec.endpoint,
json=spec.json,
headers=spec.headers,
)

return ContextGroundingIndex.model_validate(response.json())

@resource_override(resource_type="index")
@traced(name="contextgrounding_create_ephemeral_index", run_type="uipath")
async def create_ephemeral_index_async(
self,
usage: EphemeralIndexUsage,
attachments: list[str],
) -> ContextGroundingIndex:
"""Create a new ephemeral context grounding index.

Args:
usage (EphemeralIndexUsage): The task type for the ephemeral index (DeepRAG or BatchRAG)
attachments (list[str]): The list of attachments ids from which the ephemeral index will be created

Returns:
ContextGroundingIndex: The created index information.
"""
spec = self._create_ephemeral_spec(
usage,
attachments,
)

response = await self.request_async(
spec.method,
spec.endpoint,
json=spec.json,
headers=spec.headers,
)

return ContextGroundingIndex.model_validate(response.json())

@resource_override(resource_type="index", resource_identifier="index_name")
@traced(name="contextgrounding_retrieve_deep_rag", run_type="uipath")
def retrieve_deep_rag(
Expand Down Expand Up @@ -1197,6 +1257,34 @@ def _create_spec(
},
)

def _create_ephemeral_spec(
self,
usage: str,
attachments: list[str],
) -> RequestSpec:
"""Create request spec for ephemeral index creation.

Args:
usage (str): The task in which the ephemeral index will be used for
attachments (list[str]): The list of attachments ids from which the ephemeral index will be created

Returns:
RequestSpec for the create index request
"""
data_source_dict = self._build_ephemeral_data_source(attachments)

payload = CreateEphemeralIndexPayload(
usage=usage,
data_source=data_source_dict,
)

return RequestSpec(
method="POST",
endpoint=Endpoint("/ecs_/v2/indexes/createephemeral"),
json=payload.model_dump(by_alias=True, exclude_none=True),
headers={},
)

def _build_data_source(self, source: SourceConfig) -> Dict[str, Any]:
"""Build data source configuration from typed source config.

Expand Down Expand Up @@ -1265,6 +1353,22 @@ def _build_data_source(self, source: SourceConfig) -> Dict[str, Any]:

return data_source.model_dump(by_alias=True, exclude_none=True)

def _build_ephemeral_data_source(self, attachments: list[str]) -> Dict[str, Any]:
"""Build data source configuration from typed source config.

Args:
attachments (list[str]): The list of attachments ids from which the ephemeral index will be created

Returns:
Dictionary with data source configuration for API
"""
data_source = AttachmentsDataSource(attachments=attachments)
return data_source.model_dump(
by_alias=True,
exclude_none=True,
mode="json",
)

def _retrieve_by_id_spec(
self,
id: str,
Expand Down Expand Up @@ -1422,9 +1526,6 @@ def _resolve_folder_key(self, folder_key, folder_path):
else None
)

if folder_key is None:
raise ValueError("ContextGrounding: Failed to resolve folder key")

return folder_key

def _extract_bucket_info(self, index: ContextGroundingIndex) -> Tuple[str, str]:
Expand Down
16 changes: 16 additions & 0 deletions src/uipath/platform/context_grounding/context_grounding.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ class CitationMode(str, Enum):
INLINE = "Inline"


class EphemeralIndexUsage(str, Enum):
"""Enum representing possible ephemeral index usage types."""

DEEP_RAG = "DeepRAG"
BATCH_RAG = "BatchRAG"


class DeepRagStatus(str, Enum):
"""Enum representing possible deep RAG tasks status."""

Expand All @@ -41,6 +48,15 @@ class DeepRagStatus(str, Enum):
FAILED = "Failed"


class IndexStatus(str, Enum):
"""Enum representing possible index tasks status."""

QUEUED = "Queued"
IN_PROGRESS = "InProgress"
SUCCESSFUL = "Successful"
FAILED = "Failed"


class Citation(BaseModel):
"""Model representing a deep RAG citation."""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ class ContextGroundingIndex(BaseModel):
extra="allow",
)

@field_serializer("last_ingested", "last_queried", when_used="json")
@field_serializer("last_ingested", "last_queried")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so it can serialize for the waitephemeralindex interrupt

def serialize_datetime(self, value):
"""Serialize datetime fields to ISO 8601 format for JSON output."""
"""Serialize datetime fields to ISO 8601 format."""
if isinstance(value, datetime):
return value.isoformat() if value else None
return value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ class ConfluenceDataSource(DataSourceBase):
space_id: str = Field(alias="spaceId", description="Space ID")


class AttachmentsDataSource(BaseModel):
"""Data source configuration for Attachments."""

attachments: list[str] = Field(description="List of attachment ids")


class Indexer(BaseModel):
"""Configuration for periodic indexing of data sources."""

Expand Down Expand Up @@ -136,6 +142,23 @@ class CreateIndexPayload(BaseModel):
model_config = ConfigDict(populate_by_name=True)


class CreateEphemeralIndexPayload(BaseModel):
"""Payload for creating an ephemeral context grounding index.

Note: data_source is Dict[str, Any] because it may contain additional
fields like 'indexer' that are added dynamically based on configuration.
The data source is still validated through the _build_data_source method
which uses typed models internally.
"""

usage: str = Field(description="Index usage")
data_source: Dict[str, Any] = Field(
alias="dataSource", description="Data source configuration"
)

model_config = ConfigDict(populate_by_name=True)


# user-facing source configuration models
class BaseSourceConfig(BaseModel):
"""Base configuration for all source types."""
Expand Down
Loading