Skip to content

Commit cc7bb5e

Browse files
Clement Fauchereclaude
andcommitted
feat(context-grounding): add start_batch_transform_from_attachment primitive
Adds a single-call primitive that creates the ephemeral index and starts the Batch Transform task in one server operation, mirroring the DeepRag from-attachments shape from #1872. Changes - New SDK methods start_batch_transform_from_attachment(_async) on ContextGroundingService, hitting POST /ecs_/v2/batchrag/create (vdbs' BatchRagController.CreateAsync, collection-level Create action). - CreateBatchTransform interrupt model gains an optional attachment: str field; the validator rejects combining it with index_id or index_name. - UiPathResumeTriggerCreator dispatches to the new SDK method when CreateBatchTransform.attachment is set; existing start_batch_transform_ephemeral and start_batch_transform_async paths are untouched (deprecated). Note The vdbs endpoint takes a list on the wire but validates exactly one attachment, so the SDK argument is single (attachment: str) and gets wrapped into a list of one at the boundary. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 80d6735 commit cc7bb5e

8 files changed

Lines changed: 420 additions & 6 deletions

File tree

‎packages/uipath-platform/pyproject.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-platform"
3-
version = "0.2.32"
3+
version = "0.2.33"
44
description = "HTTP client library for programmatic access to UiPath Platform"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

‎packages/uipath-platform/src/uipath/platform/common/interrupt_models.py‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,24 @@ class CreateBatchTransform(BaseModel):
196196
index_folder_key: str | None = None
197197
index_folder_path: str | None = None
198198
is_ephemeral_index: bool | None = None
199+
attachment: str | None = None
199200

200201
@model_validator(mode="after")
201202
def validate_ephemeral_index_requires_index_id(self) -> "CreateBatchTransform":
202203
"""Validate that if it is an ephemeral index that it is using index id."""
203-
if self.is_ephemeral_index is True and self.index_id is None:
204-
raise ValueError("Index id must be provided for an ephemeral index")
204+
if (
205+
self.is_ephemeral_index is True
206+
and self.index_id is None
207+
and not self.attachment
208+
):
209+
raise ValueError(
210+
"Index id must be provided for an ephemeral index (or use attachment)"
211+
)
212+
if self.attachment is not None:
213+
if self.index_id is not None or self.index_name is not None:
214+
raise ValueError(
215+
"attachment cannot be combined with index_id or index_name"
216+
)
205217
return self
206218

207219

‎packages/uipath-platform/src/uipath/platform/context_grounding/_context_grounding_service.py‎

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,9 @@ async def start_batch_transform_async(
963963
)
964964
return BatchTransformCreationResponse.model_validate(response.json())
965965

966+
@deprecated(
967+
"Use start_batch_transform_from_attachment instead — one call, no separate index step."
968+
)
966969
@resource_override(resource_type="index", resource_identifier="index_name")
967970
@traced(name="contextgrounding_start_batch_transform", run_type="uipath")
968971
async def start_batch_transform_ephemeral(
@@ -1009,6 +1012,9 @@ async def start_batch_transform_ephemeral(
10091012
)
10101013
return BatchTransformCreationResponse.model_validate(response.json())
10111014

1015+
@deprecated(
1016+
"Use start_batch_transform_from_attachment_async instead — one call, no separate index step."
1017+
)
10121018
@resource_override(resource_type="index", resource_identifier="index_name")
10131019
@traced(name="contextgrounding_start_batch_transform_async", run_type="uipath")
10141020
async def start_batch_transform_ephemeral_async(
@@ -1055,6 +1061,115 @@ async def start_batch_transform_ephemeral_async(
10551061
)
10561062
return BatchTransformCreationResponse.model_validate(response.json())
10571063

1064+
@traced(
1065+
name="contextgrounding_start_batch_transform_from_attachment", run_type="uipath"
1066+
)
1067+
def start_batch_transform_from_attachment(
1068+
self,
1069+
name: str,
1070+
prompt: Annotated[str, Field(max_length=250000)],
1071+
output_columns: List[BatchTransformOutputColumn],
1072+
attachment: str,
1073+
enable_web_search_grounding: bool = False,
1074+
exclude_domains: Optional[List[str]] = None,
1075+
folder_key: str | None = None,
1076+
folder_path: str | None = None,
1077+
) -> BatchTransformCreationResponse:
1078+
"""Starts a Batch Transform task from a single attachment in one server call.
1079+
1080+
The server creates the ephemeral index from the attachment and starts the Batch Transform
1081+
task in one operation; the caller does not need to create the index separately.
1082+
1083+
Args:
1084+
name (str): The name of the Batch Transform task.
1085+
prompt (str): Describe the task: what to transform and how to output.
1086+
output_columns (list[BatchTransformOutputColumn]): The output columns to add into the csv.
1087+
attachment (str): The attachment id to transform. Exactly one attachment is supported today.
1088+
enable_web_search_grounding (bool): Whether to enable web search. Defaults to False.
1089+
exclude_domains (list[str], optional): Domains to exclude from web search grounding.
1090+
Only applies when enable_web_search_grounding is True.
1091+
folder_key (str, optional): The folder key context. Defaults to None.
1092+
folder_path (str, optional): The folder path context. Defaults to None.
1093+
1094+
Returns:
1095+
BatchTransformCreationResponse: The Batch Transform task creation response.
1096+
"""
1097+
spec = self._batch_transform_from_attachment_creation_spec(
1098+
name=name,
1099+
prompt=prompt,
1100+
output_columns=output_columns,
1101+
attachment=attachment,
1102+
enable_web_search_grounding=enable_web_search_grounding,
1103+
exclude_domains=exclude_domains,
1104+
folder_key=folder_key,
1105+
folder_path=folder_path,
1106+
)
1107+
1108+
response = self.request(
1109+
spec.method,
1110+
spec.endpoint,
1111+
params=spec.params,
1112+
json=spec.json,
1113+
headers=spec.headers,
1114+
)
1115+
1116+
return BatchTransformCreationResponse.model_validate(response.json())
1117+
1118+
@traced(
1119+
name="contextgrounding_start_batch_transform_from_attachment_async",
1120+
run_type="uipath",
1121+
)
1122+
async def start_batch_transform_from_attachment_async(
1123+
self,
1124+
name: str,
1125+
prompt: Annotated[str, Field(max_length=250000)],
1126+
output_columns: List[BatchTransformOutputColumn],
1127+
attachment: str,
1128+
enable_web_search_grounding: bool = False,
1129+
exclude_domains: Optional[List[str]] = None,
1130+
folder_key: str | None = None,
1131+
folder_path: str | None = None,
1132+
) -> BatchTransformCreationResponse:
1133+
"""Asynchronously starts a Batch Transform task from a single attachment in one server call.
1134+
1135+
The server creates the ephemeral index from the attachment and starts the Batch Transform
1136+
task in one operation; the caller does not need to create the index separately.
1137+
1138+
Args:
1139+
name (str): The name of the Batch Transform task.
1140+
prompt (str): Describe the task: what to transform and how to output.
1141+
output_columns (list[BatchTransformOutputColumn]): The output columns to add into the csv.
1142+
attachment (str): The attachment id to transform. Exactly one attachment is supported today.
1143+
enable_web_search_grounding (bool): Whether to enable web search. Defaults to False.
1144+
exclude_domains (list[str], optional): Domains to exclude from web search grounding.
1145+
Only applies when enable_web_search_grounding is True.
1146+
folder_key (str, optional): The folder key context. Defaults to None.
1147+
folder_path (str, optional): The folder path context. Defaults to None.
1148+
1149+
Returns:
1150+
BatchTransformCreationResponse: The Batch Transform task creation response.
1151+
"""
1152+
spec = self._batch_transform_from_attachment_creation_spec(
1153+
name=name,
1154+
prompt=prompt,
1155+
output_columns=output_columns,
1156+
attachment=attachment,
1157+
enable_web_search_grounding=enable_web_search_grounding,
1158+
exclude_domains=exclude_domains,
1159+
folder_key=folder_key,
1160+
folder_path=folder_path,
1161+
)
1162+
1163+
response = await self.request_async(
1164+
spec.method,
1165+
spec.endpoint,
1166+
params=spec.params,
1167+
json=spec.json,
1168+
headers=spec.headers,
1169+
)
1170+
1171+
return BatchTransformCreationResponse.model_validate(response.json())
1172+
10581173
@resource_override(resource_type="index", resource_identifier="index_name")
10591174
@traced(name="contextgrounding_retrieve_batch_transform", run_type="uipath")
10601175
def retrieve_batch_transform(
@@ -2633,6 +2748,41 @@ def _batch_transform_ephemeral_creation_spec(
26332748
headers={**header_job_key()},
26342749
)
26352750

2751+
def _batch_transform_from_attachment_creation_spec(
2752+
self,
2753+
name: str,
2754+
prompt: str,
2755+
output_columns: List[BatchTransformOutputColumn],
2756+
attachment: str,
2757+
enable_web_search_grounding: bool,
2758+
exclude_domains: Optional[List[str]],
2759+
folder_key: str | None = None,
2760+
folder_path: str | None = None,
2761+
) -> RequestSpec:
2762+
headers: dict[str, str] = {**header_job_key()}
2763+
if folder_key is not None or folder_path is not None:
2764+
folder_key = self._resolve_folder_key(folder_key, folder_path)
2765+
headers = {**header_folder(folder_key, None), **headers}
2766+
2767+
body: dict[str, object] = {
2768+
"name": name,
2769+
"prompt": prompt,
2770+
"useWebSearchGrounding": enable_web_search_grounding,
2771+
"outputColumns": [
2772+
column.model_dump(by_alias=True) for column in output_columns
2773+
],
2774+
"attachments": [attachment],
2775+
}
2776+
if exclude_domains:
2777+
body["excludeDomains"] = exclude_domains
2778+
2779+
return RequestSpec(
2780+
method="POST",
2781+
endpoint=Endpoint("/ecs_/v2/batchrag/create"),
2782+
json=body,
2783+
headers=headers,
2784+
)
2785+
26362786
def _deep_rag_retrieve_spec(
26372787
self,
26382788
id: str,

‎packages/uipath-platform/src/uipath/platform/resume_triggers/_protocol.py‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,17 @@ async def _handle_batch_rag_job_trigger(
799799
elif isinstance(value, CreateBatchTransform):
800800
uipath = UiPath()
801801
try:
802-
if value.is_ephemeral_index:
802+
if value.attachment is not None:
803+
batch_transform = await uipath.context_grounding.start_batch_transform_from_attachment_async(
804+
name=value.name,
805+
prompt=value.prompt,
806+
output_columns=value.output_columns,
807+
attachment=value.attachment,
808+
enable_web_search_grounding=value.enable_web_search_grounding,
809+
folder_path=value.index_folder_path,
810+
folder_key=value.index_folder_key,
811+
)
812+
elif value.is_ephemeral_index:
803813
batch_transform = await uipath.context_grounding.start_batch_transform_ephemeral_async(
804814
name=value.name,
805815
index_id=value.index_id,

0 commit comments

Comments
 (0)