Skip to content

Commit

Permalink
Move modules around
Browse files Browse the repository at this point in the history
  • Loading branch information
vblagoje committed Dec 20, 2024
1 parent ce864dd commit 931df70
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 41 deletions.
17 changes: 6 additions & 11 deletions haystack_experimental/dataclasses/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from haystack.utils import deserialize_callable, serialize_callable
from pydantic import TypeAdapter, create_model

from haystack_experimental.tools import extract_component_parameters

with LazyImport(message="Run 'pip install jsonschema'") as jsonschema_import:
from jsonschema import Draft202012Validator
from jsonschema.exceptions import SchemaError
Expand Down Expand Up @@ -216,18 +218,11 @@ def from_component(cls, component: Component, name: str, description: str) -> "T
"""

if not isinstance(component, Component):
raise ValueError(
f"{component} is not a Haystack component!" "Can only create a Tool from a Haystack component instance."
)

if getattr(component, "__haystack_added_to_pipeline__", None):
msg = (
"Component has been added in a Pipeline and can't be used to create a Tool. "
"Create Tool from a non-pipeline component instead."
message = (
f"Object {component!r} is not a Haystack component. "
"Use this method to create a Tool only with Haystack component instances."
)
raise ValueError(msg)

from haystack_experimental.components.tools.openai.component_caller import extract_component_parameters
raise ValueError(message)

# Extract the parameters schema from the component
parameters = extract_component_parameters(component)
Expand Down
7 changes: 7 additions & 0 deletions haystack_experimental/tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
#
# SPDX-License-Identifier: Apache-2.0

from .tool_component_descriptor import extract_component_parameters

__all__ = ["extract_component_parameters"]
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@
#
# SPDX-License-Identifier: Apache-2.0

from dataclasses import MISSING, fields, is_dataclass
from dataclasses import fields, is_dataclass
from inspect import getdoc
from typing import Any, Callable, Dict, Union, get_args, get_origin

from docstring_parser import parse
from haystack import logging
from haystack.core.component import Component
from pydantic.fields import FieldInfo

from haystack_experimental.util.utils import is_pydantic_v2_model

Expand Down Expand Up @@ -77,6 +76,25 @@ def get_param_descriptions(method: Callable) -> Dict[str, str]:
return param_descriptions


class UnsupportedTypeError(Exception):
"""Raised when a type is not supported for schema generation."""

pass


def is_nullable_type(python_type: Any) -> bool:
"""
Checks if the type is a Union with NoneType (i.e., Optional).
:param python_type: The Python type to check.
:returns: True if the type is a Union with NoneType, False otherwise.
"""
origin = get_origin(python_type)
if origin is Union:
return type(None) in get_args(python_type)
return False


# ruff: noqa: PLR0912
def create_property_schema(python_type: Any, description: str, default: Any = None) -> Dict[str, Any]:
"""
Expand Down Expand Up @@ -130,16 +148,3 @@ def create_property_schema(python_type: Any, description: str, default: Any = No
schema["default"] = default

return schema


def is_nullable_type(python_type: Any) -> bool:
"""
Checks if the type is a Union with NoneType (i.e., Optional).
:param python_type: The Python type to check.
:returns: True if the type is a Union with NoneType, False otherwise.
"""
origin = get_origin(python_type)
if origin is Union:
return type(None) in get_args(python_type)
return False
18 changes: 3 additions & 15 deletions test/components/tools/test_tool_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def run(self, text: str) -> Dict[str, str]:
"""
A simple component that generates text.
:param text: user's introductory message
:param text: user's name
:return: A dictionary with the generated text.
"""
return {"reply": f"Hello, {text}!"}
Expand Down Expand Up @@ -160,7 +160,7 @@ def test_from_component_basic(self):
"properties": {
"text": {
"type": "string",
"description": "user's introductory message"
"description": "user's name"
}
},
"required": ["text"]
Expand Down Expand Up @@ -436,18 +436,6 @@ def foo(self, text: str):
description="This should fail"
)

def test_from_component_for_pipeline_component(self):
pipeline = Pipeline()
component = SimpleComponent()
pipeline.add_component("component", component)

with pytest.raises(ValueError):
Tool.from_component(
component=component,
name="invalid_tool",
description="This should fail"
)


## Integration tests
class TestToolComponentInPipelineWithOpenAI:
Expand Down Expand Up @@ -605,7 +593,7 @@ def test_document_processor_in_pipeline(self):
pipeline.connect("llm.replies", "tool_invoker.messages")

message = ChatMessage.from_user(
text="I have two documents. First one says 'Hello world' and second one says 'Goodbye world'. Can you concatenate them?"
text="Concatenate these documents: First one says 'Hello world' and second one says 'Goodbye world'. Set only content field of the document only. Do not set id, meta, score, embedding, sparse_embedding, dataframe, blob fields."
)

result = pipeline.run({"llm": {"messages": [message]}})
Expand Down

0 comments on commit 931df70

Please sign in to comment.