haystack-experimental 0.13.0__py3-none-any.whl → 0.14.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- haystack_experimental/components/agents/__init__.py +16 -0
- haystack_experimental/components/agents/agent.py +634 -0
- haystack_experimental/components/agents/human_in_the_loop/__init__.py +35 -0
- haystack_experimental/components/agents/human_in_the_loop/breakpoint.py +63 -0
- haystack_experimental/components/agents/human_in_the_loop/dataclasses.py +72 -0
- haystack_experimental/components/agents/human_in_the_loop/errors.py +28 -0
- haystack_experimental/components/agents/human_in_the_loop/policies.py +78 -0
- haystack_experimental/components/agents/human_in_the_loop/strategies.py +455 -0
- haystack_experimental/components/agents/human_in_the_loop/types.py +89 -0
- haystack_experimental/components/agents/human_in_the_loop/user_interfaces.py +209 -0
- haystack_experimental/components/preprocessors/embedding_based_document_splitter.py +18 -6
- haystack_experimental/components/preprocessors/md_header_level_inferrer.py +146 -0
- haystack_experimental/components/summarizers/__init__.py +7 -0
- haystack_experimental/components/summarizers/llm_summarizer.py +317 -0
- haystack_experimental/core/__init__.py +3 -0
- haystack_experimental/core/pipeline/__init__.py +3 -0
- haystack_experimental/core/pipeline/breakpoint.py +174 -0
- haystack_experimental/dataclasses/__init__.py +3 -0
- haystack_experimental/dataclasses/breakpoints.py +53 -0
- {haystack_experimental-0.13.0.dist-info → haystack_experimental-0.14.0.dist-info}/METADATA +29 -14
- {haystack_experimental-0.13.0.dist-info → haystack_experimental-0.14.0.dist-info}/RECORD +24 -6
- {haystack_experimental-0.13.0.dist-info → haystack_experimental-0.14.0.dist-info}/WHEEL +0 -0
- {haystack_experimental-0.13.0.dist-info → haystack_experimental-0.14.0.dist-info}/licenses/LICENSE +0 -0
- {haystack_experimental-0.13.0.dist-info → haystack_experimental-0.14.0.dist-info}/licenses/LICENSE-MIT.txt +0 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
import sys
|
|
6
|
+
from typing import TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from lazy_imports import LazyImporter
|
|
9
|
+
|
|
10
|
+
_import_structure = {
|
|
11
|
+
"dataclasses": ["ConfirmationUIResult", "ToolExecutionDecision"],
|
|
12
|
+
"errors": ["HITLBreakpointException"],
|
|
13
|
+
"policies": ["AlwaysAskPolicy", "NeverAskPolicy", "AskOncePolicy"],
|
|
14
|
+
"strategies": ["BlockingConfirmationStrategy", "BreakpointConfirmationStrategy"],
|
|
15
|
+
"types": ["ConfirmationPolicy", "ConfirmationUI", "ConfirmationStrategy"],
|
|
16
|
+
"user_interfaces": ["RichConsoleUI", "SimpleConsoleUI"],
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if TYPE_CHECKING:
|
|
20
|
+
from .dataclasses import ConfirmationUIResult as ConfirmationUIResult
|
|
21
|
+
from .dataclasses import ToolExecutionDecision as ToolExecutionDecision
|
|
22
|
+
from .errors import HITLBreakpointException as HITLBreakpointException
|
|
23
|
+
from .policies import AlwaysAskPolicy as AlwaysAskPolicy
|
|
24
|
+
from .policies import AskOncePolicy as AskOncePolicy
|
|
25
|
+
from .policies import NeverAskPolicy as NeverAskPolicy
|
|
26
|
+
from .strategies import BlockingConfirmationStrategy as BlockingConfirmationStrategy
|
|
27
|
+
from .strategies import BreakpointConfirmationStrategy as BreakpointConfirmationStrategy
|
|
28
|
+
from .types import ConfirmationPolicy as ConfirmationPolicy
|
|
29
|
+
from .types import ConfirmationStrategy as ConfirmationStrategy
|
|
30
|
+
from .types import ConfirmationUI as ConfirmationUI
|
|
31
|
+
from .user_interfaces import RichConsoleUI as RichConsoleUI
|
|
32
|
+
from .user_interfaces import SimpleConsoleUI as SimpleConsoleUI
|
|
33
|
+
|
|
34
|
+
else:
|
|
35
|
+
sys.modules[__name__] = LazyImporter(name=__name__, module_file=__file__, import_structure=_import_structure)
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from haystack.dataclasses.breakpoints import AgentSnapshot, ToolBreakpoint
|
|
6
|
+
from haystack.utils import _deserialize_value_with_schema
|
|
7
|
+
|
|
8
|
+
from haystack_experimental.components.agents.human_in_the_loop.strategies import _prepare_tool_args
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_tool_calls_and_descriptions_from_snapshot(
|
|
12
|
+
agent_snapshot: AgentSnapshot, breakpoint_tool_only: bool = True
|
|
13
|
+
) -> tuple[list[dict], dict[str, str]]:
|
|
14
|
+
"""
|
|
15
|
+
Extract tool calls and tool descriptions from an AgentSnapshot.
|
|
16
|
+
|
|
17
|
+
By default, only the tool call that caused the breakpoint is processed and its arguments are reconstructed.
|
|
18
|
+
This is useful for scenarios where you want to present the relevant tool call and its description
|
|
19
|
+
to a human for confirmation before execution.
|
|
20
|
+
|
|
21
|
+
:param agent_snapshot: The AgentSnapshot from which to extract tool calls and descriptions.
|
|
22
|
+
:param breakpoint_tool_only: If True, only the tool call that caused the breakpoint is returned. If False, all tool
|
|
23
|
+
calls are returned.
|
|
24
|
+
:returns:
|
|
25
|
+
A tuple containing a list of tool call dictionaries and a dictionary of tool descriptions
|
|
26
|
+
"""
|
|
27
|
+
break_point = agent_snapshot.break_point.break_point
|
|
28
|
+
if not isinstance(break_point, ToolBreakpoint):
|
|
29
|
+
raise ValueError("The provided AgentSnapshot does not contain a ToolBreakpoint.")
|
|
30
|
+
|
|
31
|
+
tool_caused_break_point = break_point.tool_name
|
|
32
|
+
|
|
33
|
+
# Deserialize the tool invoker inputs from the snapshot
|
|
34
|
+
tool_invoker_inputs = _deserialize_value_with_schema(agent_snapshot.component_inputs["tool_invoker"])
|
|
35
|
+
tool_call_messages = tool_invoker_inputs["messages"]
|
|
36
|
+
state = tool_invoker_inputs["state"]
|
|
37
|
+
tool_name_to_tool = {t.name: t for t in tool_invoker_inputs["tools"]}
|
|
38
|
+
|
|
39
|
+
tool_calls = []
|
|
40
|
+
for msg in tool_call_messages:
|
|
41
|
+
if msg.tool_calls:
|
|
42
|
+
tool_calls.extend(msg.tool_calls)
|
|
43
|
+
serialized_tcs = [tc.to_dict() for tc in tool_calls]
|
|
44
|
+
|
|
45
|
+
# Reconstruct the final arguments for each tool call
|
|
46
|
+
tool_descriptions = {}
|
|
47
|
+
updated_tool_calls = []
|
|
48
|
+
for tc in serialized_tcs:
|
|
49
|
+
# Only process the tool that caused the breakpoint if breakpoint_tool_only is True
|
|
50
|
+
if breakpoint_tool_only and tc["tool_name"] != tool_caused_break_point:
|
|
51
|
+
continue
|
|
52
|
+
|
|
53
|
+
final_args = _prepare_tool_args(
|
|
54
|
+
tool=tool_name_to_tool[tc["tool_name"]],
|
|
55
|
+
tool_call_arguments=tc["arguments"],
|
|
56
|
+
state=state,
|
|
57
|
+
streaming_callback=tool_invoker_inputs.get("streaming_callback", None),
|
|
58
|
+
enable_streaming_passthrough=tool_invoker_inputs.get("enable_streaming_passthrough", False),
|
|
59
|
+
)
|
|
60
|
+
updated_tool_calls.append({**tc, "arguments": final_args})
|
|
61
|
+
tool_descriptions[tc["tool_name"]] = tool_name_to_tool[tc["tool_name"]].description
|
|
62
|
+
|
|
63
|
+
return updated_tool_calls, tool_descriptions
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from dataclasses import asdict, dataclass
|
|
6
|
+
from typing import Any, Optional
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class ConfirmationUIResult:
|
|
11
|
+
"""
|
|
12
|
+
Result of the confirmation UI interaction.
|
|
13
|
+
|
|
14
|
+
:param action:
|
|
15
|
+
The action taken by the user such as "confirm", "reject", or "modify".
|
|
16
|
+
This action type is not enforced to allow for custom actions to be implemented.
|
|
17
|
+
:param feedback:
|
|
18
|
+
Optional feedback message from the user. For example, if the user rejects the tool execution,
|
|
19
|
+
they might provide a reason for the rejection.
|
|
20
|
+
:param new_tool_params:
|
|
21
|
+
Optional set of new parameters for the tool. For example, if the user chooses to modify the tool parameters,
|
|
22
|
+
they can provide a new set of parameters here.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
action: str # "confirm", "reject", "modify"
|
|
26
|
+
feedback: Optional[str] = None
|
|
27
|
+
new_tool_params: Optional[dict[str, Any]] = None
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
@dataclass
|
|
31
|
+
class ToolExecutionDecision:
|
|
32
|
+
"""
|
|
33
|
+
Decision made regarding tool execution.
|
|
34
|
+
|
|
35
|
+
:param tool_name:
|
|
36
|
+
The name of the tool to be executed.
|
|
37
|
+
:param execute:
|
|
38
|
+
A boolean indicating whether to execute the tool with the provided parameters.
|
|
39
|
+
:param tool_call_id:
|
|
40
|
+
Optional unique identifier for the tool call. This can be used to track and correlate the decision with a
|
|
41
|
+
specific tool invocation.
|
|
42
|
+
:param feedback:
|
|
43
|
+
Optional feedback message.
|
|
44
|
+
For example, if the tool execution is rejected, this can contain the reason. Or if the tool parameters were
|
|
45
|
+
modified, this can contain the modification details.
|
|
46
|
+
:param final_tool_params:
|
|
47
|
+
Optional final parameters for the tool if execution is confirmed or modified.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
tool_name: str
|
|
51
|
+
execute: bool
|
|
52
|
+
tool_call_id: Optional[str] = None
|
|
53
|
+
feedback: Optional[str] = None
|
|
54
|
+
final_tool_params: Optional[dict[str, Any]] = None
|
|
55
|
+
|
|
56
|
+
def to_dict(self) -> dict[str, Any]:
|
|
57
|
+
"""
|
|
58
|
+
Convert the ToolExecutionDecision to a dictionary representation.
|
|
59
|
+
|
|
60
|
+
:return: A dictionary containing the tool execution decision details.
|
|
61
|
+
"""
|
|
62
|
+
return asdict(self)
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def from_dict(cls, data: dict[str, Any]) -> "ToolExecutionDecision":
|
|
66
|
+
"""
|
|
67
|
+
Populate the ToolExecutionDecision from a dictionary representation.
|
|
68
|
+
|
|
69
|
+
:param data: A dictionary containing the tool execution decision details.
|
|
70
|
+
:return: An instance of ToolExecutionDecision.
|
|
71
|
+
"""
|
|
72
|
+
return cls(**data)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class HITLBreakpointException(Exception):
|
|
9
|
+
"""
|
|
10
|
+
Exception raised when a tool execution is paused by a ConfirmationStrategy (e.g. BreakpointConfirmationStrategy).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(
|
|
14
|
+
self, message: str, tool_name: str, snapshot_file_path: str, tool_call_id: Optional[str] = None
|
|
15
|
+
) -> None:
|
|
16
|
+
"""
|
|
17
|
+
Initialize the HITLBreakpointException.
|
|
18
|
+
|
|
19
|
+
:param message: The exception message.
|
|
20
|
+
:param tool_name: The name of the tool whose execution is paused.
|
|
21
|
+
:param snapshot_file_path: The file path to the saved pipeline snapshot.
|
|
22
|
+
:param tool_call_id: Optional unique identifier for the tool call. This can be used to track and correlate
|
|
23
|
+
the decision with a specific tool invocation.
|
|
24
|
+
"""
|
|
25
|
+
super().__init__(message)
|
|
26
|
+
self.tool_name = tool_name
|
|
27
|
+
self.snapshot_file_path = snapshot_file_path
|
|
28
|
+
self.tool_call_id = tool_call_id
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
|
2
|
+
#
|
|
3
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from haystack_experimental.components.agents.human_in_the_loop.dataclasses import ConfirmationUIResult
|
|
8
|
+
from haystack_experimental.components.agents.human_in_the_loop.types import ConfirmationPolicy
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class AlwaysAskPolicy(ConfirmationPolicy):
|
|
12
|
+
"""Always ask for confirmation."""
|
|
13
|
+
|
|
14
|
+
def should_ask(self, tool_name: str, tool_description: str, tool_params: dict[str, Any]) -> bool:
|
|
15
|
+
"""
|
|
16
|
+
Always ask for confirmation before executing the tool.
|
|
17
|
+
|
|
18
|
+
:param tool_name: The name of the tool to be executed.
|
|
19
|
+
:param tool_description: The description of the tool.
|
|
20
|
+
:param tool_params: The parameters to be passed to the tool.
|
|
21
|
+
:returns: Always returns True, indicating confirmation is needed.
|
|
22
|
+
"""
|
|
23
|
+
return True
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class NeverAskPolicy(ConfirmationPolicy):
|
|
27
|
+
"""Never ask for confirmation."""
|
|
28
|
+
|
|
29
|
+
def should_ask(self, tool_name: str, tool_description: str, tool_params: dict[str, Any]) -> bool:
|
|
30
|
+
"""
|
|
31
|
+
Never ask for confirmation, always proceed with tool execution.
|
|
32
|
+
|
|
33
|
+
:param tool_name: The name of the tool to be executed.
|
|
34
|
+
:param tool_description: The description of the tool.
|
|
35
|
+
:param tool_params: The parameters to be passed to the tool.
|
|
36
|
+
:returns: Always returns False, indicating no confirmation is needed.
|
|
37
|
+
"""
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class AskOncePolicy(ConfirmationPolicy):
|
|
42
|
+
"""Ask only once per tool with specific parameters."""
|
|
43
|
+
|
|
44
|
+
def __init__(self):
|
|
45
|
+
self._asked_tools = {}
|
|
46
|
+
|
|
47
|
+
def should_ask(self, tool_name: str, tool_description: str, tool_params: dict[str, Any]) -> bool:
|
|
48
|
+
"""
|
|
49
|
+
Ask for confirmation only once per tool with specific parameters.
|
|
50
|
+
|
|
51
|
+
:param tool_name: The name of the tool to be executed.
|
|
52
|
+
:param tool_description: The description of the tool.
|
|
53
|
+
:param tool_params: The parameters to be passed to the tool.
|
|
54
|
+
:returns: True if confirmation is needed, False if already asked with the same parameters.
|
|
55
|
+
"""
|
|
56
|
+
# Don't ask again if we've already asked for this tool with the same parameters
|
|
57
|
+
return not (tool_name in self._asked_tools and self._asked_tools[tool_name] == tool_params)
|
|
58
|
+
|
|
59
|
+
def update_after_confirmation(
|
|
60
|
+
self,
|
|
61
|
+
tool_name: str,
|
|
62
|
+
tool_description: str,
|
|
63
|
+
tool_params: dict[str, Any],
|
|
64
|
+
confirmation_result: ConfirmationUIResult,
|
|
65
|
+
) -> None:
|
|
66
|
+
"""
|
|
67
|
+
Store the tool and parameters if the action was "confirm" to avoid asking again.
|
|
68
|
+
|
|
69
|
+
This method updates the internal state to remember that the user has already confirmed the execution of the
|
|
70
|
+
tool with the given parameters.
|
|
71
|
+
|
|
72
|
+
:param tool_name: The name of the tool that was executed.
|
|
73
|
+
:param tool_description: The description of the tool.
|
|
74
|
+
:param tool_params: The parameters that were passed to the tool.
|
|
75
|
+
:param confirmation_result: The result from the confirmation UI.
|
|
76
|
+
"""
|
|
77
|
+
if confirmation_result.action == "confirm":
|
|
78
|
+
self._asked_tools[tool_name] = tool_params
|