haystack-experimental 0.17.0__py3-none-any.whl → 0.18.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/agent.py +69 -143
- haystack_experimental/components/agents/human_in_the_loop/__init__.py +2 -15
- haystack_experimental/components/agents/human_in_the_loop/breakpoint.py +1 -2
- haystack_experimental/components/agents/human_in_the_loop/strategies.py +4 -548
- haystack_experimental/dataclasses/breakpoints.py +3 -4
- {haystack_experimental-0.17.0.dist-info → haystack_experimental-0.18.0.dist-info}/METADATA +24 -27
- {haystack_experimental-0.17.0.dist-info → haystack_experimental-0.18.0.dist-info}/RECORD +10 -14
- haystack_experimental/components/agents/human_in_the_loop/dataclasses.py +0 -72
- haystack_experimental/components/agents/human_in_the_loop/policies.py +0 -78
- haystack_experimental/components/agents/human_in_the_loop/types.py +0 -124
- haystack_experimental/components/agents/human_in_the_loop/user_interfaces.py +0 -209
- {haystack_experimental-0.17.0.dist-info → haystack_experimental-0.18.0.dist-info}/WHEEL +0 -0
- {haystack_experimental-0.17.0.dist-info → haystack_experimental-0.18.0.dist-info}/licenses/LICENSE +0 -0
- {haystack_experimental-0.17.0.dist-info → haystack_experimental-0.18.0.dist-info}/licenses/LICENSE-MIT.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haystack-experimental
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.18.0
|
|
4
4
|
Summary: Experimental components and features for the Haystack LLM framework.
|
|
5
5
|
Project-URL: CI: GitHub, https://github.com/deepset-ai/haystack-experimental/actions
|
|
6
6
|
Project-URL: GitHub: issues, https://github.com/deepset-ai/haystack-experimental/issues
|
|
@@ -24,7 +24,6 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
24
24
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
25
25
|
Requires-Python: >=3.10
|
|
26
26
|
Requires-Dist: haystack-ai
|
|
27
|
-
Requires-Dist: rich
|
|
28
27
|
Description-Content-Type: text/markdown
|
|
29
28
|
|
|
30
29
|
[](https://pypi.org/project/haystack-experimental)
|
|
@@ -70,14 +69,14 @@ that includes it. Once it reaches the end of its lifespan, the experiment will b
|
|
|
70
69
|
|
|
71
70
|
### Active experiments
|
|
72
71
|
|
|
73
|
-
| Name
|
|
74
|
-
|
|
75
|
-
| [`OpenAIChatGenerator`][9]
|
|
76
|
-
| [`MarkdownHeaderLevelInferrer`][15]
|
|
77
|
-
| [`Agent`][17]; [
|
|
78
|
-
| [`LLMSummarizer`][24]
|
|
79
|
-
| [`InMemoryChatMessageStore`][1]; [`ChatMessageRetriever`][2]; [`ChatMessageWriter`][3]
|
|
80
|
-
| [`Mem0MemoryStore`][26]
|
|
72
|
+
| Name | Type | Expected End Date | Dependencies | Cookbook | Discussion |
|
|
73
|
+
|----------------------------------------------------------------------------------------|---------------------------------------|-------------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
|
|
74
|
+
| [`OpenAIChatGenerator`][9] | Chat Generator Component | November 2025 | None | <a href="https://colab.research.google.com/github/deepset-ai/haystack-cookbook/blob/main/notebooks/hallucination_score_calculator.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> | [Discuss][10] |
|
|
75
|
+
| [`MarkdownHeaderLevelInferrer`][15] | Preprocessor | January 2025 | None | None | [Discuss][16] |
|
|
76
|
+
| [`Agent`][17]; [`BreakpointConfirmationStrategy`][20]; [`HITLBreakpointException`][22] | Human in the Loop via Breakpoints | December 2025 | None | None | [Discuss][23] |
|
|
77
|
+
| [`LLMSummarizer`][24] | Document Summarizer | January 2025 | None | None | [Discuss][25] |
|
|
78
|
+
| [`InMemoryChatMessageStore`][1]; [`ChatMessageRetriever`][2]; [`ChatMessageWriter`][3] | Chat Message Store, Retriever, Writer | February 2025 | None | <a href="https://colab.research.google.com/github/deepset-ai/haystack-cookbook/blob/main/notebooks/conversational_rag_using_memory.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"/> | [Discuss][4] |
|
|
79
|
+
| [`Mem0MemoryStore`][26] | MemoryStore | April 2025 | mem0ai | None | -- |
|
|
81
80
|
|
|
82
81
|
[1]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/chat_message_stores/in_memory.py
|
|
83
82
|
[2]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/retrievers/chat_message_retriever.py
|
|
@@ -88,10 +87,7 @@ that includes it. Once it reaches the end of its lifespan, the experiment will b
|
|
|
88
87
|
[15]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/preprocessors/md_header_level_inferrer.py
|
|
89
88
|
[16]: https://github.com/deepset-ai/haystack-experimental/discussions/376
|
|
90
89
|
[17]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/agent.py
|
|
91
|
-
[18]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/human_in_the_loop/policies.py
|
|
92
|
-
[19]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/human_in_the_loop/user_interfaces.py
|
|
93
90
|
[20]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/human_in_the_loop/strategies.py
|
|
94
|
-
[21]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/human_in_the_loop/dataclasses.py
|
|
95
91
|
[22]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/human_in_the_loop/errors.py
|
|
96
92
|
[23]: https://github.com/deepset-ai/haystack-experimental/discussions/381
|
|
97
93
|
[24]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/sumarizers/llm_summarizer.py
|
|
@@ -99,20 +95,21 @@ that includes it. Once it reaches the end of its lifespan, the experiment will b
|
|
|
99
95
|
[26]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/memory_stores/mem0/memory_store.py
|
|
100
96
|
|
|
101
97
|
### Adopted experiments
|
|
102
|
-
| Name | Type
|
|
103
|
-
|
|
104
|
-
| `ChatMessage` refactoring; `Tool` class; tool support in ChatGenerators; `ToolInvoker` | Tool Calling support
|
|
105
|
-
| `AsyncPipeline`; `Pipeline` bug fixes and refactoring | AsyncPipeline execution
|
|
106
|
-
| `LLMMetadataExtractor` | Metadata extraction with LLM
|
|
107
|
-
| `Auto-Merging Retriever` & `HierarchicalDocumentSplitter` | Document Splitting & Retrieval Technique
|
|
108
|
-
| `Agent` | Simplify Agent development
|
|
109
|
-
| `SuperComponent` | Simplify Pipeline development
|
|
110
|
-
| `Pipeline` | Pipeline breakpoints for debugging
|
|
111
|
-
| `ImageContent`; Image Converters; multimodal support in `OpenAIChatGenerator` and `AmazonBedrockChatGenerator`; `ChatPromptBuilder` refactoring; `SentenceTransformersDocumentImageEmbedder`; `LLMDocumentContentExtractor`; new `Routers` | Multimodality
|
|
112
|
-
| `QueryExpander` | Query Expansion Component
|
|
113
|
-
| `MultiQueryEmbeddingRetriever` | MultiQueryEmbeddingRetriever
|
|
114
|
-
| `MultiQueryTextRetriever` | MultiQueryTextRetriever
|
|
115
|
-
| `EmbeddingBasedDocumentSplitter`
|
|
98
|
+
| Name | Type | Final release |
|
|
99
|
+
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------|---------------|
|
|
100
|
+
| `ChatMessage` refactoring; `Tool` class; tool support in ChatGenerators; `ToolInvoker` | Tool Calling support | 0.4.0 |
|
|
101
|
+
| `AsyncPipeline`; `Pipeline` bug fixes and refactoring | AsyncPipeline execution | 0.7.0 |
|
|
102
|
+
| `LLMMetadataExtractor` | Metadata extraction with LLM | 0.7.0 |
|
|
103
|
+
| `Auto-Merging Retriever` & `HierarchicalDocumentSplitter` | Document Splitting & Retrieval Technique | 0.8.0 |
|
|
104
|
+
| `Agent` | Simplify Agent development | 0.8.0 |
|
|
105
|
+
| `SuperComponent` | Simplify Pipeline development | 0.8.0 |
|
|
106
|
+
| `Pipeline` | Pipeline breakpoints for debugging | 0.12.0 |
|
|
107
|
+
| `ImageContent`; Image Converters; multimodal support in `OpenAIChatGenerator` and `AmazonBedrockChatGenerator`; `ChatPromptBuilder` refactoring; `SentenceTransformersDocumentImageEmbedder`; `LLMDocumentContentExtractor`; new `Routers` | Multimodality | 0.12.0 |
|
|
108
|
+
| `QueryExpander` | Query Expansion Component | 0.14.3 |
|
|
109
|
+
| `MultiQueryEmbeddingRetriever` | MultiQueryEmbeddingRetriever | 0.14.3 |
|
|
110
|
+
| `MultiQueryTextRetriever` | MultiQueryTextRetriever | 0.14.3 |
|
|
111
|
+
| `EmbeddingBasedDocumentSplitter` | Document Splitting | 0.15.2 |
|
|
112
|
+
| `Confirmation Policies`; `ConfirmationUIs`; `BlockingConfirmationStrategy`; `ConfirmationUIResult`; `ToolExecutionDecision` | Human in the Loop | 0.16.0 |
|
|
116
113
|
|
|
117
114
|
### Discontinued experiments
|
|
118
115
|
|
|
@@ -4,15 +4,11 @@ haystack_experimental/chat_message_stores/in_memory.py,sha256=Dw5N9l8qk-RONEVVJb
|
|
|
4
4
|
haystack_experimental/chat_message_stores/types.py,sha256=BHpk36OesvAxMgu6iOOYt4gmqw_cIE4nFDVgiutCguA,2726
|
|
5
5
|
haystack_experimental/components/__init__.py,sha256=eHD7xrty2PCky_gG3ty19rpM4WfV32TyytM7gJODwl4,110
|
|
6
6
|
haystack_experimental/components/agents/__init__.py,sha256=Sxu9LxPpQ5cljgoTgUeNC0GY8CwUdiSy1JWkd_-RRJ4,414
|
|
7
|
-
haystack_experimental/components/agents/agent.py,sha256=
|
|
8
|
-
haystack_experimental/components/agents/human_in_the_loop/__init__.py,sha256=
|
|
9
|
-
haystack_experimental/components/agents/human_in_the_loop/breakpoint.py,sha256=
|
|
10
|
-
haystack_experimental/components/agents/human_in_the_loop/dataclasses.py,sha256=qQG4yRlzzcNeBlWagnZpjeJKZ2v_n2_9V9W0ZvsgBn4,2538
|
|
7
|
+
haystack_experimental/components/agents/agent.py,sha256=KKVQe6JAsy6TE8vS22xyMcLXP2Ds8JVLXdkL9wM2jYM,46801
|
|
8
|
+
haystack_experimental/components/agents/human_in_the_loop/__init__.py,sha256=NAVRXBjgLXn734XPr208WSjqAinSkkgM4LTpr1cZZ8k,746
|
|
9
|
+
haystack_experimental/components/agents/human_in_the_loop/breakpoint.py,sha256=P94JmVgu2B5spUPu4dMltleOdG7qsoSiJxnxkGGvKrY,2907
|
|
11
10
|
haystack_experimental/components/agents/human_in_the_loop/errors.py,sha256=Mgn8HWx-3AqTFHu5ZY9PWWb_brMsO1xtdrOFzHzbXRI,1020
|
|
12
|
-
haystack_experimental/components/agents/human_in_the_loop/
|
|
13
|
-
haystack_experimental/components/agents/human_in_the_loop/strategies.py,sha256=b9oJgXJ805VMljm55i1S2j2wQ-2-bPxkn5oWG5Vx9RU,28608
|
|
14
|
-
haystack_experimental/components/agents/human_in_the_loop/types.py,sha256=Fu6LR67GOimGhzEgJOnpU4pb14zEfk1JtBrDFwTuLk8,4582
|
|
15
|
-
haystack_experimental/components/agents/human_in_the_loop/user_interfaces.py,sha256=LHHZc0JljvnzoQaNgFGiAoJyWDYFWeYFPE2khZ4z-x4,8694
|
|
11
|
+
haystack_experimental/components/agents/human_in_the_loop/strategies.py,sha256=027sKjy8oe1tSTBRi9XNpHqJlr5k8IHJRYrfUqFNeRg,4863
|
|
16
12
|
haystack_experimental/components/embedders/__init__.py,sha256=eHD7xrty2PCky_gG3ty19rpM4WfV32TyytM7gJODwl4,110
|
|
17
13
|
haystack_experimental/components/embedders/types/__init__.py,sha256=HGR8aavwIEx7v-8nm5JxFIw47EWn7vAUmywhakTNDCo,182
|
|
18
14
|
haystack_experimental/components/embedders/types/protocol.py,sha256=nVMo2x_sFP9T_DN-q-_HKGrLRd3rj27m7ZLxtigY4UQ,1026
|
|
@@ -33,7 +29,7 @@ haystack_experimental/core/__init__.py,sha256=eHD7xrty2PCky_gG3ty19rpM4WfV32Tyyt
|
|
|
33
29
|
haystack_experimental/core/pipeline/__init__.py,sha256=eHD7xrty2PCky_gG3ty19rpM4WfV32TyytM7gJODwl4,110
|
|
34
30
|
haystack_experimental/core/pipeline/breakpoint.py,sha256=NcagwEJupIZ_Mp20YLmJyeqTZe8qwo6LfuB7OTXnlXk,5214
|
|
35
31
|
haystack_experimental/dataclasses/__init__.py,sha256=eHD7xrty2PCky_gG3ty19rpM4WfV32TyytM7gJODwl4,110
|
|
36
|
-
haystack_experimental/dataclasses/breakpoints.py,sha256=
|
|
32
|
+
haystack_experimental/dataclasses/breakpoints.py,sha256=ZeSjfb72UwGDW9P5sTC59gyEXSobwDtdTus0vMJMuIM,2026
|
|
37
33
|
haystack_experimental/memory_stores/__init__.py,sha256=xkSdV7qQ_e1kNO4PrXW37CIJMGavYiwbPtsfeSHQaQ4,169
|
|
38
34
|
haystack_experimental/memory_stores/mem0/__init__.py,sha256=pntAgiFC6jXvzyHUQUNPtyChlys69jLa6rTVbClTb9I,458
|
|
39
35
|
haystack_experimental/memory_stores/mem0/memory_store.py,sha256=PkDMVRWXooorTpHtnMRHZLgsxokJR8DlnV7vgedhPyk,14148
|
|
@@ -45,8 +41,8 @@ haystack_experimental/utils/hallucination_risk_calculator/core_math.py,sha256=8X
|
|
|
45
41
|
haystack_experimental/utils/hallucination_risk_calculator/dataclasses.py,sha256=8HQL-ktwoog0WZlFz3-NQhhmVMjzMIrRjRoYuYXmorE,2284
|
|
46
42
|
haystack_experimental/utils/hallucination_risk_calculator/openai_planner.py,sha256=Vt0icGcrPtTRywh9L2YfwB62a7pDynrm5-qlKaLHLsA,11381
|
|
47
43
|
haystack_experimental/utils/hallucination_risk_calculator/skeletonization.py,sha256=KYdBDw5LcRtw8cmKW4aNGOKh3YrA17CPmcRE-FG6kSA,5466
|
|
48
|
-
haystack_experimental-0.
|
|
49
|
-
haystack_experimental-0.
|
|
50
|
-
haystack_experimental-0.
|
|
51
|
-
haystack_experimental-0.
|
|
52
|
-
haystack_experimental-0.
|
|
44
|
+
haystack_experimental-0.18.0.dist-info/METADATA,sha256=z0FIckGo2ezlyJ5uUjkjonjpJWWT7HQjEL1gKjCOml8,16826
|
|
45
|
+
haystack_experimental-0.18.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
46
|
+
haystack_experimental-0.18.0.dist-info/licenses/LICENSE,sha256=93_5nS97uHxptHvK9E8BZgKxLGeIS-rBWT2swIv-X5Y,11368
|
|
47
|
+
haystack_experimental-0.18.0.dist-info/licenses/LICENSE-MIT.txt,sha256=knmLkIKj_6tTrTSVRg9Tq88Kww4UCPLt2I1RGXJv9sQ,1037
|
|
48
|
+
haystack_experimental-0.18.0.dist-info/RECORD,,
|
|
@@ -1,72 +0,0 @@
|
|
|
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
|
|
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: str | None = None
|
|
27
|
-
new_tool_params: dict[str, Any] | None = 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: str | None = None
|
|
53
|
-
feedback: str | None = None
|
|
54
|
-
final_tool_params: dict[str, Any] | None = 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)
|
|
@@ -1,78 +0,0 @@
|
|
|
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
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
from typing import Any, Protocol
|
|
6
|
-
|
|
7
|
-
from haystack.core.serialization import default_from_dict, default_to_dict
|
|
8
|
-
|
|
9
|
-
from haystack_experimental.components.agents.human_in_the_loop.dataclasses import (
|
|
10
|
-
ConfirmationUIResult,
|
|
11
|
-
ToolExecutionDecision,
|
|
12
|
-
)
|
|
13
|
-
|
|
14
|
-
# Ellipsis are needed to define the Protocol but pylint complains. See https://github.com/pylint-dev/pylint/issues/9319.
|
|
15
|
-
# pylint: disable=unnecessary-ellipsis
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
class ConfirmationUI(Protocol):
|
|
19
|
-
"""Base class for confirmation UIs."""
|
|
20
|
-
|
|
21
|
-
def get_user_confirmation(
|
|
22
|
-
self, tool_name: str, tool_description: str, tool_params: dict[str, Any]
|
|
23
|
-
) -> ConfirmationUIResult:
|
|
24
|
-
"""Get user confirmation for tool execution."""
|
|
25
|
-
...
|
|
26
|
-
|
|
27
|
-
def to_dict(self) -> dict[str, Any]:
|
|
28
|
-
"""Serialize the UI to a dictionary."""
|
|
29
|
-
return default_to_dict(self)
|
|
30
|
-
|
|
31
|
-
@classmethod
|
|
32
|
-
def from_dict(cls, data: dict[str, Any]) -> "ConfirmationUI":
|
|
33
|
-
"""Deserialize the ConfirmationUI from a dictionary."""
|
|
34
|
-
return default_from_dict(cls, data)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
class ConfirmationPolicy(Protocol):
|
|
38
|
-
"""Base class for confirmation policies."""
|
|
39
|
-
|
|
40
|
-
def should_ask(self, tool_name: str, tool_description: str, tool_params: dict[str, Any]) -> bool:
|
|
41
|
-
"""Determine whether to ask for confirmation."""
|
|
42
|
-
...
|
|
43
|
-
|
|
44
|
-
def update_after_confirmation(
|
|
45
|
-
self,
|
|
46
|
-
tool_name: str,
|
|
47
|
-
tool_description: str,
|
|
48
|
-
tool_params: dict[str, Any],
|
|
49
|
-
confirmation_result: ConfirmationUIResult,
|
|
50
|
-
) -> None:
|
|
51
|
-
"""Update the policy based on the confirmation UI result."""
|
|
52
|
-
pass
|
|
53
|
-
|
|
54
|
-
def to_dict(self) -> dict[str, Any]:
|
|
55
|
-
"""Serialize the policy to a dictionary."""
|
|
56
|
-
return default_to_dict(self)
|
|
57
|
-
|
|
58
|
-
@classmethod
|
|
59
|
-
def from_dict(cls, data: dict[str, Any]) -> "ConfirmationPolicy":
|
|
60
|
-
"""Deserialize the policy from a dictionary."""
|
|
61
|
-
return default_from_dict(cls, data)
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
class ConfirmationStrategy(Protocol):
|
|
65
|
-
def run(
|
|
66
|
-
self,
|
|
67
|
-
tool_name: str,
|
|
68
|
-
tool_description: str,
|
|
69
|
-
tool_params: dict[str, Any],
|
|
70
|
-
tool_call_id: str | None = None,
|
|
71
|
-
**kwargs: dict[str, Any] | None,
|
|
72
|
-
) -> ToolExecutionDecision:
|
|
73
|
-
"""
|
|
74
|
-
Run the confirmation strategy for a given tool and its parameters.
|
|
75
|
-
|
|
76
|
-
:param tool_name: The name of the tool to be executed.
|
|
77
|
-
:param tool_description: The description of the tool.
|
|
78
|
-
:param tool_params: The parameters to be passed to the tool.
|
|
79
|
-
:param tool_call_id: Optional unique identifier for the tool call. This can be used to track and correlate
|
|
80
|
-
the decision with a specific tool invocation.
|
|
81
|
-
:param kwargs: Additional keyword arguments. Implementations may accept `confirmation_strategy_context`
|
|
82
|
-
for passing request-scoped resources (e.g., WebSocket connections, async queues) in web/server
|
|
83
|
-
environments.
|
|
84
|
-
|
|
85
|
-
:returns:
|
|
86
|
-
The result of the confirmation strategy (e.g., tool output, rejection message, etc.).
|
|
87
|
-
"""
|
|
88
|
-
...
|
|
89
|
-
|
|
90
|
-
async def run_async(
|
|
91
|
-
self,
|
|
92
|
-
tool_name: str,
|
|
93
|
-
tool_description: str,
|
|
94
|
-
tool_params: dict[str, Any],
|
|
95
|
-
tool_call_id: str | None = None,
|
|
96
|
-
**kwargs: dict[str, Any] | None,
|
|
97
|
-
) -> ToolExecutionDecision:
|
|
98
|
-
"""
|
|
99
|
-
Async version of run. Run the confirmation strategy for a given tool and its parameters.
|
|
100
|
-
|
|
101
|
-
Default implementation calls the sync run() method. Override for true async behavior.
|
|
102
|
-
|
|
103
|
-
:param tool_name: The name of the tool to be executed.
|
|
104
|
-
:param tool_description: The description of the tool.
|
|
105
|
-
:param tool_params: The parameters to be passed to the tool.
|
|
106
|
-
:param tool_call_id: Optional unique identifier for the tool call. This can be used to track and correlate
|
|
107
|
-
the decision with a specific tool invocation.
|
|
108
|
-
:param kwargs: Additional keyword arguments. Implementations may accept `confirmation_strategy_context`
|
|
109
|
-
for passing request-scoped resources (e.g., WebSocket connections, async queues) in web/server
|
|
110
|
-
environments.
|
|
111
|
-
|
|
112
|
-
:returns:
|
|
113
|
-
The result of the confirmation strategy (e.g., tool output, rejection message, etc.).
|
|
114
|
-
"""
|
|
115
|
-
...
|
|
116
|
-
|
|
117
|
-
def to_dict(self) -> dict[str, Any]:
|
|
118
|
-
"""Serialize the strategy to a dictionary."""
|
|
119
|
-
...
|
|
120
|
-
|
|
121
|
-
@classmethod
|
|
122
|
-
def from_dict(cls, data: dict[str, Any]) -> "ConfirmationStrategy":
|
|
123
|
-
"""Deserialize the strategy from a dictionary."""
|
|
124
|
-
...
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
# SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
|
|
2
|
-
#
|
|
3
|
-
# SPDX-License-Identifier: Apache-2.0
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
from threading import Lock
|
|
7
|
-
from typing import Any
|
|
8
|
-
|
|
9
|
-
from haystack.core.serialization import default_to_dict
|
|
10
|
-
from rich.console import Console
|
|
11
|
-
from rich.panel import Panel
|
|
12
|
-
from rich.prompt import Prompt
|
|
13
|
-
|
|
14
|
-
from haystack_experimental.components.agents.human_in_the_loop.dataclasses import ConfirmationUIResult
|
|
15
|
-
from haystack_experimental.components.agents.human_in_the_loop.types import ConfirmationUI
|
|
16
|
-
|
|
17
|
-
_ui_lock = Lock()
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
class RichConsoleUI(ConfirmationUI):
|
|
21
|
-
"""Rich console interface for user interaction."""
|
|
22
|
-
|
|
23
|
-
def __init__(self, console: Console | None = None):
|
|
24
|
-
self.console = console or Console()
|
|
25
|
-
|
|
26
|
-
def get_user_confirmation(
|
|
27
|
-
self, tool_name: str, tool_description: str, tool_params: dict[str, Any]
|
|
28
|
-
) -> ConfirmationUIResult:
|
|
29
|
-
"""
|
|
30
|
-
Get user confirmation for tool execution via rich console prompts.
|
|
31
|
-
|
|
32
|
-
:param tool_name: The name of the tool to be executed.
|
|
33
|
-
:param tool_description: The description of the tool.
|
|
34
|
-
:param tool_params: The parameters to be passed to the tool.
|
|
35
|
-
:returns: ConfirmationUIResult based on user input.
|
|
36
|
-
"""
|
|
37
|
-
with _ui_lock:
|
|
38
|
-
self._display_tool_info(tool_name, tool_description, tool_params)
|
|
39
|
-
# If wrong input is provided, Prompt.ask will re-prompt
|
|
40
|
-
choice = Prompt.ask("\nYour choice", choices=["y", "n", "m"], default="y", console=self.console)
|
|
41
|
-
return self._process_choice(choice, tool_params)
|
|
42
|
-
|
|
43
|
-
def _display_tool_info(self, tool_name: str, tool_description: str, tool_params: dict[str, Any]) -> None:
|
|
44
|
-
"""
|
|
45
|
-
Display tool information and parameters in a rich panel.
|
|
46
|
-
|
|
47
|
-
:param tool_name: The name of the tool to be executed.
|
|
48
|
-
:param tool_description: The description of the tool.
|
|
49
|
-
:param tool_params: The parameters to be passed to the tool.
|
|
50
|
-
"""
|
|
51
|
-
lines = [
|
|
52
|
-
f"[bold yellow]Tool:[/bold yellow] {tool_name}",
|
|
53
|
-
f"[bold yellow]Description:[/bold yellow] {tool_description}",
|
|
54
|
-
"\n[bold yellow]Arguments:[/bold yellow]",
|
|
55
|
-
]
|
|
56
|
-
|
|
57
|
-
if tool_params:
|
|
58
|
-
for k, v in tool_params.items():
|
|
59
|
-
lines.append(f"[cyan]{k}:[/cyan] {v}")
|
|
60
|
-
else:
|
|
61
|
-
lines.append(" (No arguments)")
|
|
62
|
-
|
|
63
|
-
self.console.print(Panel("\n".join(lines), title="🔧 Tool Execution Request", title_align="left"))
|
|
64
|
-
|
|
65
|
-
def _process_choice(self, choice: str, tool_params: dict[str, Any]) -> ConfirmationUIResult:
|
|
66
|
-
"""
|
|
67
|
-
Process the user's choice and return the corresponding ConfirmationUIResult.
|
|
68
|
-
|
|
69
|
-
:param choice: The user's choice ('y', 'n', or 'm').
|
|
70
|
-
:param tool_params: The original tool parameters.
|
|
71
|
-
:returns:
|
|
72
|
-
ConfirmationUIResult based on user input.
|
|
73
|
-
"""
|
|
74
|
-
if choice == "y":
|
|
75
|
-
return ConfirmationUIResult(action="confirm")
|
|
76
|
-
elif choice == "m":
|
|
77
|
-
return self._modify_params(tool_params)
|
|
78
|
-
else: # reject
|
|
79
|
-
feedback = Prompt.ask("Feedback message (optional)", default="", console=self.console)
|
|
80
|
-
return ConfirmationUIResult(action="reject", feedback=feedback or None)
|
|
81
|
-
|
|
82
|
-
def _modify_params(self, tool_params: dict[str, Any]) -> ConfirmationUIResult:
|
|
83
|
-
"""
|
|
84
|
-
Prompt the user to modify tool parameters.
|
|
85
|
-
|
|
86
|
-
:param tool_params: The original tool parameters.
|
|
87
|
-
:returns:
|
|
88
|
-
ConfirmationUIResult with modified parameters.
|
|
89
|
-
"""
|
|
90
|
-
new_params: dict[str, Any] = {}
|
|
91
|
-
for k, v in tool_params.items():
|
|
92
|
-
# We don't JSON dump strings to avoid users needing to input extra quotes
|
|
93
|
-
default_val = json.dumps(v) if not isinstance(v, str) else v
|
|
94
|
-
while True:
|
|
95
|
-
new_val = Prompt.ask(f"Modify '{k}'", default=default_val, console=self.console)
|
|
96
|
-
try:
|
|
97
|
-
if isinstance(v, str):
|
|
98
|
-
# Always treat input as string
|
|
99
|
-
new_params[k] = new_val
|
|
100
|
-
else:
|
|
101
|
-
# Parse JSON for all non-string types
|
|
102
|
-
new_params[k] = json.loads(new_val)
|
|
103
|
-
break
|
|
104
|
-
except json.JSONDecodeError:
|
|
105
|
-
self.console.print("[red]❌ Invalid JSON, please try again.[/red]")
|
|
106
|
-
|
|
107
|
-
return ConfirmationUIResult(action="modify", new_tool_params=new_params)
|
|
108
|
-
|
|
109
|
-
def to_dict(self) -> dict[str, Any]:
|
|
110
|
-
"""
|
|
111
|
-
Serializes the RichConsoleConfirmationUI to a dictionary.
|
|
112
|
-
|
|
113
|
-
:returns:
|
|
114
|
-
Dictionary with serialized data.
|
|
115
|
-
"""
|
|
116
|
-
# Note: Console object is not serializable; we store None
|
|
117
|
-
return default_to_dict(self, console=None)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
class SimpleConsoleUI(ConfirmationUI):
|
|
121
|
-
"""Simple console interface using standard input/output."""
|
|
122
|
-
|
|
123
|
-
def get_user_confirmation(
|
|
124
|
-
self, tool_name: str, tool_description: str, tool_params: dict[str, Any]
|
|
125
|
-
) -> ConfirmationUIResult:
|
|
126
|
-
"""
|
|
127
|
-
Get user confirmation for tool execution via simple console prompts.
|
|
128
|
-
|
|
129
|
-
:param tool_name: The name of the tool to be executed.
|
|
130
|
-
:param tool_description: The description of the tool.
|
|
131
|
-
:param tool_params: The parameters to be passed to the tool.
|
|
132
|
-
"""
|
|
133
|
-
with _ui_lock:
|
|
134
|
-
self._display_tool_info(tool_name, tool_description, tool_params)
|
|
135
|
-
valid_choices = {"y", "yes", "n", "no", "m", "modify"}
|
|
136
|
-
while True:
|
|
137
|
-
choice = input("Confirm execution? (y=confirm / n=reject / m=modify): ").strip().lower()
|
|
138
|
-
if choice in valid_choices:
|
|
139
|
-
break
|
|
140
|
-
print("Invalid input. Please enter 'y', 'n', or 'm'.")
|
|
141
|
-
return self._process_choice(choice, tool_params)
|
|
142
|
-
|
|
143
|
-
def _display_tool_info(self, tool_name: str, tool_description: str, tool_params: dict[str, Any]) -> None:
|
|
144
|
-
"""
|
|
145
|
-
Display tool information and parameters in the console.
|
|
146
|
-
|
|
147
|
-
:param tool_name: The name of the tool to be executed.
|
|
148
|
-
:param tool_description: The description of the tool.
|
|
149
|
-
:param tool_params: The parameters to be passed to the tool.
|
|
150
|
-
"""
|
|
151
|
-
print("\n--- Tool Execution Request ---")
|
|
152
|
-
print(f"Tool: {tool_name}")
|
|
153
|
-
print(f"Description: {tool_description}")
|
|
154
|
-
print("Arguments:")
|
|
155
|
-
if tool_params:
|
|
156
|
-
for k, v in tool_params.items():
|
|
157
|
-
print(f" {k}: {v}")
|
|
158
|
-
else:
|
|
159
|
-
print(" (No arguments)")
|
|
160
|
-
print("-" * 30)
|
|
161
|
-
|
|
162
|
-
def _process_choice(self, choice: str, tool_params: dict[str, Any]) -> ConfirmationUIResult:
|
|
163
|
-
"""
|
|
164
|
-
Process the user's choice and return the corresponding ConfirmationUIResult.
|
|
165
|
-
|
|
166
|
-
:param choice: The user's choice ('y', 'n', or 'm').
|
|
167
|
-
:param tool_params: The original tool parameters.
|
|
168
|
-
:returns:
|
|
169
|
-
ConfirmationUIResult based on user input.
|
|
170
|
-
"""
|
|
171
|
-
if choice in ("y", "yes"):
|
|
172
|
-
return ConfirmationUIResult(action="confirm")
|
|
173
|
-
elif choice in ("m", "modify"):
|
|
174
|
-
return self._modify_params(tool_params)
|
|
175
|
-
else: # reject
|
|
176
|
-
feedback = input("Feedback message (optional): ").strip()
|
|
177
|
-
return ConfirmationUIResult(action="reject", feedback=feedback or None)
|
|
178
|
-
|
|
179
|
-
def _modify_params(self, tool_params: dict[str, Any]) -> ConfirmationUIResult:
|
|
180
|
-
"""
|
|
181
|
-
Prompt the user to modify tool parameters.
|
|
182
|
-
|
|
183
|
-
:param tool_params: The original tool parameters.
|
|
184
|
-
:returns:
|
|
185
|
-
ConfirmationUIResult with modified parameters.
|
|
186
|
-
"""
|
|
187
|
-
new_params: dict[str, Any] = {}
|
|
188
|
-
|
|
189
|
-
if not tool_params:
|
|
190
|
-
print("No parameters to modify, skipping modification.")
|
|
191
|
-
return ConfirmationUIResult(action="modify", new_tool_params=new_params)
|
|
192
|
-
|
|
193
|
-
for k, v in tool_params.items():
|
|
194
|
-
# We don't JSON dump strings to avoid users needing to input extra quotes
|
|
195
|
-
default_val = json.dumps(v) if not isinstance(v, str) else v
|
|
196
|
-
while True:
|
|
197
|
-
new_val = input(f"Modify '{k}' (current: {default_val}): ").strip() or default_val
|
|
198
|
-
try:
|
|
199
|
-
if isinstance(v, str):
|
|
200
|
-
# Always treat input as string
|
|
201
|
-
new_params[k] = new_val
|
|
202
|
-
else:
|
|
203
|
-
# Parse JSON for all non-string types
|
|
204
|
-
new_params[k] = json.loads(new_val)
|
|
205
|
-
break
|
|
206
|
-
except json.JSONDecodeError:
|
|
207
|
-
print("❌ Invalid JSON, please try again.")
|
|
208
|
-
|
|
209
|
-
return ConfirmationUIResult(action="modify", new_tool_params=new_params)
|
|
File without changes
|
{haystack_experimental-0.17.0.dist-info → haystack_experimental-0.18.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|