Skip to content
Open
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 packages/uipath/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "uipath"
version = "2.14.26"
version = "2.14.27"
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
131 changes: 131 additions & 0 deletions packages/uipath/src/uipath/agent/models/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import (
Annotated,
Any,
ClassVar,
Dict,
Iterable,
List,
Expand Down Expand Up @@ -129,6 +130,7 @@ class AgentInternalToolType(str, CaseInsensitiveEnum):
BATCH_TRANSFORM = "batch-transform"
HTTP_REQUEST = "http-request"
GENERATE_FILE = "generate-file"
JEV_CLASSIFIER = "jev-classifier"


class AgentEscalationRecipientType(str, CaseInsensitiveEnum):
Expand Down Expand Up @@ -206,6 +208,7 @@ class AgentToolArgumentPropertiesVariant(str, CaseInsensitiveEnum):
STATIC = "static"
TEXT_BUILDER = "textBuilder"
ARRAY_BUILDER = "arrayBuilder"
OBJECT_BUILDER = "objectBuilder"


class TextTokenType(str, CaseInsensitiveEnum):
Expand Down Expand Up @@ -303,12 +306,26 @@ class AgentToolArrayBuilderArgumentProperties(BaseCfg):
)


class AgentToolObjectBuilderArgumentProperties(BaseCfg):
"""Agent object builder argument properties model.

A marker on an object argument: each of its properties carries its own
argument properties.
"""

variant: Literal[AgentToolArgumentPropertiesVariant.OBJECT_BUILDER] = Field(
default=AgentToolArgumentPropertiesVariant.OBJECT_BUILDER,
frozen=True,
)


AgentToolArgumentProperties = Annotated[
Union[
AgentToolStaticArgumentProperties,
AgentToolArgumentArgumentProperties,
AgentToolTextBuilderArgumentProperties,
AgentToolArrayBuilderArgumentProperties,
AgentToolObjectBuilderArgumentProperties,
],
Field(discriminator="variant"),
_case_insensitive_enum_validator("variant", AgentToolArgumentPropertiesVariant),
Expand Down Expand Up @@ -1075,13 +1092,23 @@ class AgentInternalGenerateFileToolProperties(BaseResourceProperties):
)


class AgentInternalJevClassifierToolProperties(BaseResourceProperties):
"""Agent internal Jev classifier tool properties model."""

tool_type: Literal[AgentInternalToolType.JEV_CLASSIFIER] = Field(
alias="toolType", default=AgentInternalToolType.JEV_CLASSIFIER, frozen=True
)
settings: AgentInternalJevClassifierSettings = Field(..., alias="settings")


AgentInternalToolProperties = Annotated[
Union[
AgentInternalAnalyzeFilesToolProperties,
AgentInternalDeepRagToolProperties,
AgentInternalBatchTransformToolProperties,
AgentInternalHttpRequestToolProperties,
AgentInternalGenerateFileToolProperties,
AgentInternalJevClassifierToolProperties,
],
Field(discriminator="tool_type"),
_case_insensitive_enum_validator("tool_type", AgentInternalToolType, "toolType"),
Expand Down Expand Up @@ -1117,6 +1144,110 @@ class AgentInternalBatchTransformSettings(BaseCfg):
)


JEV_NAME_PATTERN = r"^[A-Za-z_][A-Za-z0-9_]{0,63}$"


class JevQuestionType(str, CaseInsensitiveEnum):
"""Jev question type enumeration (matches TypeSafe's question types)."""

CHOICE = "choice"
SCORE = "score"
NOUL = "noul"


class JevChoiceOption(BaseCfg):
"""An option of a Jev choice question."""

name: str = Field(..., min_length=1)
description: Optional[str] = Field(None)


class BaseJevQuestion(BaseCfg):
"""Common fields of a Jev question.

A question carries only the fields of its type: ``options`` belong to choice
questions, ``levels`` to score questions and ``criteria`` to noul questions.
"""

foreign_fields: ClassVar[tuple[str, ...]] = ()

name: str = Field(..., pattern=JEV_NAME_PATTERN)
instructions: str = Field(..., min_length=1)

@model_validator(mode="after")
def _only_own_fields(self) -> "BaseJevQuestion":
extra = self.model_extra or {}
present = [f for f in self.foreign_fields if extra.get(f) is not None]
if present:
raise ValueError(
f"Question '{self.name}' cannot have {' or '.join(present)}"
)
return self


class JevChoiceQuestion(BaseJevQuestion):
"""Jev question selecting one of a set of options."""

foreign_fields: ClassVar[tuple[str, ...]] = ("levels", "criteria")

type: Literal[JevQuestionType.CHOICE] = JevQuestionType.CHOICE
options: List[JevChoiceOption] = Field(..., min_length=2, max_length=255)

@model_validator(mode="after")
def _unique_option_names(self) -> "JevChoiceQuestion":
names = [option.name for option in self.options]
if len(names) != len(set(names)):
raise ValueError(f"Question '{self.name}' has duplicate option names")
return self


class JevScoreQuestion(BaseJevQuestion):
"""Jev question placing the input on an ordered scale of levels."""

foreign_fields: ClassVar[tuple[str, ...]] = ("options", "criteria")

type: Literal[JevQuestionType.SCORE] = JevQuestionType.SCORE
levels: List[Annotated[str, Field(min_length=1)]] = Field(
..., min_length=2, max_length=10
)


class JevNoulCriteria(BaseModel):
"""What counts as a true and as a false answer to a Jev noul question."""

model_config = ConfigDict(extra="forbid")

true: Optional[str] = Field(None)
false: Optional[str] = Field(None)


class JevNoulQuestion(BaseJevQuestion):
"""Jev yes/no question answered with a probability."""

foreign_fields: ClassVar[tuple[str, ...]] = ("options", "levels")

type: Literal[JevQuestionType.NOUL] = JevQuestionType.NOUL
criteria: Optional[JevNoulCriteria] = Field(None)


JevQuestion = Annotated[
Union[JevChoiceQuestion, JevScoreQuestion, JevNoulQuestion],
Field(discriminator="type"),
_case_insensitive_enum_validator("type", JevQuestionType),
]


class AgentInternalJevClassifierSettings(BaseCfg):

@IRONICBo IRONICBo Sep 29, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Moving questions out of settings also removes the only aggregate uniqueness check (and the duplicate-name regression). _QUESTION now validates one item at a time, while inputSchema and argumentProperties remain generic, so two runtime questions with the same name pass every model added here. System One’s wire contract keys questions by name; converting that list to the request object must then either overwrite one question or fail later in the execution layer.

Could this retain a typed question collection/root model with an after-validator, or explicitly require the future execution adapter to reject duplicate names before serialization, with the two-question regression restored? This is the same keyed boundary used by Jev Social’s request builder: the stable question key is also how the matching answer is recovered.

"""Agent internal Jev classifier tool settings model.

Only the configuration that is never a call argument: the ``state`` and
``questions`` the tool sends to Jev are declared in the resource's
``inputSchema`` and supplied through its ``argumentProperties``.
"""

model: str = Field("jev-latest")


class AgentIntegrationToolResourceConfig(BaseAgentToolResourceConfig):
"""Agent integration tool resource configuration model."""

Expand Down
Loading
Loading