From 1b2312b6e99cba239290fbfe114a6c2a1e68158f Mon Sep 17 00:00:00 2001 From: Maxwell Du <60411452+maxduu@users.noreply.github.com> Date: Wed, 11 Feb 2026 11:50:38 -0600 Subject: [PATCH] fix: cas event and api schemas chore: formatting and time-to-live type fix fix: more cas types chore: upgrade minor version chore: update pyproject version --- pyproject.toml | 2 +- src/uipath/core/chat/__init__.py | 32 +++++++++++------- src/uipath/core/chat/citation.py | 33 ++++++++++--------- src/uipath/core/chat/content.py | 14 ++++++-- src/uipath/core/chat/event.py | 28 +++++++++------- src/uipath/core/chat/exchange.py | 3 ++ src/uipath/core/chat/interrupt.py | 13 ++++++++ src/uipath/core/chat/message.py | 10 +++--- .../core/chat/{conversation.py => session.py} | 26 ++++++++++----- src/uipath/core/chat/tool.py | 31 ++++++++--------- uv.lock | 2 +- 11 files changed, 123 insertions(+), 71 deletions(-) rename src/uipath/core/chat/{conversation.py => session.py} (61%) diff --git a/pyproject.toml b/pyproject.toml index 585e83f..a5df102 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "uipath-core" -version = "0.3.2" +version = "0.4.0" description = "UiPath Core abstractions" readme = { file = "README.md", content-type = "text/markdown" } requires-python = ">=3.11" diff --git a/src/uipath/core/chat/__init__.py b/src/uipath/core/chat/__init__.py index aca8a1d..0ae2de3 100644 --- a/src/uipath/core/chat/__init__.py +++ b/src/uipath/core/chat/__init__.py @@ -46,12 +46,14 @@ UiPathConversationCitationEndEvent, UiPathConversationCitationEvent, UiPathConversationCitationSource, + UiPathConversationCitationSourceBase, UiPathConversationCitationSourceMedia, UiPathConversationCitationSourceUrl, UiPathConversationCitationStartEvent, ) from .content import ( InlineOrExternal, + UiPathContentPartInterrupted, UiPathConversationContentPart, UiPathConversationContentPartChunkEvent, UiPathConversationContentPartEndEvent, @@ -60,12 +62,6 @@ UiPathExternalValue, UiPathInlineValue, ) -from .conversation import ( - UiPathConversationCapabilities, - UiPathConversationEndEvent, - UiPathConversationStartedEvent, - UiPathConversationStartEvent, -) from .error import ( UiPathConversationErrorEndEvent, UiPathConversationErrorEvent, @@ -82,6 +78,7 @@ InterruptTypeEnum, UiPathConversationGenericInterruptEndEvent, UiPathConversationGenericInterruptStartEvent, + UiPathConversationInterrupt, UiPathConversationInterruptEndEvent, UiPathConversationInterruptEvent, UiPathConversationInterruptStartEvent, @@ -97,6 +94,13 @@ UiPathConversationMessageStartEvent, ) from .meta import UiPathConversationMetaEvent +from .session import ( + UiPathSessionCapabilities, + UiPathSessionEndEvent, + UiPathSessionEndingEvent, + UiPathSessionStartedEvent, + UiPathSessionStartEvent, +) from .tool import ( UiPathConversationToolCall, UiPathConversationToolCallEndEvent, @@ -113,11 +117,12 @@ "UiPathConversationErrorStartEvent", "UiPathConversationErrorEndEvent", "UiPathConversationErrorEvent", - # Conversation - "UiPathConversationCapabilities", - "UiPathConversationStartEvent", - "UiPathConversationStartedEvent", - "UiPathConversationEndEvent", + # Session + "UiPathSessionCapabilities", + "UiPathSessionStartEvent", + "UiPathSessionStartedEvent", + "UiPathSessionEndingEvent", + "UiPathSessionEndEvent", # Exchange "UiPathConversationExchangeStartEvent", "UiPathConversationExchangeEndEvent", @@ -139,9 +144,11 @@ "UiPathConversationToolCallConfirmationInterruptEndEvent", "UiPathConversationGenericInterruptStartEvent", "UiPathConversationGenericInterruptEndEvent", + "UiPathConversationInterrupt", # Content "UiPathConversationContentPartChunkEvent", "UiPathConversationContentPartStartEvent", + "UiPathContentPartInterrupted", "UiPathConversationContentPartEndEvent", "UiPathConversationContentPartEvent", "UiPathConversationContentPart", @@ -152,9 +159,10 @@ "UiPathConversationCitationStartEvent", "UiPathConversationCitationEndEvent", "UiPathConversationCitationEvent", - "UiPathConversationCitationSource", + "UiPathConversationCitationSourceBase", "UiPathConversationCitationSourceUrl", "UiPathConversationCitationSourceMedia", + "UiPathConversationCitationSource", "UiPathConversationCitation", # Tool "UiPathConversationToolCallStartEvent", diff --git a/src/uipath/core/chat/citation.py b/src/uipath/core/chat/citation.py index 2b8ffa4..927564d 100644 --- a/src/uipath/core/chat/citation.py +++ b/src/uipath/core/chat/citation.py @@ -34,39 +34,38 @@ class UiPathConversationCitationEvent(BaseModel): model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) -class UiPathConversationCitationSourceUrl(BaseModel): - """Represents a citation source that can be rendered as a link (URL).""" +class UiPathConversationCitationSourceBase(BaseModel): + """Represents a citation source with common base fields.""" - url: str + title: str + number: int model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) -class UiPathConversationCitationSourceMedia(BaseModel): - """Represents a citation source that references media, such as a PDF document.""" +class UiPathConversationCitationSourceUrl(UiPathConversationCitationSourceBase): + """Represents a citation source that can be rendered as a link (URL).""" - mime_type: str = Field(..., alias="mimeType") - download_url: str | None = Field(None, alias="downloadUrl") - page_number: str | None = Field(None, alias="pageNumber") + url: str model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) -class UiPathConversationCitationSource(BaseModel): - """Represents a citation source, either a URL or media reference.""" - - title: str - number: int +class UiPathConversationCitationSourceMedia(UiPathConversationCitationSourceBase): + """Represents a citation source that references media, such as a PDF document.""" - # Union of Url or Media - these are optional - url: str | None = None - mime_type: str | None = Field(None, alias="mimeType") + mime_type: str | None = Field(..., alias="mimeType") download_url: str | None = Field(None, alias="downloadUrl") page_number: str | None = Field(None, alias="pageNumber") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) +UiPathConversationCitationSource = ( + UiPathConversationCitationSourceUrl | UiPathConversationCitationSourceMedia +) + + class UiPathConversationCitation(BaseModel): """Represents a citation or reference inside a content part.""" @@ -74,5 +73,7 @@ class UiPathConversationCitation(BaseModel): offset: int length: int sources: list[UiPathConversationCitationSource] + created_at: str = Field(..., alias="createdAt") + updated_at: str = Field(..., alias="updatedAt") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) diff --git a/src/uipath/core/chat/content.py b/src/uipath/core/chat/content.py index 32ac78c..fbdc3b5 100644 --- a/src/uipath/core/chat/content.py +++ b/src/uipath/core/chat/content.py @@ -1,5 +1,7 @@ """Message content part events.""" +from __future__ import annotations + from typing import Any from pydantic import BaseModel, ConfigDict, Field @@ -22,20 +24,26 @@ class UiPathConversationContentPartStartEvent(BaseModel): mime_type: str = Field(..., alias="mimeType") metadata: dict[str, Any] | None = Field(None, alias="metaData") - external_value: "UiPathExternalValue | None" = Field(None, alias="externalValue") + external_value: UiPathExternalValue | None = Field(None, alias="externalValue") name: str | None = None timestamp: str | None = None model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) +class UiPathContentPartInterrupted(BaseModel): + """Indicates the interrupt of a content stream.""" + + model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) + + class UiPathConversationContentPartEndEvent(BaseModel): """Signals the end of a message content part.""" last_chunk_content_part_sequence: int | None = Field( None, alias="lastChunkContentPartSequence" ) - interrupted: dict[str, Any] | None = None + interrupted: UiPathContentPartInterrupted | None = None metadata: dict[str, Any] | None = Field(None, alias="metaData") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) @@ -88,5 +96,7 @@ class UiPathConversationContentPart(BaseModel): is_transcript: bool | None = Field(None, alias="isTranscript") is_incomplete: bool | None = Field(None, alias="isIncomplete") name: str | None = None + created_at: str = Field(..., alias="createdAt") + updated_at: str = Field(..., alias="updatedAt") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) diff --git a/src/uipath/core/chat/event.py b/src/uipath/core/chat/event.py index 8a038ca..492d45f 100644 --- a/src/uipath/core/chat/event.py +++ b/src/uipath/core/chat/event.py @@ -7,14 +7,15 @@ from pydantic import BaseModel, ConfigDict, Field from .async_stream import UiPathConversationAsyncInputStreamEvent -from .conversation import ( - UiPathConversationEndEvent, - UiPathConversationStartedEvent, - UiPathConversationStartEvent, -) from .error import UiPathConversationErrorEvent from .exchange import UiPathConversationExchangeEvent from .meta import UiPathConversationMetaEvent +from .session import ( + UiPathSessionEndEvent, + UiPathSessionEndingEvent, + UiPathSessionStartedEvent, + UiPathSessionStartEvent, +) from .tool import UiPathConversationToolCallEvent @@ -39,20 +40,25 @@ class UiPathConversationEvent(BaseModel): alias="conversationId", description="A globally unique identifier for conversation to which the other sub-event and data properties apply.", ) - start: UiPathConversationStartEvent | None = Field( + start: UiPathSessionStartEvent | None = Field( None, alias="startSession", - description="Signals the start of an event stream concerning a conversation. This event does NOT necessarily mean this is a brand new conversation. It may be a continuation of an existing conversation.", + description="Signals the start of session for a conversation.", ) - started: UiPathConversationStartedEvent | None = Field( + started: UiPathSessionStartedEvent | None = Field( None, alias="sessionStarted", - description="Signals the acceptance of the start of a conversation.", + description="Sent in response to a SessionStartEvent to signal the acceptance of the session.", + ) + ending: UiPathSessionEndingEvent | None = Field( + None, + alias="sessionEnding", + description="Sent by the service when the client needs to end the current session.", ) - end: UiPathConversationEndEvent | None = Field( + end: UiPathSessionEndEvent | None = Field( None, alias="endSession", - description="Signals the end of a conversation event stream. This does NOT mean the conversation is over. A new event stream for the conversation could be started in the future.", + description="Signals the end of a session for a conversation.", ) exchange: UiPathConversationExchangeEvent | None = Field( None, diff --git a/src/uipath/core/chat/exchange.py b/src/uipath/core/chat/exchange.py index f7e2188..e187a07 100644 --- a/src/uipath/core/chat/exchange.py +++ b/src/uipath/core/chat/exchange.py @@ -62,5 +62,8 @@ class UiPathConversationExchange(BaseModel): exchange_id: str = Field(..., alias="exchangeId") messages: list[UiPathConversationMessage] + created_at: str = Field(..., alias="createdAt") + updated_at: str = Field(..., alias="updatedAt") + span_id: str | None = Field(None, alias="spanId") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) diff --git a/src/uipath/core/chat/interrupt.py b/src/uipath/core/chat/interrupt.py index d40e275..97a9c80 100644 --- a/src/uipath/core/chat/interrupt.py +++ b/src/uipath/core/chat/interrupt.py @@ -90,3 +90,16 @@ class UiPathConversationInterruptEvent(BaseModel): end: UiPathConversationInterruptEndEvent | None = Field(None, alias="endInterrupt") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) + + +class UiPathConversationInterrupt(BaseModel): + """Represents an interrupt within a message - a pause point where the agent needs external input.""" + + interrupt_id: str = Field(..., alias="interruptId") + type: str + interrupt_value: Any = Field(..., alias="interruptValue") + end_value: Any | None = Field(None, alias="endValue") + created_at: str = Field(..., alias="createdAt") + updated_at: str = Field(..., alias="updatedAt") + + model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) diff --git a/src/uipath/core/chat/message.py b/src/uipath/core/chat/message.py index a4e9602..06bf3dc 100644 --- a/src/uipath/core/chat/message.py +++ b/src/uipath/core/chat/message.py @@ -6,7 +6,7 @@ from .content import UiPathConversationContentPart, UiPathConversationContentPartEvent from .error import UiPathConversationErrorEvent -from .interrupt import UiPathConversationInterruptEvent +from .interrupt import UiPathConversationInterrupt, UiPathConversationInterruptEvent from .tool import UiPathConversationToolCall, UiPathConversationToolCallEvent @@ -53,11 +53,13 @@ class UiPathConversationMessage(BaseModel): message_id: str = Field(..., alias="messageId") role: str - content_parts: list[UiPathConversationContentPart] | None = Field( - None, alias="contentParts" + content_parts: list[UiPathConversationContentPart] = Field( + ..., alias="contentParts" ) - tool_calls: list[UiPathConversationToolCall] | None = Field(None, alias="toolCalls") + tool_calls: list[UiPathConversationToolCall] = Field(..., alias="toolCalls") + interrupts: list[UiPathConversationInterrupt] created_at: str = Field(..., alias="createdAt") updated_at: str = Field(..., alias="updatedAt") + span_id: str | None = Field(None, alias="spanId") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) diff --git a/src/uipath/core/chat/conversation.py b/src/uipath/core/chat/session.py similarity index 61% rename from src/uipath/core/chat/conversation.py rename to src/uipath/core/chat/session.py index aacd775..d0156b1 100644 --- a/src/uipath/core/chat/conversation.py +++ b/src/uipath/core/chat/session.py @@ -5,7 +5,7 @@ from pydantic import BaseModel, ConfigDict, Field -class UiPathConversationCapabilities(BaseModel): +class UiPathSessionCapabilities(BaseModel): """Describes the capabilities of a conversation participant.""" async_input_stream_emitter: bool | None = Field( @@ -24,25 +24,33 @@ class UiPathConversationCapabilities(BaseModel): ) -class UiPathConversationStartEvent(BaseModel): - """Signals the start of a conversation event stream.""" +class UiPathSessionStartEvent(BaseModel): + """Signals the start of session for a conversation.""" - capabilities: UiPathConversationCapabilities | None = None + capabilities: UiPathSessionCapabilities | None = None metadata: dict[str, Any] | None = Field(None, alias="metaData") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) -class UiPathConversationStartedEvent(BaseModel): - """Signals the acceptance of the start of a conversation.""" +class UiPathSessionStartedEvent(BaseModel): + """Sent in response to a SessionStartEvent to signal the acceptance of the session.""" - capabilities: UiPathConversationCapabilities | None = None + capabilities: UiPathSessionCapabilities | None = None model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) -class UiPathConversationEndEvent(BaseModel): - """Signals the end of a conversation event stream.""" +class UiPathSessionEndingEvent(BaseModel): + """Sent by the service when the client needs to end the current session.""" + + time_to_live_ms: int = Field(..., alias="timeToLiveMS") + + model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) + + +class UiPathSessionEndEvent(BaseModel): + """Signals the end of a session for a conversation.""" metadata: dict[str, Any] | None = Field(None, alias="metaData") diff --git a/src/uipath/core/chat/tool.py b/src/uipath/core/chat/tool.py index d1e0e00..540349a 100644 --- a/src/uipath/core/chat/tool.py +++ b/src/uipath/core/chat/tool.py @@ -4,7 +4,6 @@ from pydantic import BaseModel, ConfigDict, Field -from .content import InlineOrExternal from .error import UiPathConversationErrorEvent @@ -12,31 +11,19 @@ class UiPathConversationToolCallResult(BaseModel): """Represents the result of a tool call execution.""" timestamp: str | None = None - value: InlineOrExternal | None = None + output: Any | None = None is_error: bool | None = Field(None, alias="isError") cancelled: bool | None = None model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) -class UiPathConversationToolCall(BaseModel): - """Represents a call to an external tool or function within a message.""" - - tool_call_id: str = Field(..., alias="toolCallId") - name: str - input: InlineOrExternal | None = None - timestamp: str | None = None - result: UiPathConversationToolCallResult | None = None - - model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) - - class UiPathConversationToolCallStartEvent(BaseModel): """Signals the start of a tool call.""" tool_name: str = Field(..., alias="toolName") timestamp: str | None = None - input: InlineOrExternal | None = None + input: dict[str, Any] | None = None metadata: dict[str, Any] | None = Field(None, alias="metaData") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) @@ -66,3 +53,17 @@ class UiPathConversationToolCallEvent(BaseModel): error: UiPathConversationErrorEvent | None = Field(None, alias="toolCallError") model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) + + +class UiPathConversationToolCall(BaseModel): + """Represents a call to an external tool or function within a message.""" + + tool_call_id: str = Field(..., alias="toolCallId") + name: str + input: dict[str, Any] | None = None + timestamp: str | None = None + result: UiPathConversationToolCallResult | None = None + created_at: str = Field(..., alias="createdAt") + updated_at: str = Field(..., alias="updatedAt") + + model_config = ConfigDict(validate_by_name=True, validate_by_alias=True) diff --git a/uv.lock b/uv.lock index 82ba2af..bea4097 100644 --- a/uv.lock +++ b/uv.lock @@ -1007,7 +1007,7 @@ wheels = [ [[package]] name = "uipath-core" -version = "0.3.2" +version = "0.4.0" source = { editable = "." } dependencies = [ { name = "opentelemetry-instrumentation" },