haystack-experimental 0.14.3__py3-none-any.whl → 0.15.1__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/chat_message_stores/__init__.py +1 -1
- haystack_experimental/chat_message_stores/in_memory.py +176 -31
- haystack_experimental/chat_message_stores/types.py +33 -21
- haystack_experimental/components/agents/agent.py +147 -44
- haystack_experimental/components/agents/human_in_the_loop/strategies.py +220 -3
- haystack_experimental/components/agents/human_in_the_loop/types.py +36 -1
- haystack_experimental/components/embedders/types/protocol.py +2 -2
- haystack_experimental/components/preprocessors/embedding_based_document_splitter.py +16 -16
- haystack_experimental/components/retrievers/__init__.py +1 -3
- haystack_experimental/components/retrievers/chat_message_retriever.py +57 -26
- haystack_experimental/components/writers/__init__.py +1 -1
- haystack_experimental/components/writers/chat_message_writer.py +25 -22
- {haystack_experimental-0.14.3.dist-info → haystack_experimental-0.15.1.dist-info}/METADATA +24 -31
- {haystack_experimental-0.14.3.dist-info → haystack_experimental-0.15.1.dist-info}/RECORD +17 -24
- {haystack_experimental-0.14.3.dist-info → haystack_experimental-0.15.1.dist-info}/WHEEL +1 -1
- haystack_experimental/components/query/__init__.py +0 -18
- haystack_experimental/components/query/query_expander.py +0 -294
- haystack_experimental/components/retrievers/multi_query_embedding_retriever.py +0 -173
- haystack_experimental/components/retrievers/multi_query_text_retriever.py +0 -150
- haystack_experimental/super_components/__init__.py +0 -3
- haystack_experimental/super_components/indexers/__init__.py +0 -11
- haystack_experimental/super_components/indexers/sentence_transformers_document_indexer.py +0 -199
- {haystack_experimental-0.14.3.dist-info → haystack_experimental-0.15.1.dist-info}/licenses/LICENSE +0 -0
- {haystack_experimental-0.14.3.dist-info → haystack_experimental-0.15.1.dist-info}/licenses/LICENSE-MIT.txt +0 -0
|
@@ -63,7 +63,12 @@ class ConfirmationPolicy(Protocol):
|
|
|
63
63
|
|
|
64
64
|
class ConfirmationStrategy(Protocol):
|
|
65
65
|
def run(
|
|
66
|
-
self,
|
|
66
|
+
self,
|
|
67
|
+
tool_name: str,
|
|
68
|
+
tool_description: str,
|
|
69
|
+
tool_params: dict[str, Any],
|
|
70
|
+
tool_call_id: Optional[str] = None,
|
|
71
|
+
**kwargs: Optional[dict[str, Any]],
|
|
67
72
|
) -> ToolExecutionDecision:
|
|
68
73
|
"""
|
|
69
74
|
Run the confirmation strategy for a given tool and its parameters.
|
|
@@ -73,6 +78,36 @@ class ConfirmationStrategy(Protocol):
|
|
|
73
78
|
:param tool_params: The parameters to be passed to the tool.
|
|
74
79
|
:param tool_call_id: Optional unique identifier for the tool call. This can be used to track and correlate
|
|
75
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: Optional[str] = None,
|
|
96
|
+
**kwargs: Optional[dict[str, Any]],
|
|
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.
|
|
76
111
|
|
|
77
112
|
:returns:
|
|
78
113
|
The result of the confirmation strategy (e.g., tool output, rejection message, etc.).
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, Protocol
|
|
6
6
|
|
|
7
7
|
from haystack import Document
|
|
8
8
|
|
|
@@ -15,7 +15,7 @@ class DocumentEmbedder(Protocol):
|
|
|
15
15
|
Protocol for Document Embedders.
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
def run(self, documents:
|
|
18
|
+
def run(self, documents: list[Document]) -> dict[str, Any]:
|
|
19
19
|
"""
|
|
20
20
|
Generate embeddings for the input documents.
|
|
21
21
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
5
|
from copy import deepcopy
|
|
6
|
-
from typing import Any,
|
|
6
|
+
from typing import Any, Optional
|
|
7
7
|
|
|
8
8
|
import numpy as np
|
|
9
9
|
from haystack import Document, component, logging
|
|
@@ -136,8 +136,8 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
136
136
|
self.document_embedder.warm_up()
|
|
137
137
|
self._is_warmed_up = True
|
|
138
138
|
|
|
139
|
-
@component.output_types(documents=
|
|
140
|
-
def run(self, documents:
|
|
139
|
+
@component.output_types(documents=list[Document])
|
|
140
|
+
def run(self, documents: list[Document]) -> dict[str, list[Document]]:
|
|
141
141
|
"""
|
|
142
142
|
Split documents based on embedding similarity.
|
|
143
143
|
|
|
@@ -162,7 +162,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
162
162
|
if not isinstance(documents, list) or (documents and not isinstance(documents[0], Document)):
|
|
163
163
|
raise TypeError("EmbeddingBasedDocumentSplitter expects a List of Documents as input.")
|
|
164
164
|
|
|
165
|
-
split_docs:
|
|
165
|
+
split_docs: list[Document] = []
|
|
166
166
|
for doc in documents:
|
|
167
167
|
if doc.content is None:
|
|
168
168
|
raise ValueError(
|
|
@@ -178,7 +178,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
178
178
|
|
|
179
179
|
return {"documents": split_docs}
|
|
180
180
|
|
|
181
|
-
def _split_document(self, doc: Document) ->
|
|
181
|
+
def _split_document(self, doc: Document) -> list[Document]:
|
|
182
182
|
"""
|
|
183
183
|
Split a single document based on embedding similarity.
|
|
184
184
|
"""
|
|
@@ -194,7 +194,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
194
194
|
# Create Document objects from the final splits
|
|
195
195
|
return EmbeddingBasedDocumentSplitter._create_documents_from_splits(splits=final_splits, original_doc=doc)
|
|
196
196
|
|
|
197
|
-
def _split_text(self, text: str) ->
|
|
197
|
+
def _split_text(self, text: str) -> list[str]:
|
|
198
198
|
"""
|
|
199
199
|
Split a text into smaller chunks based on embedding similarity.
|
|
200
200
|
"""
|
|
@@ -221,7 +221,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
221
221
|
|
|
222
222
|
return sub_splits
|
|
223
223
|
|
|
224
|
-
def _group_sentences(self, sentences:
|
|
224
|
+
def _group_sentences(self, sentences: list[str]) -> list[str]:
|
|
225
225
|
"""
|
|
226
226
|
Group sentences into groups of sentences_per_group.
|
|
227
227
|
"""
|
|
@@ -235,7 +235,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
235
235
|
|
|
236
236
|
return groups
|
|
237
237
|
|
|
238
|
-
def _calculate_embeddings(self, sentence_groups:
|
|
238
|
+
def _calculate_embeddings(self, sentence_groups: list[str]) -> list[list[float]]:
|
|
239
239
|
"""
|
|
240
240
|
Calculate embeddings for each sentence group using the DocumentEmbedder.
|
|
241
241
|
"""
|
|
@@ -246,7 +246,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
246
246
|
embeddings = [doc.embedding for doc in embedded_docs]
|
|
247
247
|
return embeddings
|
|
248
248
|
|
|
249
|
-
def _find_split_points(self, embeddings:
|
|
249
|
+
def _find_split_points(self, embeddings: list[list[float]]) -> list[int]:
|
|
250
250
|
"""
|
|
251
251
|
Find split points based on cosine distances between sequential embeddings.
|
|
252
252
|
"""
|
|
@@ -273,7 +273,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
273
273
|
return split_points
|
|
274
274
|
|
|
275
275
|
@staticmethod
|
|
276
|
-
def _cosine_distance(embedding1:
|
|
276
|
+
def _cosine_distance(embedding1: list[float], embedding2: list[float]) -> float:
|
|
277
277
|
"""
|
|
278
278
|
Calculate cosine distance between two embeddings.
|
|
279
279
|
"""
|
|
@@ -291,7 +291,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
291
291
|
return 1.0 - cosine_sim
|
|
292
292
|
|
|
293
293
|
@staticmethod
|
|
294
|
-
def _create_splits_from_points(sentence_groups:
|
|
294
|
+
def _create_splits_from_points(sentence_groups: list[str], split_points: list[int]) -> list[str]:
|
|
295
295
|
"""
|
|
296
296
|
Create splits based on split points.
|
|
297
297
|
"""
|
|
@@ -315,7 +315,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
315
315
|
|
|
316
316
|
return splits
|
|
317
317
|
|
|
318
|
-
def _merge_small_splits(self, splits:
|
|
318
|
+
def _merge_small_splits(self, splits: list[str]) -> list[str]:
|
|
319
319
|
"""
|
|
320
320
|
Merge splits that are below min_length.
|
|
321
321
|
"""
|
|
@@ -341,7 +341,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
341
341
|
|
|
342
342
|
return merged
|
|
343
343
|
|
|
344
|
-
def _split_large_splits(self, splits:
|
|
344
|
+
def _split_large_splits(self, splits: list[str]) -> list[str]:
|
|
345
345
|
"""
|
|
346
346
|
Recursively split splits that are above max_length.
|
|
347
347
|
|
|
@@ -375,7 +375,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
375
375
|
return final_splits
|
|
376
376
|
|
|
377
377
|
@staticmethod
|
|
378
|
-
def _create_documents_from_splits(splits:
|
|
378
|
+
def _create_documents_from_splits(splits: list[str], original_doc: Document) -> list[Document]:
|
|
379
379
|
"""
|
|
380
380
|
Create Document objects from splits.
|
|
381
381
|
"""
|
|
@@ -405,7 +405,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
405
405
|
|
|
406
406
|
return documents
|
|
407
407
|
|
|
408
|
-
def to_dict(self) ->
|
|
408
|
+
def to_dict(self) -> dict[str, Any]:
|
|
409
409
|
"""
|
|
410
410
|
Serializes the component to a dictionary.
|
|
411
411
|
"""
|
|
@@ -422,7 +422,7 @@ class EmbeddingBasedDocumentSplitter:
|
|
|
422
422
|
)
|
|
423
423
|
|
|
424
424
|
@classmethod
|
|
425
|
-
def from_dict(cls, data:
|
|
425
|
+
def from_dict(cls, data: dict[str, Any]) -> "EmbeddingBasedDocumentSplitter":
|
|
426
426
|
"""
|
|
427
427
|
Deserializes the component from a dictionary.
|
|
428
428
|
"""
|
|
@@ -3,7 +3,5 @@
|
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
5
|
from haystack_experimental.components.retrievers.chat_message_retriever import ChatMessageRetriever
|
|
6
|
-
from haystack_experimental.components.retrievers.multi_query_embedding_retriever import MultiQueryEmbeddingRetriever
|
|
7
|
-
from haystack_experimental.components.retrievers.multi_query_text_retriever import MultiQueryTextRetriever
|
|
8
6
|
|
|
9
|
-
_all_ = ["ChatMessageRetriever"
|
|
7
|
+
_all_ = ["ChatMessageRetriever"]
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, Optional
|
|
6
6
|
|
|
7
7
|
from haystack import DeserializationError, component, default_from_dict, default_to_dict, logging
|
|
8
8
|
from haystack.core.serialization import import_class_by_name
|
|
9
|
-
from haystack.dataclasses import ChatMessage
|
|
9
|
+
from haystack.dataclasses import ChatMessage, ChatRole
|
|
10
10
|
|
|
11
11
|
from haystack_experimental.chat_message_stores.types import ChatMessageStore
|
|
12
12
|
|
|
@@ -30,41 +30,40 @@ class ChatMessageRetriever:
|
|
|
30
30
|
]
|
|
31
31
|
|
|
32
32
|
message_store = InMemoryChatMessageStore()
|
|
33
|
-
message_store.write_messages(messages)
|
|
33
|
+
message_store.write_messages(chat_history_id="user_456_session_123", messages=messages)
|
|
34
34
|
retriever = ChatMessageRetriever(message_store)
|
|
35
35
|
|
|
36
|
-
result = retriever.run()
|
|
36
|
+
result = retriever.run(chat_history_id="user_456_session_123")
|
|
37
37
|
|
|
38
38
|
print(result["messages"])
|
|
39
39
|
```
|
|
40
40
|
"""
|
|
41
41
|
|
|
42
|
-
def __init__(self,
|
|
42
|
+
def __init__(self, chat_message_store: ChatMessageStore, last_k: Optional[int] = 10):
|
|
43
43
|
"""
|
|
44
44
|
Create the ChatMessageRetriever component.
|
|
45
45
|
|
|
46
|
-
:param
|
|
46
|
+
:param chat_message_store:
|
|
47
47
|
An instance of a ChatMessageStore.
|
|
48
48
|
:param last_k:
|
|
49
49
|
The number of last messages to retrieve. Defaults to 10 messages if not specified.
|
|
50
50
|
"""
|
|
51
|
-
self.
|
|
52
|
-
if last_k <= 0:
|
|
53
|
-
raise ValueError(f"last_k must be greater than 0. Currently,
|
|
51
|
+
self.chat_message_store = chat_message_store
|
|
52
|
+
if last_k and last_k <= 0:
|
|
53
|
+
raise ValueError(f"last_k must be greater than 0. Currently, last_k is {last_k}")
|
|
54
54
|
self.last_k = last_k
|
|
55
55
|
|
|
56
|
-
def to_dict(self) ->
|
|
56
|
+
def to_dict(self) -> dict[str, Any]:
|
|
57
57
|
"""
|
|
58
58
|
Serializes the component to a dictionary.
|
|
59
59
|
|
|
60
60
|
:returns:
|
|
61
61
|
Dictionary with serialized data.
|
|
62
62
|
"""
|
|
63
|
-
|
|
64
|
-
return default_to_dict(self, message_store=message_store, last_k=self.last_k)
|
|
63
|
+
return default_to_dict(self, chat_message_store=self.chat_message_store.to_dict(), last_k=self.last_k)
|
|
65
64
|
|
|
66
65
|
@classmethod
|
|
67
|
-
def from_dict(cls, data:
|
|
66
|
+
def from_dict(cls, data: dict[str, Any]) -> "ChatMessageRetriever":
|
|
68
67
|
"""
|
|
69
68
|
Deserializes the component from a dictionary.
|
|
70
69
|
|
|
@@ -74,35 +73,67 @@ class ChatMessageRetriever:
|
|
|
74
73
|
The deserialized component.
|
|
75
74
|
"""
|
|
76
75
|
init_params = data.get("init_parameters", {})
|
|
77
|
-
if "
|
|
78
|
-
raise DeserializationError("Missing '
|
|
79
|
-
if "type" not in init_params["
|
|
76
|
+
if "chat_message_store" not in init_params:
|
|
77
|
+
raise DeserializationError("Missing 'chat_message_store' in serialization data")
|
|
78
|
+
if "type" not in init_params["chat_message_store"]:
|
|
80
79
|
raise DeserializationError("Missing 'type' in message store's serialization data")
|
|
81
80
|
|
|
82
|
-
message_store_data = init_params["
|
|
81
|
+
message_store_data = init_params["chat_message_store"]
|
|
83
82
|
try:
|
|
84
83
|
message_store_class = import_class_by_name(message_store_data["type"])
|
|
85
84
|
except ImportError as e:
|
|
86
85
|
raise DeserializationError(f"Class '{message_store_data['type']}' not correctly imported") from e
|
|
86
|
+
if not hasattr(message_store_class, "from_dict"):
|
|
87
|
+
raise DeserializationError(f"{message_store_class} does not have from_dict method implemented.")
|
|
88
|
+
init_params["chat_message_store"] = message_store_class.from_dict(message_store_data)
|
|
87
89
|
|
|
88
|
-
data["init_parameters"]["message_store"] = default_from_dict(message_store_class, message_store_data)
|
|
89
90
|
return default_from_dict(cls, data)
|
|
90
91
|
|
|
91
|
-
@component.output_types(messages=
|
|
92
|
-
def run(
|
|
92
|
+
@component.output_types(messages=list[ChatMessage])
|
|
93
|
+
def run(
|
|
94
|
+
self,
|
|
95
|
+
chat_history_id: str,
|
|
96
|
+
*,
|
|
97
|
+
last_k: Optional[int] = None,
|
|
98
|
+
current_messages: Optional[list[ChatMessage]] = None,
|
|
99
|
+
) -> dict[str, list[ChatMessage]]:
|
|
93
100
|
"""
|
|
94
101
|
Run the ChatMessageRetriever
|
|
95
102
|
|
|
103
|
+
:param chat_history_id:
|
|
104
|
+
A unique identifier for the chat session or conversation whose messages should be retrieved.
|
|
105
|
+
Each `chat_history_id` corresponds to a distinct chat history stored in the underlying ChatMessageStore.
|
|
106
|
+
For example, use a session ID or conversation ID to isolate messages from different chat sessions.
|
|
96
107
|
:param last_k: The number of last messages to retrieve. This parameter takes precedence over the last_k
|
|
97
108
|
parameter passed to the ChatMessageRetriever constructor. If unspecified, the last_k parameter passed
|
|
98
109
|
to the constructor will be used.
|
|
110
|
+
:param current_messages:
|
|
111
|
+
A list of incoming chat messages to combine with the retrieved messages. System messages from this list
|
|
112
|
+
are prepended before the retrieved history, while all other messages (e.g., user messages) are appended
|
|
113
|
+
after. This is useful for including new conversational context alongside stored history so the output
|
|
114
|
+
can be directly used as input to a ChatGenerator or an Agent. If not provided, only the stored messages
|
|
115
|
+
will be returned.
|
|
116
|
+
|
|
99
117
|
:returns:
|
|
100
|
-
|
|
101
|
-
|
|
118
|
+
A dictionary with the following key:
|
|
119
|
+
- `messages` - The retrieved chat messages combined with any provided current messages.
|
|
120
|
+
:raises ValueError: If last_k is not None and is less than 0.
|
|
102
121
|
"""
|
|
103
|
-
if last_k is not None and last_k
|
|
104
|
-
raise ValueError("last_k must be
|
|
122
|
+
if last_k is not None and last_k < 0:
|
|
123
|
+
raise ValueError("last_k must be 0 or greater")
|
|
124
|
+
|
|
125
|
+
resolved_last_k = last_k or self.last_k
|
|
126
|
+
if resolved_last_k == 0:
|
|
127
|
+
return {"messages": current_messages or []}
|
|
128
|
+
|
|
129
|
+
retrieved_messages = self.chat_message_store.retrieve_messages(
|
|
130
|
+
chat_history_id=chat_history_id, last_k=last_k or self.last_k
|
|
131
|
+
)
|
|
105
132
|
|
|
106
|
-
|
|
133
|
+
if not current_messages:
|
|
134
|
+
return {"messages": retrieved_messages}
|
|
107
135
|
|
|
108
|
-
|
|
136
|
+
# We maintain the order: system messages first, then stored messages, then new user messages
|
|
137
|
+
system_messages = [msg for msg in current_messages if msg.is_from(ChatRole.SYSTEM)]
|
|
138
|
+
other_messages = [msg for msg in current_messages if not msg.is_from(ChatRole.SYSTEM)]
|
|
139
|
+
return {"messages": system_messages + retrieved_messages + other_messages}
|
|
@@ -2,16 +2,14 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
from typing import Any
|
|
5
|
+
from typing import Any
|
|
6
6
|
|
|
7
|
-
from haystack import DeserializationError, component, default_from_dict, default_to_dict
|
|
7
|
+
from haystack import DeserializationError, component, default_from_dict, default_to_dict
|
|
8
8
|
from haystack.core.serialization import import_class_by_name
|
|
9
9
|
from haystack.dataclasses import ChatMessage
|
|
10
10
|
|
|
11
11
|
from haystack_experimental.chat_message_stores.types import ChatMessageStore
|
|
12
12
|
|
|
13
|
-
logger = logging.getLogger(__name__)
|
|
14
|
-
|
|
15
13
|
|
|
16
14
|
@component
|
|
17
15
|
class ChatMessageWriter:
|
|
@@ -30,30 +28,30 @@ class ChatMessageWriter:
|
|
|
30
28
|
]
|
|
31
29
|
message_store = InMemoryChatMessageStore()
|
|
32
30
|
writer = ChatMessageWriter(message_store)
|
|
33
|
-
writer.run(messages)
|
|
31
|
+
writer.run(chat_history_id="user_456_session_123", messages=messages)
|
|
34
32
|
```
|
|
35
33
|
"""
|
|
36
34
|
|
|
37
|
-
def __init__(self,
|
|
35
|
+
def __init__(self, chat_message_store: ChatMessageStore) -> None:
|
|
38
36
|
"""
|
|
39
37
|
Create a ChatMessageWriter component.
|
|
40
38
|
|
|
41
|
-
:param
|
|
39
|
+
:param chat_message_store:
|
|
42
40
|
The ChatMessageStore where the chat messages are to be written.
|
|
43
41
|
"""
|
|
44
|
-
self.
|
|
42
|
+
self.chat_message_store = chat_message_store
|
|
45
43
|
|
|
46
|
-
def to_dict(self) ->
|
|
44
|
+
def to_dict(self) -> dict[str, Any]:
|
|
47
45
|
"""
|
|
48
46
|
Serializes the component to a dictionary.
|
|
49
47
|
|
|
50
48
|
:returns:
|
|
51
49
|
Dictionary with serialized data.
|
|
52
50
|
"""
|
|
53
|
-
return default_to_dict(self,
|
|
51
|
+
return default_to_dict(self, chat_message_store=self.chat_message_store.to_dict())
|
|
54
52
|
|
|
55
53
|
@classmethod
|
|
56
|
-
def from_dict(cls, data:
|
|
54
|
+
def from_dict(cls, data: dict[str, Any]) -> "ChatMessageWriter":
|
|
57
55
|
"""
|
|
58
56
|
Deserializes the component from a dictionary.
|
|
59
57
|
|
|
@@ -66,31 +64,36 @@ class ChatMessageWriter:
|
|
|
66
64
|
If the message store is not properly specified in the serialization data or its type cannot be imported.
|
|
67
65
|
"""
|
|
68
66
|
init_params = data.get("init_parameters", {})
|
|
69
|
-
if "
|
|
70
|
-
raise DeserializationError("Missing '
|
|
71
|
-
if "type" not in init_params["
|
|
67
|
+
if "chat_message_store" not in init_params:
|
|
68
|
+
raise DeserializationError("Missing 'chat_message_store' in serialization data")
|
|
69
|
+
if "type" not in init_params["chat_message_store"]:
|
|
72
70
|
raise DeserializationError("Missing 'type' in message store's serialization data")
|
|
73
|
-
|
|
71
|
+
|
|
72
|
+
message_store_data = init_params["chat_message_store"]
|
|
74
73
|
try:
|
|
75
74
|
message_store_class = import_class_by_name(message_store_data["type"])
|
|
76
75
|
except ImportError as e:
|
|
77
76
|
raise DeserializationError(f"Class '{message_store_data['type']}' not correctly imported") from e
|
|
78
|
-
|
|
77
|
+
if not hasattr(message_store_class, "from_dict"):
|
|
78
|
+
raise DeserializationError(f"{message_store_class} does not have from_dict method implemented.")
|
|
79
|
+
init_params["chat_message_store"] = message_store_class.from_dict(message_store_data)
|
|
80
|
+
|
|
79
81
|
return default_from_dict(cls, data)
|
|
80
82
|
|
|
81
83
|
@component.output_types(messages_written=int)
|
|
82
|
-
def run(self, messages:
|
|
84
|
+
def run(self, chat_history_id: str, messages: list[ChatMessage]) -> dict[str, int]:
|
|
83
85
|
"""
|
|
84
86
|
Run the ChatMessageWriter on the given input data.
|
|
85
87
|
|
|
88
|
+
:param chat_history_id:
|
|
89
|
+
A unique identifier for the chat session or conversation whose messages should be retrieved.
|
|
90
|
+
Each `chat_history_id` corresponds to a distinct chat history stored in the underlying ChatMessageStore.
|
|
91
|
+
For example, use a session ID or conversation ID to isolate messages from different chat sessions.
|
|
86
92
|
:param messages:
|
|
87
93
|
A list of chat messages to write to the store.
|
|
94
|
+
|
|
88
95
|
:returns:
|
|
89
96
|
- `messages_written`: Number of messages written to the ChatMessageStore.
|
|
90
|
-
|
|
91
|
-
:raises ValueError:
|
|
92
|
-
If the specified message store is not found.
|
|
93
97
|
"""
|
|
94
|
-
|
|
95
|
-
messages_written = self.message_store.write_messages(messages=messages)
|
|
98
|
+
messages_written = self.chat_message_store.write_messages(chat_history_id=chat_history_id, messages=messages)
|
|
96
99
|
return {"messages_written": messages_written}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: haystack-experimental
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.15.1
|
|
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
|
|
@@ -71,35 +71,24 @@ that includes it. Once it reaches the end of its lifespan, the experiment will b
|
|
|
71
71
|
|
|
72
72
|
### Active experiments
|
|
73
73
|
|
|
74
|
-
| Name | Type
|
|
75
|
-
|
|
76
|
-
| [`
|
|
77
|
-
| [`
|
|
78
|
-
| [`
|
|
79
|
-
| [`
|
|
80
|
-
| [`
|
|
81
|
-
| [`
|
|
82
|
-
| [`MultiQueryTextRetriever`][14] | MultiQueryTextRetriever | November 2025 | None | None | [Discuss][12] |
|
|
83
|
-
| [`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] |
|
|
84
|
-
| [`MarkdownHeaderLevelInferrer`][15] | Preprocessor | January 2025 | None | None | [Discuss][16] |
|
|
85
|
-
| [`Agent`][17]; [Confirmation Policies][18]; [ConfirmationUIs][19]; [ConfirmationStrategies][20]; [`ConfirmationUIResult` and `ToolExecutionDecision`][21] [HITLBreakpointException][22] | Human in the Loop | December 2025 | rich | None | [Discuss][23] |
|
|
86
|
-
| [`LLMSummarizer`][24] | Document Summarizer | January 2025 | None | None | [Discuss][25] |
|
|
74
|
+
| Name | Type | Expected End Date | Dependencies | Cookbook | Discussion |
|
|
75
|
+
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|-------------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
|
|
76
|
+
| [`EmbeddingBasedDocumentSplitter`][8] | EmbeddingBasedDocumentSplitter | August 2025 | None | None | [Discuss][7] |
|
|
77
|
+
| [`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] |
|
|
78
|
+
| [`MarkdownHeaderLevelInferrer`][15] | Preprocessor | January 2025 | None | None | [Discuss][16] |
|
|
79
|
+
| [`Agent`][17]; [Confirmation Policies][18]; [ConfirmationUIs][19]; [ConfirmationStrategies][20]; [`ConfirmationUIResult` and `ToolExecutionDecision`][21] [HITLBreakpointException][22] | Human in the Loop | December 2025 | rich | None | [Discuss][23] |
|
|
80
|
+
| [`LLMSummarizer`][24] | Document Summarizer | January 2025 | None | None | [Discuss][25] |
|
|
81
|
+
| [`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] |
|
|
87
82
|
|
|
88
83
|
[1]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/chat_message_stores/in_memory.py
|
|
89
84
|
[2]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/retrievers/chat_message_retriever.py
|
|
90
85
|
[3]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/writers/chat_message_writer.py
|
|
91
86
|
[4]: https://github.com/deepset-ai/haystack-experimental/discussions/75
|
|
92
|
-
[5]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/query/query_expander.py
|
|
93
|
-
[6]: https://github.com/deepset-ai/haystack-experimental/discussions/346
|
|
94
87
|
[7]: https://github.com/deepset-ai/haystack-experimental/discussions/356
|
|
95
88
|
[8]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/preprocessors/embedding_based_document_splitter.py
|
|
96
89
|
[9]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/generators/chat/openai.py
|
|
97
90
|
[10]: https://github.com/deepset-ai/haystack-experimental/discussions/361
|
|
98
|
-
[
|
|
99
|
-
[12]: https://github.com/deepset-ai/haystack-experimental/discussions/364
|
|
100
|
-
[13]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/retrievers/multi_query_embedding_retriever.py
|
|
101
|
-
[14]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/retrievers/multi_query_text_retriever.py
|
|
102
|
-
[15]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/preprocessors/md_header_level_inferrer.py
|
|
91
|
+
[15]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/preprocessors/md_header_level_inferrer.py
|
|
103
92
|
[16]: https://github.com/deepset-ai/haystack-experimental/discussions/376
|
|
104
93
|
[17]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/agent.py
|
|
105
94
|
[18]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/human_in_the_loop/policies.py
|
|
@@ -112,16 +101,20 @@ that includes it. Once it reaches the end of its lifespan, the experiment will b
|
|
|
112
101
|
[25]: https://github.com/deepset-ai/haystack-experimental/discussions/382
|
|
113
102
|
|
|
114
103
|
### Adopted experiments
|
|
115
|
-
| Name
|
|
116
|
-
|
|
117
|
-
| `ChatMessage` refactoring; `Tool` class; tool support in ChatGenerators; `ToolInvoker`
|
|
118
|
-
| `AsyncPipeline`; `Pipeline` bug fixes and refactoring
|
|
119
|
-
| `LLMMetadataExtractor`
|
|
120
|
-
| `Auto-Merging Retriever` & `HierarchicalDocumentSplitter`
|
|
121
|
-
| `Agent`
|
|
122
|
-
| `SuperComponent`
|
|
123
|
-
| `Pipeline`
|
|
124
|
-
| `ImageContent`; Image Converters; multimodal support in `OpenAIChatGenerator` and `AmazonBedrockChatGenerator`; `ChatPromptBuilder` refactoring; `SentenceTransformersDocumentImageEmbedder`; `LLMDocumentContentExtractor`; new `Routers`
|
|
104
|
+
| Name | Type | Final release |
|
|
105
|
+
|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------|---------------|
|
|
106
|
+
| `ChatMessage` refactoring; `Tool` class; tool support in ChatGenerators; `ToolInvoker` | Tool Calling support | 0.4.0 |
|
|
107
|
+
| `AsyncPipeline`; `Pipeline` bug fixes and refactoring | AsyncPipeline execution | 0.7.0 |
|
|
108
|
+
| `LLMMetadataExtractor` | Metadata extraction with LLM | 0.7.0 |
|
|
109
|
+
| `Auto-Merging Retriever` & `HierarchicalDocumentSplitter` | Document Splitting & Retrieval Technique | 0.8.0 |
|
|
110
|
+
| `Agent` | Simplify Agent development | 0.8.0 |
|
|
111
|
+
| `SuperComponent` | Simplify Pipeline development | 0.8.0 |
|
|
112
|
+
| `Pipeline` | Pipeline breakpoints for debugging | 0.12.0 |
|
|
113
|
+
| `ImageContent`; Image Converters; multimodal support in `OpenAIChatGenerator` and `AmazonBedrockChatGenerator`; `ChatPromptBuilder` refactoring; `SentenceTransformersDocumentImageEmbedder`; `LLMDocumentContentExtractor`; new `Routers` | Multimodality | 0.12.0 |
|
|
114
|
+
| `QueryExpander` | Query Expansion Component | 0.14.3 |
|
|
115
|
+
| `MultiQueryEmbeddingRetriever` | MultiQueryEmbeddingRetriever | 0.14.3 |
|
|
116
|
+
| `MultiQueryTextRetriever` | MultiQueryTextRetriever | 0.14.3 |
|
|
117
|
+
|
|
125
118
|
|
|
126
119
|
### Discontinued experiments
|
|
127
120
|
|