fix: Fix invoker to work when using dataclass with from_dict but dataclass… (#9434)

* Fix invoker to work when using dataclass with from_dict but dataclass is already given

* add reno

* Add unit test

* Remove line
This commit is contained in:
Sebastian Husch Lee 2025-05-26 09:40:09 +02:00 committed by Julian Risch
parent 37e249b47f
commit f6867ebaee
3 changed files with 35 additions and 4 deletions

View File

@ -159,15 +159,19 @@ class ComponentTool(Tool):
target_type = get_args(param_type)[0] if get_origin(param_type) is list else param_type
if hasattr(target_type, "from_dict"):
if isinstance(param_value, list):
param_value = [target_type.from_dict(item) for item in param_value if isinstance(item, dict)]
resolved_param_value = [
target_type.from_dict(item) if isinstance(item, dict) else item for item in param_value
]
elif isinstance(param_value, dict):
param_value = target_type.from_dict(param_value)
resolved_param_value = target_type.from_dict(param_value)
else:
resolved_param_value = param_value
else:
# Let TypeAdapter handle both single values and lists
type_adapter = TypeAdapter(param_type)
param_value = type_adapter.validate_python(param_value)
resolved_param_value = type_adapter.validate_python(param_value)
converted_kwargs[param_name] = param_value
converted_kwargs[param_name] = resolved_param_value
logger.debug(f"Invoking component {type(component)} with kwargs: {converted_kwargs}")
return component.run(**converted_kwargs)

View File

@ -0,0 +1,5 @@
---
fixes:
- |
Fix component_invoker used by ComponentTool to work when a dataclass like ChatMessage is directly passed to `component_tool.invoke(...)`.
Previously this would either cause an error or silently skip your input.

View File

@ -30,6 +30,21 @@ from test.tools.test_parameters_schema_utils import BYTE_STREAM_SCHEMA, DOCUMENT
# Component and Model Definitions
@component
class SimpleComponentUsingChatMessages:
"""A simple component that generates text."""
@component.output_types(reply=str)
def run(self, messages: List[ChatMessage]) -> Dict[str, str]:
"""
A simple component that generates text.
:param messages: Users messages
:return: A dictionary with the generated text.
"""
return {"reply": f"Hello, {messages[0].text}!"}
@component
class SimpleComponent:
"""A simple component that generates text."""
@ -306,6 +321,13 @@ class TestComponentTool:
with pytest.raises(ValueError):
ComponentTool(component=not_a_component, name="invalid_tool", description="This should fail")
def test_component_invoker_with_chat_message_input(self):
tool = ComponentTool(
component=SimpleComponentUsingChatMessages(), name="simple_tool", description="A simple tool"
)
result = tool.invoke(messages=[ChatMessage.from_user(text="world")])
assert result == {"reply": "Hello, world!"}
# Integration tests
class TestToolComponentInPipelineWithOpenAI: