haystack-experimental 0.14.3__tar.gz → 0.15.0__tar.gz

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.
Files changed (60) hide show
  1. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/.gitignore +1 -1
  2. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/PKG-INFO +24 -31
  3. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/README.md +23 -30
  4. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/chat_message_stores/__init__.py +1 -1
  5. haystack_experimental-0.15.0/haystack_experimental/chat_message_stores/in_memory.py +231 -0
  6. haystack_experimental-0.15.0/haystack_experimental/chat_message_stores/types.py +86 -0
  7. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/agent.py +147 -44
  8. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/human_in_the_loop/strategies.py +220 -3
  9. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/human_in_the_loop/types.py +36 -1
  10. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/embedders/types/protocol.py +2 -2
  11. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/preprocessors/embedding_based_document_splitter.py +16 -16
  12. haystack_experimental-0.15.0/haystack_experimental/components/retrievers/__init__.py +7 -0
  13. haystack_experimental-0.15.0/haystack_experimental/components/retrievers/chat_message_retriever.py +139 -0
  14. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/writers/__init__.py +1 -1
  15. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/writers/chat_message_writer.py +25 -22
  16. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/pyproject.toml +4 -10
  17. haystack_experimental-0.14.3/haystack_experimental/chat_message_stores/in_memory.py +0 -86
  18. haystack_experimental-0.14.3/haystack_experimental/chat_message_stores/types.py +0 -74
  19. haystack_experimental-0.14.3/haystack_experimental/components/query/__init__.py +0 -18
  20. haystack_experimental-0.14.3/haystack_experimental/components/query/query_expander.py +0 -294
  21. haystack_experimental-0.14.3/haystack_experimental/components/retrievers/__init__.py +0 -9
  22. haystack_experimental-0.14.3/haystack_experimental/components/retrievers/chat_message_retriever.py +0 -108
  23. haystack_experimental-0.14.3/haystack_experimental/components/retrievers/multi_query_embedding_retriever.py +0 -173
  24. haystack_experimental-0.14.3/haystack_experimental/components/retrievers/multi_query_text_retriever.py +0 -150
  25. haystack_experimental-0.14.3/haystack_experimental/super_components/indexers/__init__.py +0 -11
  26. haystack_experimental-0.14.3/haystack_experimental/super_components/indexers/sentence_transformers_document_indexer.py +0 -199
  27. haystack_experimental-0.14.3/haystack_experimental/utils/__init__.py +0 -3
  28. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/LICENSE +0 -0
  29. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/LICENSE-MIT.txt +0 -0
  30. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/__init__.py +0 -0
  31. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/__init__.py +0 -0
  32. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/__init__.py +0 -0
  33. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/human_in_the_loop/__init__.py +0 -0
  34. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/human_in_the_loop/breakpoint.py +0 -0
  35. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/human_in_the_loop/dataclasses.py +0 -0
  36. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/human_in_the_loop/errors.py +0 -0
  37. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/human_in_the_loop/policies.py +0 -0
  38. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/agents/human_in_the_loop/user_interfaces.py +0 -0
  39. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/embedders/__init__.py +0 -0
  40. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/embedders/types/__init__.py +0 -0
  41. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/generators/__init__.py +0 -0
  42. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/generators/chat/__init__.py +0 -0
  43. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/generators/chat/openai.py +0 -0
  44. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/preprocessors/__init__.py +0 -0
  45. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/preprocessors/md_header_level_inferrer.py +0 -0
  46. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/retrievers/types/__init__.py +0 -0
  47. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/retrievers/types/protocol.py +0 -0
  48. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/summarizers/__init__.py +0 -0
  49. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/components/summarizers/llm_summarizer.py +0 -0
  50. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/core/__init__.py +0 -0
  51. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/core/pipeline/__init__.py +0 -0
  52. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/core/pipeline/breakpoint.py +0 -0
  53. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/dataclasses/__init__.py +0 -0
  54. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/dataclasses/breakpoints.py +0 -0
  55. {haystack_experimental-0.14.3/haystack_experimental/super_components → haystack_experimental-0.15.0/haystack_experimental/utils}/__init__.py +0 -0
  56. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/utils/hallucination_risk_calculator/__init__.py +0 -0
  57. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/utils/hallucination_risk_calculator/core_math.py +0 -0
  58. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/utils/hallucination_risk_calculator/dataclasses.py +0 -0
  59. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/utils/hallucination_risk_calculator/openai_planner.py +0 -0
  60. {haystack_experimental-0.14.3 → haystack_experimental-0.15.0}/haystack_experimental/utils/hallucination_risk_calculator/skeletonization.py +0 -0
@@ -75,7 +75,7 @@ instance/
75
75
  .scrapy
76
76
 
77
77
  # documentation
78
- docs/pydoc/temp/
78
+ pydoc/temp/
79
79
 
80
80
  # PyBuilder
81
81
  target/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: haystack-experimental
3
- Version: 0.14.3
3
+ Version: 0.15.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
@@ -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 | Expected End Date | Dependencies | Cookbook | Discussion |
75
- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------|-------------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
76
- | [`InMemoryChatMessageStore`][1] | Memory Store | December 2024 | 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] |
77
- | [`ChatMessageRetriever`][2] | Memory Component | December 2024 | 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] |
78
- | [`ChatMessageWriter`][3] | Memory Component | December 2024 | 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
- | [`QueryExpander`][5] | Query Expansion Component | October 2025 | None | None | [Discuss][6] |
80
- | [`EmbeddingBasedDocumentSplitter`][8] | EmbeddingBasedDocumentSplitter | August 2025 | None | None | [Discuss][7] |
81
- | [`MultiQueryEmbeddingRetriever`][13] | MultiQueryEmbeddingRetriever | November 2025 | None | None | [Discuss][11] |
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
- [11]: https://github.com/deepset-ai/haystack-experimental/discussions/363
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 | Type | Final release |
116
- |----------------------------------------------------------------------------------------|------------------------------------------|---------------|
117
- | `ChatMessage` refactoring; `Tool` class; tool support in ChatGenerators; `ToolInvoker` | Tool Calling support | 0.4.0 |
118
- | `AsyncPipeline`; `Pipeline` bug fixes and refactoring | AsyncPipeline execution | 0.7.0 |
119
- | `LLMMetadataExtractor` | Metadata extraction with LLM | 0.7.0 |
120
- | `Auto-Merging Retriever` & `HierarchicalDocumentSplitter` | Document Splitting & Retrieval Technique | 0.8.0 |
121
- | `Agent` | Simplify Agent development | 0.8.0 |
122
- | `SuperComponent` | Simplify Pipeline development | 0.8.0 |
123
- | `Pipeline` | Pipeline breakpoints for debugging | 0.12.0 |
124
- | `ImageContent`; Image Converters; multimodal support in `OpenAIChatGenerator` and `AmazonBedrockChatGenerator`; `ChatPromptBuilder` refactoring; `SentenceTransformersDocumentImageEmbedder`; `LLMDocumentContentExtractor`; new `Routers` | Multimodality | 0.12.0 |
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
 
@@ -41,35 +41,24 @@ that includes it. Once it reaches the end of its lifespan, the experiment will b
41
41
 
42
42
  ### Active experiments
43
43
 
44
- | Name | Type | Expected End Date | Dependencies | Cookbook | Discussion |
45
- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------|-------------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
46
- | [`InMemoryChatMessageStore`][1] | Memory Store | December 2024 | 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] |
47
- | [`ChatMessageRetriever`][2] | Memory Component | December 2024 | 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] |
48
- | [`ChatMessageWriter`][3] | Memory Component | December 2024 | 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] |
49
- | [`QueryExpander`][5] | Query Expansion Component | October 2025 | None | None | [Discuss][6] |
50
- | [`EmbeddingBasedDocumentSplitter`][8] | EmbeddingBasedDocumentSplitter | August 2025 | None | None | [Discuss][7] |
51
- | [`MultiQueryEmbeddingRetriever`][13] | MultiQueryEmbeddingRetriever | November 2025 | None | None | [Discuss][11] |
52
- | [`MultiQueryTextRetriever`][14] | MultiQueryTextRetriever | November 2025 | None | None | [Discuss][12] |
53
- | [`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] |
54
- | [`MarkdownHeaderLevelInferrer`][15] | Preprocessor | January 2025 | None | None | [Discuss][16] |
55
- | [`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] |
56
- | [`LLMSummarizer`][24] | Document Summarizer | January 2025 | None | None | [Discuss][25] |
44
+ | Name | Type | Expected End Date | Dependencies | Cookbook | Discussion |
45
+ |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------|-------------------|--------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------|
46
+ | [`EmbeddingBasedDocumentSplitter`][8] | EmbeddingBasedDocumentSplitter | August 2025 | None | None | [Discuss][7] |
47
+ | [`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] |
48
+ | [`MarkdownHeaderLevelInferrer`][15] | Preprocessor | January 2025 | None | None | [Discuss][16] |
49
+ | [`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] |
50
+ | [`LLMSummarizer`][24] | Document Summarizer | January 2025 | None | None | [Discuss][25] |
51
+ | [`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] |
57
52
 
58
53
  [1]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/chat_message_stores/in_memory.py
59
54
  [2]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/retrievers/chat_message_retriever.py
60
55
  [3]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/writers/chat_message_writer.py
61
56
  [4]: https://github.com/deepset-ai/haystack-experimental/discussions/75
62
- [5]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/query/query_expander.py
63
- [6]: https://github.com/deepset-ai/haystack-experimental/discussions/346
64
57
  [7]: https://github.com/deepset-ai/haystack-experimental/discussions/356
65
58
  [8]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/preprocessors/embedding_based_document_splitter.py
66
59
  [9]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/generators/chat/openai.py
67
60
  [10]: https://github.com/deepset-ai/haystack-experimental/discussions/361
68
- [11]: https://github.com/deepset-ai/haystack-experimental/discussions/363
69
- [12]: https://github.com/deepset-ai/haystack-experimental/discussions/364
70
- [13]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/retrievers/multi_query_embedding_retriever.py
71
- [14]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/retrievers/multi_query_text_retriever.py
72
- [15]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/preprocessors/md_header_level_inferrer.py
61
+ [15]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/preprocessors/md_header_level_inferrer.py
73
62
  [16]: https://github.com/deepset-ai/haystack-experimental/discussions/376
74
63
  [17]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/agent.py
75
64
  [18]: https://github.com/deepset-ai/haystack-experimental/blob/main/haystack_experimental/components/agents/human_in_the_loop/policies.py
@@ -82,16 +71,20 @@ that includes it. Once it reaches the end of its lifespan, the experiment will b
82
71
  [25]: https://github.com/deepset-ai/haystack-experimental/discussions/382
83
72
 
84
73
  ### Adopted experiments
85
- | Name | Type | Final release |
86
- |----------------------------------------------------------------------------------------|------------------------------------------|---------------|
87
- | `ChatMessage` refactoring; `Tool` class; tool support in ChatGenerators; `ToolInvoker` | Tool Calling support | 0.4.0 |
88
- | `AsyncPipeline`; `Pipeline` bug fixes and refactoring | AsyncPipeline execution | 0.7.0 |
89
- | `LLMMetadataExtractor` | Metadata extraction with LLM | 0.7.0 |
90
- | `Auto-Merging Retriever` & `HierarchicalDocumentSplitter` | Document Splitting & Retrieval Technique | 0.8.0 |
91
- | `Agent` | Simplify Agent development | 0.8.0 |
92
- | `SuperComponent` | Simplify Pipeline development | 0.8.0 |
93
- | `Pipeline` | Pipeline breakpoints for debugging | 0.12.0 |
94
- | `ImageContent`; Image Converters; multimodal support in `OpenAIChatGenerator` and `AmazonBedrockChatGenerator`; `ChatPromptBuilder` refactoring; `SentenceTransformersDocumentImageEmbedder`; `LLMDocumentContentExtractor`; new `Routers` | Multimodality | 0.12.0 |
74
+ | Name | Type | Final release |
75
+ |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------|---------------|
76
+ | `ChatMessage` refactoring; `Tool` class; tool support in ChatGenerators; `ToolInvoker` | Tool Calling support | 0.4.0 |
77
+ | `AsyncPipeline`; `Pipeline` bug fixes and refactoring | AsyncPipeline execution | 0.7.0 |
78
+ | `LLMMetadataExtractor` | Metadata extraction with LLM | 0.7.0 |
79
+ | `Auto-Merging Retriever` & `HierarchicalDocumentSplitter` | Document Splitting & Retrieval Technique | 0.8.0 |
80
+ | `Agent` | Simplify Agent development | 0.8.0 |
81
+ | `SuperComponent` | Simplify Pipeline development | 0.8.0 |
82
+ | `Pipeline` | Pipeline breakpoints for debugging | 0.12.0 |
83
+ | `ImageContent`; Image Converters; multimodal support in `OpenAIChatGenerator` and `AmazonBedrockChatGenerator`; `ChatPromptBuilder` refactoring; `SentenceTransformersDocumentImageEmbedder`; `LLMDocumentContentExtractor`; new `Routers` | Multimodality | 0.12.0 |
84
+ | `QueryExpander` | Query Expansion Component | 0.14.3 |
85
+ | `MultiQueryEmbeddingRetriever` | MultiQueryEmbeddingRetriever | 0.14.3 |
86
+ | `MultiQueryTextRetriever` | MultiQueryTextRetriever | 0.14.3 |
87
+
95
88
 
96
89
  ### Discontinued experiments
97
90
 
@@ -4,4 +4,4 @@
4
4
 
5
5
  from haystack_experimental.chat_message_stores.in_memory import InMemoryChatMessageStore
6
6
 
7
- _all_ = ["InMemoryChatMessageStore"]
7
+ __all__ = ["InMemoryChatMessageStore"]
@@ -0,0 +1,231 @@
1
+ # SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from dataclasses import replace
6
+ from typing import Any, Iterable, Optional
7
+
8
+ from haystack import default_from_dict, default_to_dict
9
+ from haystack.dataclasses import ChatMessage, ChatRole
10
+
11
+ # Global storage for all InMemoryDocumentStore instances, indexed by the chat history id.
12
+ _STORAGES: dict[str, list[ChatMessage]] = {}
13
+
14
+
15
+ class InMemoryChatMessageStore:
16
+ """
17
+ Stores chat messages in-memory.
18
+
19
+ The `chat_history_id` parameter is used as a unique identifier for each conversation or chat session.
20
+ It acts as a namespace that isolates messages from different sessions. Each `chat_history_id` value corresponds to a
21
+ separate list of `ChatMessage` objects stored in memory.
22
+
23
+ Typical usage involves providing a unique `chat_history_id` (for example, a session ID or conversation ID)
24
+ whenever you write, read, or delete messages. This ensures that chat messages from different
25
+ conversations do not overlap.
26
+
27
+ Usage example:
28
+ ```python
29
+ from haystack.dataclasses import ChatMessage
30
+ from haystack_experimental.chat_message_stores.in_memory import InMemoryChatMessageStore
31
+
32
+ message_store = InMemoryChatMessageStore()
33
+
34
+ messages = [
35
+ ChatMessage.from_assistant("Hello, how can I help you?"),
36
+ ChatMessage.from_user("Hi, I have a question about Python. What is a Protocol?"),
37
+ ]
38
+ message_store.write_messages(chat_history_id="user_456_session_123", messages=messages)
39
+ retrieved_messages = message_store.retrieve_messages(chat_history_id="user_456_session_123")
40
+
41
+ print(retrieved_messages)
42
+ ```
43
+ """
44
+
45
+ def __init__(self, skip_system_messages: bool = True, last_k: Optional[int] = 10) -> None:
46
+ """
47
+ Create an InMemoryChatMessageStore.
48
+
49
+ :param skip_system_messages:
50
+ Whether to skip storing system messages. Defaults to True.
51
+ :param last_k:
52
+ The number of last messages to retrieve. Defaults to 10 messages if not specified.
53
+ """
54
+ self.skip_system_messages = skip_system_messages
55
+ self.last_k = last_k
56
+
57
+ def to_dict(self) -> dict[str, Any]:
58
+ """
59
+ Serializes the component to a dictionary.
60
+
61
+ :returns:
62
+ Dictionary with serialized data.
63
+ """
64
+ return default_to_dict(self, skip_system_messages=self.skip_system_messages, last_k=self.last_k)
65
+
66
+ @classmethod
67
+ def from_dict(cls, data: dict[str, Any]) -> "InMemoryChatMessageStore":
68
+ """
69
+ Deserializes the component from a dictionary.
70
+
71
+ :param data:
72
+ The dictionary to deserialize from.
73
+ :returns:
74
+ The deserialized component.
75
+ """
76
+ return default_from_dict(cls, data)
77
+
78
+ def count_messages(self, chat_history_id: str) -> int:
79
+ """
80
+ Returns the number of chat messages stored in this store.
81
+
82
+ :param chat_history_id:
83
+ The chat history id for which to count messages.
84
+
85
+ :returns: The number of messages.
86
+ """
87
+ return len(_STORAGES.get(chat_history_id, []))
88
+
89
+ def write_messages(self, chat_history_id: str, messages: list[ChatMessage]) -> int:
90
+ """
91
+ Writes chat messages to the ChatMessageStore.
92
+
93
+ :param chat_history_id:
94
+ The chat history id under which to store the messages.
95
+ :param messages:
96
+ A list of ChatMessages to write.
97
+
98
+ :returns: The number of messages written.
99
+
100
+ :raises ValueError: If messages is not a list of ChatMessages.
101
+ """
102
+ if not isinstance(messages, Iterable) or any(not isinstance(message, ChatMessage) for message in messages):
103
+ raise ValueError("Please provide a list of ChatMessages.")
104
+
105
+ # We assign an ID to messages that don't have one yet. The ID simply corresponds to the chat_history_id in the
106
+ # array.
107
+ counter = self.count_messages(chat_history_id)
108
+ messages_with_id = []
109
+ for msg in messages:
110
+ # Skip system messages if configured to do so
111
+ if self.skip_system_messages and msg.is_from(ChatRole.SYSTEM):
112
+ continue
113
+
114
+ chat_message_id = msg.meta.get("chat_message_id")
115
+ if chat_message_id is None:
116
+ # We use replace to avoid mutating the original message
117
+ msg = replace(msg, _meta={"chat_message_id": str(counter), **msg.meta})
118
+ counter += 1
119
+
120
+ messages_with_id.append(msg)
121
+
122
+ # For now, we always skip messages that are already stored based on their ID.
123
+ existing_messages = _STORAGES.get(chat_history_id, [])
124
+ existing_ids = {
125
+ msg.meta.get("chat_message_id") for msg in existing_messages if msg.meta.get("chat_message_id") is not None
126
+ }
127
+ messages_to_write = [
128
+ message for message in messages_with_id if message.meta["chat_message_id"] not in existing_ids
129
+ ]
130
+
131
+ for message in messages_to_write:
132
+ if chat_history_id not in _STORAGES:
133
+ _STORAGES[chat_history_id] = []
134
+ _STORAGES[chat_history_id].append(message)
135
+
136
+ return len(messages_to_write)
137
+
138
+ def retrieve_messages(self, chat_history_id: str, last_k: Optional[int] = None) -> list[ChatMessage]:
139
+ """
140
+ Retrieves all stored chat messages.
141
+
142
+ :param chat_history_id:
143
+ The chat history id from which to retrieve messages.
144
+ :param last_k:
145
+ The number of last messages to retrieve. If unspecified, the last_k parameter passed
146
+ to the constructor will be used.
147
+
148
+ :returns: A list of chat messages.
149
+ :raises ValueError:
150
+ If last_k is not None and is less than 0.
151
+ """
152
+
153
+ if last_k is not None and last_k < 0:
154
+ raise ValueError("last_k must be 0 or greater")
155
+
156
+ resolved_last_k = last_k if last_k is not None else self.last_k
157
+ if resolved_last_k == 0:
158
+ return []
159
+
160
+ messages = _STORAGES.get(chat_history_id, [])
161
+ if resolved_last_k is not None:
162
+ messages = self._get_last_k_messages(messages=messages, last_k=resolved_last_k)
163
+
164
+ return messages
165
+
166
+ @staticmethod
167
+ def _get_last_k_messages(messages: list[ChatMessage], last_k: int) -> list[ChatMessage]:
168
+ """
169
+ Get the last_k rounds of messages from the incoming list of messages.
170
+
171
+ This is done in such a way such the returned list of messages is always valid. By valid we mean it will
172
+ be submittable to an LLM without causing issues. For example, we want to avoid slicing the chat history in a
173
+ way that a ToolCall is present without its corresponding ToolOutput.
174
+
175
+ This is handled by treating ToolCalls and its corresponding ToolOutput(s) as a single unit when slicing the chat
176
+ history.
177
+
178
+ :param messages:
179
+ List of chat messages.
180
+ :param last_k:
181
+ The number of last rounds of messages to retrieve. By rounds of messages we mean pairs of
182
+ User -> Assistant messages. ToolCalls and ToolOutputs are considered part of the Assistant message.
183
+ :returns:
184
+ The sliced list of chat messages.
185
+ """
186
+ rounds = []
187
+ current = []
188
+
189
+ for msg in messages:
190
+ # Treat system messages as separate rounds
191
+ if msg.role == "system":
192
+ rounds.append([msg])
193
+ continue
194
+
195
+ # User messages always start a new round
196
+ if msg.role == "user":
197
+ current.append(msg)
198
+ continue
199
+
200
+ # Assistant messages can either end a round or continue it (in case of tool calls)
201
+ if msg.role == "assistant":
202
+ current.append(msg)
203
+ if msg.text and not msg.tool_calls:
204
+ rounds.append(current)
205
+ current = []
206
+ continue
207
+
208
+ # Append all other messages (e.g., tool outputs) to the current round
209
+ current.append(msg)
210
+
211
+ # Catch any remaining messages in the current round
212
+ if current:
213
+ rounds.append(current)
214
+
215
+ selected = rounds[-last_k:]
216
+ return [m for r in selected for m in r]
217
+
218
+ def delete_messages(self, chat_history_id: str) -> None:
219
+ """
220
+ Deletes all stored chat messages.
221
+
222
+ :param chat_history_id:
223
+ The chat history id from which to delete messages.
224
+ """
225
+ _STORAGES.pop(chat_history_id, None)
226
+
227
+ def delete_all_messages(self) -> None:
228
+ """
229
+ Deletes all stored chat messages from all chat history ids.
230
+ """
231
+ _STORAGES.clear()
@@ -0,0 +1,86 @@
1
+ # SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
2
+ #
3
+ # SPDX-License-Identifier: Apache-2.0
4
+
5
+ from typing import Any, Optional, Protocol
6
+
7
+ from haystack.dataclasses import ChatMessage
8
+
9
+ # Ellipsis are needed for the type checker, it's safe to disable module-wide
10
+ # pylint: disable=unnecessary-ellipsis
11
+
12
+
13
+ class ChatMessageStore(Protocol):
14
+ """
15
+ Stores ChatMessages to be used by the components of a Pipeline.
16
+
17
+ Classes implementing this protocol might store ChatMessages either in durable storage or in memory. They might
18
+ allow specialized components (e.g. retrievers) to perform retrieval on them, either by embedding, by keyword,
19
+ hybrid, and so on, depending on the backend used.
20
+
21
+ In order to write or retrieve chat messages, consider using a ChatMessageWriter or ChatMessageRetriever.
22
+ """
23
+
24
+ def to_dict(self) -> dict[str, Any]:
25
+ """
26
+ Serializes this store to a dictionary.
27
+
28
+ :returns: The serialized store as a dictionary.
29
+ """
30
+ ...
31
+
32
+ @classmethod
33
+ def from_dict(cls, data: dict[str, Any]) -> "ChatMessageStore":
34
+ """
35
+ Deserializes the store from a dictionary.
36
+
37
+ :param data: The dictionary to deserialize from.
38
+ :returns: The deserialized store.
39
+ """
40
+ ...
41
+
42
+ def count_messages(self, chat_history_id: str) -> int:
43
+ """
44
+ Returns the number of chat messages stored.
45
+
46
+ :param chat_history_id: The chat history id for which to count messages.
47
+
48
+ :returns: The number of messages.
49
+ """
50
+ ...
51
+
52
+ def write_messages(self, chat_history_id: str, messages: list[ChatMessage]) -> int:
53
+ """
54
+ Writes chat messages to the ChatMessageStore.
55
+
56
+ :param chat_history_id: The chat history id under which to store the messages.
57
+ :param messages: A list of ChatMessages to write.
58
+
59
+ :returns: The number of messages written.
60
+ """
61
+ ...
62
+
63
+ def delete_messages(self, chat_history_id: str) -> None:
64
+ """
65
+ Deletes all stored chat messages.
66
+
67
+ :param chat_history_id: The chat history id from which to delete all messages.
68
+ """
69
+ ...
70
+
71
+ def delete_all_messages(self) -> None:
72
+ """
73
+ Deletes all stored chat messages from all indices.
74
+ """
75
+ ...
76
+
77
+ def retrieve_messages(self, chat_history_id: str, last_k: Optional[int] = None) -> list[ChatMessage]:
78
+ """
79
+ Retrieves chat messages from the ChatMessageStore.
80
+
81
+ :param chat_history_id: The chat history id from which to retrieve messages.
82
+ :param last_k: The number of last messages to retrieve. If None, retrieves all messages.
83
+
84
+ :returns: A list of retrieved ChatMessages.
85
+ """
86
+ ...