Skip to content

Conversation

radu-mocanu
Copy link
Collaborator

@radu-mocanu radu-mocanu commented Sep 26, 2025

TODO:

  • implement true streaming

Development Package

  • Add this package as a dependency in your pyproject.toml:
[project]
dependencies = [
  # Exact version:
  "uipath-langchain==0.0.136.dev1001970617",

  # Any version from PR
  "uipath-langchain>=0.0.136.dev1001970000,<0.0.136.dev1001980000"
]

[[tool.uv.index]]
name = "testpypi"
url = "https://test.pypi.org/simple/"
publish-url = "https://test.pypi.org/legacy/"
explicit = true

[tool.uv.sources]
uipath-langchain = { index = "testpypi" }

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements streaming methods for UiPath LangChain chat models by adding _stream and _astream methods to two chat model classes. This enables real-time response streaming capabilities for both synchronous and asynchronous usage patterns.

  • Adds streaming method implementations to two chat model classes
  • Includes proper type annotations and documentation for the new streaming methods
  • Updates version number to reflect the new functionality

Reviewed Changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.

File Description
src/uipath_langchain/chat/models.py Implements _stream and _astream methods for two chat model classes with proper typing and documentation
src/uipath_langchain/_cli/_runtime/_conversation.py Adds handling for string content in message mapping
pyproject.toml Updates version from 0.0.134 to 0.0.135

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment on lines +62 to +74
response = self._call(self.url, payload, self.auth_headers)

# For non-streaming response, yield single chunk
chat_result = self._create_chat_result(response)
chunk = ChatGenerationChunk(
message=AIMessageChunk(
content=chat_result.generations[0].message.content,
additional_kwargs=chat_result.generations[0].message.additional_kwargs,
response_metadata=chat_result.generations[0].message.response_metadata,
usage_metadata=chat_result.generations[0].message.usage_metadata, # type: ignore
)
)
yield chunk
Copy link
Preview

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

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

The streaming implementation returns a single chunk instead of true streaming. Consider implementing actual streaming by making a streaming request to the API or clearly document this as a fallback implementation.

Copilot uses AI. Check for mistakes.

Comment on lines +86 to +99
response = await self._acall(self.url, payload, self.auth_headers)

# For non-streaming response, yield single chunk
chat_result = self._create_chat_result(response)
chunk = ChatGenerationChunk(
message=AIMessageChunk(
content=chat_result.generations[0].message.content,
additional_kwargs=chat_result.generations[0].message.additional_kwargs,
response_metadata=chat_result.generations[0].message.response_metadata,
usage_metadata=chat_result.generations[0].message.usage_metadata, # type: ignore
)
)
yield chunk

Copy link
Preview

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

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

The async streaming implementation also returns a single chunk instead of true streaming. This duplicates the same non-streaming behavior as the sync version.

Suggested change
response = await self._acall(self.url, payload, self.auth_headers)
# For non-streaming response, yield single chunk
chat_result = self._create_chat_result(response)
chunk = ChatGenerationChunk(
message=AIMessageChunk(
content=chat_result.generations[0].message.content,
additional_kwargs=chat_result.generations[0].message.additional_kwargs,
response_metadata=chat_result.generations[0].message.response_metadata,
usage_metadata=chat_result.generations[0].message.usage_metadata, # type: ignore
)
)
yield chunk
# Assume _acall returns an async iterator over streamed response chunks
async for chunk_data in self._acall(self.url, payload, self.auth_headers, stream=True):
# Convert each streamed chunk to ChatGenerationChunk
chat_result = self._create_chat_result(chunk_data)
yield ChatGenerationChunk(
message=AIMessageChunk(
content=chat_result.generations[0].message.content,
additional_kwargs=chat_result.generations[0].message.additional_kwargs,
response_metadata=chat_result.generations[0].message.response_metadata,
usage_metadata=chat_result.generations[0].message.usage_metadata, # type: ignore
)
)

Copilot uses AI. Check for mistakes.

Comment on lines +294 to +309
response = self._call(self.url, payload, self.auth_headers)

# For non-streaming response, yield single chunk
chat_result = self._create_chat_result(response)
chunk = ChatGenerationChunk(
message=AIMessageChunk(
content=chat_result.generations[0].message.content,
additional_kwargs=chat_result.generations[0].message.additional_kwargs,
response_metadata=chat_result.generations[0].message.response_metadata,
usage_metadata=chat_result.generations[0].message.usage_metadata, # type: ignore
tool_calls=getattr(
chat_result.generations[0].message, "tool_calls", None
),
)
)
yield chunk
Copy link
Preview

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

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

This is the third instance of duplicated non-streaming logic in streaming methods. The code pattern is repeated across multiple methods with only minor variations.

Copilot uses AI. Check for mistakes.

Comment on lines +337 to +352
response = await self._acall(self.url, payload, self.auth_headers)

# For non-streaming response, yield single chunk
chat_result = self._create_chat_result(response)
chunk = ChatGenerationChunk(
message=AIMessageChunk(
content=chat_result.generations[0].message.content,
additional_kwargs=chat_result.generations[0].message.additional_kwargs,
response_metadata=chat_result.generations[0].message.response_metadata,
usage_metadata=chat_result.generations[0].message.usage_metadata, # type: ignore
tool_calls=getattr(
chat_result.generations[0].message, "tool_calls", None
),
)
)
yield chunk
Copy link
Preview

Copilot AI Sep 26, 2025

Choose a reason for hiding this comment

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

Fourth instance of the same duplicated non-streaming implementation. Consider extracting this chunk creation logic into a shared helper method to reduce code duplication.

Copilot uses AI. Check for mistakes.

@radu-mocanu radu-mocanu changed the title feat: implement streaming methods for chat models [WIP] feat: implement streaming methods for chat models Sep 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant