Skip to content
Merged
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: 3 additions & 0 deletions testcases/multimodal-invoke/input.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"prompt": "Describe the content of this file in one sentence."
}
6 changes: 6 additions & 0 deletions testcases/multimodal-invoke/langgraph.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"dependencies": ["."],
"graphs": {
"agent": "./src/main.py:graph"
}
}
16 changes: 16 additions & 0 deletions testcases/multimodal-invoke/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[project]
name = "multimodal-invoke"
version = "0.0.1"
description = "Test multimodal LLM invoke with file attachments via get_chat_model"
authors = [{ name = "John Doe", email = "john.doe@myemail.com" }]
dependencies = [
"langgraph>=0.2.70",
"langchain-core>=0.3.34",
"langgraph-checkpoint-sqlite>=2.0.3",
"uipath-langchain[vertex,bedrock]",
"pydantic>=2.10.6",
]
requires-python = ">=3.11"

[tool.uv.sources]
uipath-langchain = { path = "../../", editable = true }
21 changes: 21 additions & 0 deletions testcases/multimodal-invoke/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash
set -e

echo "Syncing dependencies..."
uv sync

echo "Authenticating with UiPath..."
uv run uipath auth --client-id="$CLIENT_ID" --client-secret="$CLIENT_SECRET" --base-url="$BASE_URL"

echo "Initializing the project..."
uv run uipath init

echo "Packing agent..."
uv run uipath pack

echo "Running agent..."
uv run uipath run agent --file input.json

echo "Running agent again with empty UIPATH_JOB_KEY..."
export UIPATH_JOB_KEY=""
uv run uipath run agent --trace-file .uipath/traces.jsonl --file input.json >> local_run_output.log
12 changes: 12 additions & 0 deletions testcases/multimodal-invoke/src/assert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import json

with open("__uipath/output.json", "r", encoding="utf-8") as f:
output_data = json.load(f)

output_content = output_data["output"]
result_summary = output_content["result_summary"]

print(f"Success: {output_content['success']}")
print(f"Summary:\n{result_summary}")

assert output_content["success"] is True, "Test did not succeed. See summary above."
116 changes: 116 additions & 0 deletions testcases/multimodal-invoke/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import logging

from langchain_core.messages import AIMessage, HumanMessage
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import END, START, StateGraph, MessagesState
from pydantic import BaseModel, Field

from uipath_langchain.agent.multimodal.invoke import llm_call_with_files
from uipath_langchain.agent.multimodal.types import FileInfo
from uipath_langchain.chat.chat_model_factory import get_chat_model

logger = logging.getLogger(__name__)

MODELS_TO_TEST = [
"gpt-4.1-2025-04-14",
"gemini-2.5-pro",
"anthropic.claude-sonnet-4-5-20250929-v1:0",
]

FILES_TO_TEST = [
FileInfo(
url="https://www.w3schools.com/css/img_5terre.jpg",
name="img_5terre.jpg",
mime_type="image/jpeg",
),
FileInfo(
url="https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
name="dummy.pdf",
mime_type="application/pdf",
),
]


class GraphInput(BaseModel):
prompt: str = Field(default="Describe the content of this file in one sentence.")


class GraphOutput(BaseModel):
success: bool
result_summary: str


class GraphState(MessagesState):
prompt: str
success: bool
result_summary: str
model_results: dict


async def run_multimodal_invoke(state: GraphState) -> dict:
messages = [HumanMessage(content=state["prompt"])]
model_results = {}

for model_name in MODELS_TO_TEST:
logger.info(f"Testing {model_name}...")
model = get_chat_model(
model=model_name,
temperature=0.0,
max_tokens=200,
agenthub_config="agentsplayground",
)
test_results = {}
for file_info in FILES_TO_TEST:
label = file_info.name
logger.info(f" {label}...")
try:
response: AIMessage = await llm_call_with_files(
messages, [file_info], model
)
logger.info(f" {label}: ✓")
test_results[label] = "✓"
except Exception as e:
logger.error(f" {label}: ✗ {e}")
test_results[label] = f"✗ {str(e)[:60]}"
model_results[model_name] = test_results

summary_lines = []
for model_name, results in model_results.items():
summary_lines.append(f"{model_name}:")
for file_name, result in results.items():
summary_lines.append(f" {file_name}: {result}")
has_failures = any(
"✗" in v for results in model_results.values() for v in results.values()
)

return {
"success": not has_failures,
"result_summary": "\n".join(summary_lines),
"model_results": model_results,
}


async def return_results(state: GraphState) -> GraphOutput:
logger.info(f"Success: {state['success']}")
logger.info(f"Summary:\n{state['result_summary']}")
return GraphOutput(
success=state["success"],
result_summary=state["result_summary"],
)


def build_graph() -> StateGraph:
builder = StateGraph(GraphState, input_schema=GraphInput, output_schema=GraphOutput)

builder.add_node("run_multimodal_invoke", run_multimodal_invoke)
builder.add_node("results", return_results)

builder.add_edge(START, "run_multimodal_invoke")
builder.add_edge("run_multimodal_invoke", "results")
builder.add_edge("results", END)

memory = MemorySaver()
return builder.compile(checkpointer=memory)


graph = build_graph()
Loading