Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
8badd70
feat(agent): add ontology binding to Data Fabric context config
sankalp-uipath Jun 17, 2026
906d618
feat(entities): add ontology binding + get_ontology_file to Data Fabr…
sankalp-uipath Jun 17, 2026
cd4ff88
feat(agent): allow multiple ontologies per context (ontologySet)
sankalp-uipath Jun 17, 2026
8175316
Merge remote-tracking branch 'origin/main' into feat/agent-datafabric…
sankalp-uipath Jun 17, 2026
2048c56
fix(entities): scope ontology fetch via header_folder, not missing _f…
sankalp-uipath Jun 22, 2026
28d3c0c
feat(entities): validate ontology file_type; require folderId; add co…
sankalp-uipath Jun 22, 2026
33f76f0
Merge branch 'main' into feat/agent-datafabric-ontology-binding
sankalp-uipath Jun 22, 2026
d4ccd79
chore: bump uipath to 2.11.8 and uipath-platform to 0.1.72
sankalp-uipath Jun 22, 2026
f22074c
docs(entities): mark get_ontology_file_async as Preview Feature
sankalp-uipath Jun 23, 2026
74d47bb
Merge branch 'main' into feat/agent-datafabric-ontology-binding
sankalp-uipath Jun 23, 2026
bcbf2dd
chore: bump uipath to 2.11.9 (main advanced to 2.11.8)
sankalp-uipath Jun 23, 2026
75aaab5
feat(agent): ontology as standalone resource (ontologyRefs)
sankalp-uipath Jun 23, 2026
336bfb3
Merge remote-tracking branch 'origin/main' into feat/agent-datafabric…
sankalp-uipath Jun 23, 2026
c231702
test: annotate parsed for mypy (var-annotated)
sankalp-uipath Jun 23, 2026
2fe9114
Merge branch 'main' into feat/agent-datafabric-ontology-binding
sankalp-uipath Jun 24, 2026
6877f6a
chore: bump uipath to 2.11.11 (above main)
sankalp-uipath Jun 24, 2026
69d42df
refactor(agent): nest ontology as ontologySet on context
sankalp-uipath Jun 25, 2026
1ce9049
chore: merge main; bump uipath 2.11.13 / platform 0.1.77
sankalp-uipath Jun 25, 2026
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 packages/uipath-platform/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "uipath-platform"
version = "0.1.76"
version = "0.1.77"
description = "HTTP client library for programmatic access to UiPath Platform"
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.11"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
AggregateRow,
ChoiceSetValue,
DataFabricEntityItem,
DataFabricOntologyItem,
Entity,
EntityAggregate,
EntityAggregateFunction,
Expand Down Expand Up @@ -46,6 +47,7 @@
"AggregateRow",
"ChoiceSetValue",
"DataFabricEntityItem",
"DataFabricOntologyItem",
"EntitiesService",
"Entity",
"EntityAggregate",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""

import logging
import re
from typing import Any, Dict, List, Optional, Type

from httpx import Response
Expand All @@ -24,6 +25,8 @@
from ..common._bindings import _resource_overwrites
from ..common._config import UiPathApiConfig
from ..common._execution_context import UiPathExecutionContext
from ..common._folder_context import header_folder
from ..common._models import Endpoint, RequestSpec
from ..orchestrator._folder_service import FolderService
from ._entity_data_service import EntityDataService, FileContent
from ._entity_resolution import (
Expand Down Expand Up @@ -58,6 +61,12 @@

logger = logging.getLogger(__name__)

# Ontology name contract (QueryEngine OntologyController): lowercase, starts
# with a letter, max 64 chars. The name becomes a URL path segment.
_ONTOLOGY_NAME_RE = re.compile(r"^[a-z][a-z0-9-]{0,63}$")
# Allowed ontology component file types (also URL path segments).
_ONTOLOGY_FILE_TYPES = frozenset({"owl", "r2rml", "shacl", "summary", "context"})


class EntitiesService(BaseService):
"""Service for managing UiPath Data Service entities.
Expand Down Expand Up @@ -1100,6 +1109,68 @@ async def delete_record_async(self, entity_key: str, record_id: str) -> None:
"""
await self._data.delete_record_async(entity_key, record_id)

async def get_ontology_file_async(
self,
Comment on lines +1112 to +1113
ontology_name: str,
file_type: str = "owl",
folder_key: Optional[str] = None,
) -> Dict[str, Any]:
Comment thread
sankalp-uipath marked this conversation as resolved.
"""Fetch one file of an ontology from Data Fabric.

!!! warning "Preview Feature"
This method is currently experimental. Behavior and parameters are
subject to change in future versions.

Ontologies are served by the same QueryEngine service as entity SQL
queries, under ``datafabric_/api/ontologies``. The JSON wrapper is
requested so the result is notation-agnostic — the ``owl`` file content
may be Turtle or OWL Functional Notation.

Args:
ontology_name: Ontology name. Validated against the QE name contract.
file_type: One of owl, r2rml, shacl, summary, context.
folder_key: Folder the ontology lives in.

Returns:
Dict[str, Any]: The file record (e.g. ``content``, ``mediaType``).

Raises:
ValueError: If the ontology name or file type is invalid.
"""
self._validate_ontology_name(ontology_name)
self._validate_file_type(file_type)
spec = self._ontology_file_spec(ontology_name, file_type)
headers = {"Accept": "application/json", **header_folder(folder_key, None)}
response = await self.request_async(spec.method, spec.endpoint, headers=headers)
return response.json()
Comment thread
sankalp-uipath marked this conversation as resolved.

@staticmethod
def _validate_ontology_name(ontology_name: str) -> None:
"""Validate the ontology name before it becomes a URL path segment."""
if not _ONTOLOGY_NAME_RE.match(ontology_name or ""):
raise ValueError(
f"Invalid ontology name {ontology_name!r}. "
"Must match ^[a-z][a-z0-9-]{0,63}$."
)

@staticmethod
def _validate_file_type(file_type: str) -> None:
"""Validate the file type before it becomes a URL path segment."""
if file_type not in _ONTOLOGY_FILE_TYPES:
allowed = ", ".join(sorted(_ONTOLOGY_FILE_TYPES))
raise ValueError(
f"Invalid ontology file type {file_type!r}. One of: {allowed}."
)

@staticmethod
def _ontology_file_spec(ontology_name: str, file_type: str) -> RequestSpec:
return RequestSpec(
method="GET",
endpoint=Endpoint(
f"datafabric_/api/ontologies/{ontology_name}/files/{file_type}"
),
)

@traced(name="entity_record_insert_batch", run_type="uipath")
def insert_records(
self,
Expand Down
20 changes: 20 additions & 0 deletions packages/uipath-platform/src/uipath/platform/entities/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,26 @@ class DataFabricEntityItem(BaseModel):
description: Optional[str] = None


class DataFabricOntologyItem(BaseModel):
"""A single Data Fabric ontology reference nested in a context's ontologySet.

Mirrors :class:`DataFabricEntityItem`: the ontology is configured inline on
the Data Fabric context (alongside ``entitySet``), carrying its own
``folderId`` so it resolves from its own folder. ``name`` is used to fetch
the ontology from the QueryEngine ontology API.
"""

model_config = ConfigDict(
validate_by_name=True, validate_by_alias=True, extra="allow"
)

name: str
ontology_key: Optional[str] = Field(None, alias="referenceKey")
folder_key: str = Field(alias="folderId")
description: Optional[str] = None
id: Optional[str] = None


class EntitySetResolution(BaseModel):
"""Result of resolving an agent entity set with overwrites applied."""

Expand Down
75 changes: 75 additions & 0 deletions packages/uipath-platform/tests/services/test_entities_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2647,3 +2647,78 @@ def test_5xx_with_batch_shape_still_propagates(
entity_key=str(entity_key),
records=[{"name": "x"}],
)


class TestGetOntologyFileAsync:
"""Tests for EntitiesService.get_ontology_file_async."""

@pytest.mark.anyio
async def test_builds_endpoint_and_folder_header(
self, service: EntitiesService
) -> None:
response = MagicMock()
response.json.return_value = {"content": "OWL", "mediaType": "text/plain"}
service.request_async = AsyncMock(return_value=response) # type: ignore[method-assign]

result = await service.get_ontology_file_async(
"library", "owl", folder_key="folder-1"
)

assert result == {"content": "OWL", "mediaType": "text/plain"}
service.request_async.assert_called_once()
call = service.request_async.call_args
method, endpoint = call.args[0], call.args[1]
headers = call.kwargs["headers"]
assert method == "GET"
assert str(endpoint) == "/datafabric_/api/ontologies/library/files/owl"
assert headers["Accept"] == "application/json"
assert headers["x-uipath-folderkey"] == "folder-1"

@pytest.mark.anyio
async def test_no_folder_header_when_folder_key_none(
self, service: EntitiesService
) -> None:
response = MagicMock()
response.json.return_value = {"content": "OWL", "mediaType": "text/plain"}
service.request_async = AsyncMock(return_value=response) # type: ignore[method-assign]

await service.get_ontology_file_async("library")

headers = service.request_async.call_args.kwargs["headers"]
assert "x-uipath-folderkey" not in headers

@pytest.mark.anyio
@pytest.mark.parametrize(
"file_type", ["owl", "r2rml", "shacl", "summary", "context"]
)
async def test_accepts_allowed_file_types(
self, service: EntitiesService, file_type: str
) -> None:
response = MagicMock()
response.json.return_value = {"content": "x"}
service.request_async = AsyncMock(return_value=response) # type: ignore[method-assign]

await service.get_ontology_file_async("library", file_type)

endpoint = service.request_async.call_args.args[1]
assert str(endpoint) == f"/datafabric_/api/ontologies/library/files/{file_type}"

@pytest.mark.anyio
async def test_rejects_invalid_ontology_name(
self, service: EntitiesService
) -> None:
service.request_async = AsyncMock() # type: ignore[method-assign]

with pytest.raises(ValueError, match="Invalid ontology name"):
await service.get_ontology_file_async("Bad_Name") # uppercase + underscore

service.request_async.assert_not_called()

@pytest.mark.anyio
async def test_rejects_invalid_file_type(self, service: EntitiesService) -> None:
service.request_async = AsyncMock() # type: ignore[method-assign]

with pytest.raises(ValueError, match="Invalid ontology file type"):
await service.get_ontology_file_async("library", "exe")

service.request_async.assert_not_called()
4 changes: 2 additions & 2 deletions packages/uipath-platform/uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/uipath/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[project]
name = "uipath"
version = "2.11.12"
version = "2.11.13"
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"
dependencies = [
"uipath-core>=0.5.21, <0.6.0",
"uipath-runtime>=0.11.0, <0.12.0",
"uipath-platform>=0.1.76, <0.2.0",
"uipath-platform>=0.1.77, <0.2.0",
"click>=8.3.1",
"httpx>=0.28.1",
"pyjwt>=2.10.1",
Expand Down
11 changes: 10 additions & 1 deletion packages/uipath/src/uipath/agent/models/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
)
from uipath.eval.mocks import ExampleCall
from uipath.platform.connections import Connection
from uipath.platform.entities import DataFabricEntityItem
from uipath.platform.entities import DataFabricEntityItem, DataFabricOntologyItem
from uipath.platform.guardrails import (
BuiltInValidatorGuardrail,
)
Expand Down Expand Up @@ -440,6 +440,15 @@ class AgentContextResourceConfig(BaseAgentResourceConfig):
None, description="Context settings"
)
entity_set: Optional[List[DataFabricEntityItem]] = Field(None, alias="entitySet")
ontology_set: Optional[List[DataFabricOntologyItem]] = Field(
None,
alias="ontologySet",
description=(
"Data Fabric ontologies grounding this context, configured inline "
"alongside the entity set. Each carries its own folderId and is "
"fetched from the QueryEngine ontology API at runtime."
),
)
Comment on lines 442 to +451
argument_properties: Dict[str, AgentToolArgumentProperties] = Field(
{}, alias="argumentProperties"
)
Expand Down
Loading
Loading