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
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "uipath-langchain"
version = "0.1.18"
version = "0.1.19"
description = "UiPath Langchain"
readme = { file = "README.md", content-type = "text/markdown" }
requires-python = ">=3.11"
Expand Down Expand Up @@ -113,4 +113,3 @@ name = "testpypi"
url = "https://test.pypi.org/simple/"
publish-url = "https://test.pypi.org/legacy/"
explicit = true

70 changes: 53 additions & 17 deletions src/uipath_langchain/chat/mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
from langchain_core.messages import (
AIMessageChunk,
BaseMessage,
Citation,
HumanMessage,
TextContentBlock,
ToolCallChunk,
ToolMessage,
)
from uipath.core.chat import (
UiPathConversationCitationEndEvent,
UiPathConversationCitationEvent,
UiPathConversationCitationSource,
UiPathConversationCitationStartEvent,
UiPathConversationContentPartChunkEvent,
UiPathConversationContentPartEndEvent,
UiPathConversationContentPartEvent,
Expand Down Expand Up @@ -184,13 +189,50 @@ def map_event(
text_block = cast(TextContentBlock, block)
text = text_block["text"]

msg_event.content_part = UiPathConversationContentPartEvent(
content_part_id=f"chunk-{message.id}-0",
chunk=UiPathConversationContentPartChunkEvent(
data=text,
content_part_sequence=0,
),
)
# Map citations if present
annotations = text_block.get("annotations", [])
citation_annotations = [
cast(Citation, annotation)
for annotation in annotations
if annotation.get("type") == "citation"
]

if citation_annotations:
for citation_annotation in citation_annotations:
# Build citation source, only include url if present
block_index = text_block.get("index", 0)
block_index = block_index // 2 + 1
source_args = {
"title": citation_annotation.get("title"),
"number": block_index,
}
if citation_annotation.get("url") is not None:
source_args["url"] = citation_annotation.get("url")

citation_source = UiPathConversationCitationSource(
**source_args
)

msg_event.content_part = UiPathConversationContentPartEvent(
content_part_id=f"chunk-{message.id}-0",
chunk=UiPathConversationContentPartChunkEvent(
data=citation_annotation["cited_text"],
citation=UiPathConversationCitationEvent(
citation_id=str(uuid4()),
start=UiPathConversationCitationStartEvent(),
end=UiPathConversationCitationEndEvent(
sources=[citation_source]
),
),
),
)
else:
msg_event.content_part = UiPathConversationContentPartEvent(
content_part_id=f"chunk-{message.id}-0",
chunk=UiPathConversationContentPartChunkEvent(
data=text
),
)

elif block_type == "tool_call_chunk":
tool_chunk_block = cast(ToolCallChunk, block)
Expand All @@ -204,10 +246,7 @@ def map_event(

msg_event.content_part = UiPathConversationContentPartEvent(
content_part_id=f"chunk-{message.id}-0",
chunk=UiPathConversationContentPartChunkEvent(
data=args,
content_part_sequence=0,
),
chunk=UiPathConversationContentPartChunkEvent(data=args),
)
# Continue so that multiple tool_call_chunks in the same block list
# are handled correctly
Expand All @@ -217,10 +256,7 @@ def map_event(
elif isinstance(message.content, str) and message.content:
msg_event.content_part = UiPathConversationContentPartEvent(
content_part_id=f"content-{message.id}",
chunk=UiPathConversationContentPartChunkEvent(
data=message.content,
content_part_sequence=0,
),
chunk=UiPathConversationContentPartChunkEvent(data=message.content),
)

if (
Expand Down Expand Up @@ -269,12 +305,12 @@ def map_event(
tool_call_id=message.tool_call_id,
start=UiPathConversationToolCallStartEvent(
tool_name=message.name,
arguments=None,
input=None,
timestamp=timestamp,
),
end=UiPathConversationToolCallEndEvent(
timestamp=timestamp,
result=UiPathInlineValue(inline=content_value),
output=UiPathInlineValue(inline=content_value),
),
),
)
Expand Down
16 changes: 12 additions & 4 deletions src/uipath_langchain/runtime/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from langgraph.errors import EmptyInputError, GraphRecursionError, InvalidUpdateError
from langgraph.graph.state import CompiledStateGraph
from langgraph.types import Command, Interrupt, StateSnapshot
from pydantic import ValidationError
from uipath.runtime import (
UiPathBreakpointResult,
UiPathExecuteOptions,
Expand Down Expand Up @@ -135,10 +136,17 @@ async def stream(
if chunk_type == "messages":
if isinstance(data, tuple):
message, _ = data
event = UiPathRuntimeMessageEvent(
payload=self.chat.map_event(message),
)
yield event

try:
mapped_event = self.chat.map_event(message)
event = UiPathRuntimeMessageEvent(
payload=mapped_event,
)
yield event
except ValidationError as e:
logger.warning(
f"Failed to map event due to validation error, skipping: {e}"
)

# Emit UiPathRuntimeStateEvent for state updates
elif chunk_type == "updates":
Expand Down
2 changes: 1 addition & 1 deletion uv.lock

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