Skip to content

Commit e6fc28e

Browse files
committed
update vertex
1 parent 3faef71 commit e6fc28e

3 files changed

Lines changed: 108 additions & 20 deletions

File tree

src/uipath_llamaindex/llms/__init__.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,6 @@
55
OpenAIModel,
66
)
77

8-
# Note: UiPathVertex requires optional dependencies (google-genai, llama-index-llms-google-genai)
9-
# Import it directly from uipath_llamaindex.llms.vertex:
10-
# from uipath_llamaindex.llms.vertex import UiPathVertex
11-
12-
# Note: UiPathChatBedrock and UiPathChatBedrockConverse require optional dependencies
13-
# (boto3, aiobotocore, llama-index-llms-bedrock, llama-index-llms-bedrock-converse)
14-
# Import them directly from uipath_llamaindex.llms.bedrock:
15-
# from uipath_llamaindex.llms.bedrock import UiPathChatBedrock, UiPathChatBedrockConverse
16-
178
__all__ = [
189
"UiPathOpenAI",
1910
"OpenAIModel",

src/uipath_llamaindex/llms/vertex.py

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22
import os
3-
from typing import Any, Optional
3+
from typing import Any, Generator, Optional, Sequence
44

55
import httpx
66
from llama_index.core.callbacks import CallbackManager
@@ -37,7 +37,20 @@ def _check_vertex_dependencies() -> None:
3737

3838
import google.genai # noqa: E402
3939
import google.genai.types as genai_types # noqa: E402
40+
from llama_index.core.base.llms.types import ( # noqa: E402
41+
ChatMessage,
42+
ChatResponse,
43+
ChatResponseAsyncGen,
44+
ChatResponseGen,
45+
CompletionResponse,
46+
CompletionResponseAsyncGen,
47+
CompletionResponseGen,
48+
)
4049
from llama_index.core.bridge.pydantic import PrivateAttr # noqa: E402
50+
from llama_index.core.llms.callbacks import ( # noqa: E402
51+
llm_chat_callback,
52+
llm_completion_callback,
53+
)
4154
from llama_index.llms.google_genai import GoogleGenAI # noqa: E402
4255

4356

@@ -254,3 +267,97 @@ def _build_base_url_static(model: str) -> str:
254267
model=model,
255268
)
256269
return f"{env_uipath_url.rstrip('/')}/{formatted_endpoint}"
270+
271+
# Streaming fallback methods - call non-streaming and yield single response
272+
# This works around backend streaming bugs in UiPath Gateway
273+
274+
@llm_completion_callback()
275+
def complete(
276+
self, prompt: str, formatted: bool = False, **kwargs: Any
277+
) -> CompletionResponse:
278+
"""Completion endpoint - delegates to chat."""
279+
response = self.chat([ChatMessage(role="user", content=prompt)], **kwargs)
280+
return CompletionResponse(
281+
text=response.message.content or "",
282+
raw=response.raw,
283+
additional_kwargs=response.additional_kwargs,
284+
)
285+
286+
@llm_completion_callback()
287+
def stream_complete(
288+
self, prompt: str, formatted: bool = False, **kwargs: Any
289+
) -> CompletionResponseGen:
290+
"""Streaming completion fallback - calls complete and yields single response."""
291+
292+
def gen() -> Generator[CompletionResponse, None, None]:
293+
response = self.complete(prompt, formatted=formatted, **kwargs)
294+
# Yield the full response as a single "chunk" with delta = full text
295+
yield CompletionResponse(
296+
text=response.text,
297+
raw=response.raw,
298+
delta=response.text,
299+
additional_kwargs=response.additional_kwargs,
300+
)
301+
302+
return gen()
303+
304+
@llm_completion_callback()
305+
async def astream_complete(
306+
self, prompt: str, formatted: bool = False, **kwargs: Any
307+
) -> CompletionResponseAsyncGen:
308+
"""Async streaming completion fallback - calls acomplete and yields single response."""
309+
310+
async def gen() -> CompletionResponseAsyncGen:
311+
response = await self.acomplete(prompt, formatted=formatted, **kwargs)
312+
# Yield the full response as a single "chunk" with delta = full text
313+
yield CompletionResponse(
314+
text=response.text,
315+
raw=response.raw,
316+
delta=response.text,
317+
additional_kwargs=response.additional_kwargs,
318+
)
319+
320+
return gen()
321+
322+
@llm_chat_callback()
323+
def chat(self, messages: Sequence[ChatMessage], **kwargs: Any) -> ChatResponse:
324+
"""Chat endpoint - delegates to parent's async chat via sync wrapper."""
325+
import asyncio
326+
327+
return asyncio.get_event_loop().run_until_complete(self.achat(messages, **kwargs))
328+
329+
@llm_chat_callback()
330+
def stream_chat(
331+
self, messages: Sequence[ChatMessage], **kwargs: Any
332+
) -> ChatResponseGen:
333+
"""Streaming chat fallback - calls chat and yields single response."""
334+
335+
def gen() -> Generator[ChatResponse, None, None]:
336+
response = self.chat(messages, **kwargs)
337+
# Yield the full response as a single "chunk" with delta = full content
338+
yield ChatResponse(
339+
message=response.message,
340+
raw=response.raw,
341+
delta=response.message.content or "",
342+
additional_kwargs=response.additional_kwargs,
343+
)
344+
345+
return gen()
346+
347+
@llm_chat_callback()
348+
async def astream_chat(
349+
self, messages: Sequence[ChatMessage], **kwargs: Any
350+
) -> ChatResponseAsyncGen:
351+
"""Async streaming chat fallback - calls achat and yields single response."""
352+
353+
async def gen() -> ChatResponseAsyncGen:
354+
response = await self.achat(messages, **kwargs)
355+
# Yield the full response as a single "chunk" with delta = full content
356+
yield ChatResponse(
357+
message=response.message,
358+
raw=response.raw,
359+
delta=response.message.content or "",
360+
additional_kwargs=response.additional_kwargs,
361+
)
362+
363+
return gen()

testcases/chat-models/src/main.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,7 @@
1313
logger = logging.getLogger(__name__)
1414

1515
# Methods to skip for specific models due to known limitations
16-
# UiPathVertex: sync methods fail in async context (Google GenAI SDK uses asyncio.run internally)
17-
# UiPathVertex: streaming methods fail (gateway returns JSON array instead of SSE)
1816
SKIP_METHODS: dict[str, set[str]] = {
19-
"UiPathVertex": {
20-
"complete", # asyncio.run() cannot be called from a running event loop
21-
"chat", # asyncio.run() cannot be called from a running event loop
22-
"stream_complete", # asyncio.run() + gateway streaming issue
23-
"stream_chat", # asyncio.run() + gateway streaming issue
24-
"astream_complete", # gateway returns JSON array instead of SSE
25-
"astream_chat", # gateway returns JSON array instead of SSE
26-
},
2717
"UiPathChatBedrock": {
2818
"tool_calling", # Bedrock LLMs do not support tool calling - use BedrockConverse instead
2919
"acomplete", # Bedrock base class does not implement async methods

0 commit comments

Comments
 (0)