haiku.rag-slim 0.16.0__py3-none-any.whl → 0.24.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.

Potentially problematic release.


This version of haiku.rag-slim might be problematic. Click here for more details.

Files changed (94) hide show
  1. haiku/rag/app.py +430 -72
  2. haiku/rag/chunkers/__init__.py +31 -0
  3. haiku/rag/chunkers/base.py +31 -0
  4. haiku/rag/chunkers/docling_local.py +164 -0
  5. haiku/rag/chunkers/docling_serve.py +179 -0
  6. haiku/rag/cli.py +207 -24
  7. haiku/rag/cli_chat.py +489 -0
  8. haiku/rag/client.py +1251 -266
  9. haiku/rag/config/__init__.py +16 -10
  10. haiku/rag/config/loader.py +5 -44
  11. haiku/rag/config/models.py +126 -17
  12. haiku/rag/converters/__init__.py +31 -0
  13. haiku/rag/converters/base.py +63 -0
  14. haiku/rag/converters/docling_local.py +193 -0
  15. haiku/rag/converters/docling_serve.py +229 -0
  16. haiku/rag/converters/text_utils.py +237 -0
  17. haiku/rag/embeddings/__init__.py +123 -24
  18. haiku/rag/embeddings/voyageai.py +175 -20
  19. haiku/rag/graph/__init__.py +0 -11
  20. haiku/rag/graph/agui/__init__.py +8 -2
  21. haiku/rag/graph/agui/cli_renderer.py +1 -1
  22. haiku/rag/graph/agui/emitter.py +219 -31
  23. haiku/rag/graph/agui/server.py +20 -62
  24. haiku/rag/graph/agui/stream.py +1 -2
  25. haiku/rag/graph/research/__init__.py +5 -2
  26. haiku/rag/graph/research/dependencies.py +12 -126
  27. haiku/rag/graph/research/graph.py +390 -135
  28. haiku/rag/graph/research/models.py +91 -112
  29. haiku/rag/graph/research/prompts.py +99 -91
  30. haiku/rag/graph/research/state.py +35 -27
  31. haiku/rag/inspector/__init__.py +8 -0
  32. haiku/rag/inspector/app.py +259 -0
  33. haiku/rag/inspector/widgets/__init__.py +6 -0
  34. haiku/rag/inspector/widgets/chunk_list.py +100 -0
  35. haiku/rag/inspector/widgets/context_modal.py +89 -0
  36. haiku/rag/inspector/widgets/detail_view.py +130 -0
  37. haiku/rag/inspector/widgets/document_list.py +75 -0
  38. haiku/rag/inspector/widgets/info_modal.py +209 -0
  39. haiku/rag/inspector/widgets/search_modal.py +183 -0
  40. haiku/rag/inspector/widgets/visual_modal.py +126 -0
  41. haiku/rag/mcp.py +106 -102
  42. haiku/rag/monitor.py +33 -9
  43. haiku/rag/providers/__init__.py +5 -0
  44. haiku/rag/providers/docling_serve.py +108 -0
  45. haiku/rag/qa/__init__.py +12 -10
  46. haiku/rag/qa/agent.py +43 -61
  47. haiku/rag/qa/prompts.py +35 -57
  48. haiku/rag/reranking/__init__.py +9 -6
  49. haiku/rag/reranking/base.py +1 -1
  50. haiku/rag/reranking/cohere.py +5 -4
  51. haiku/rag/reranking/mxbai.py +5 -2
  52. haiku/rag/reranking/vllm.py +3 -4
  53. haiku/rag/reranking/zeroentropy.py +6 -5
  54. haiku/rag/store/__init__.py +2 -1
  55. haiku/rag/store/engine.py +242 -42
  56. haiku/rag/store/exceptions.py +4 -0
  57. haiku/rag/store/models/__init__.py +8 -2
  58. haiku/rag/store/models/chunk.py +190 -0
  59. haiku/rag/store/models/document.py +46 -0
  60. haiku/rag/store/repositories/chunk.py +141 -121
  61. haiku/rag/store/repositories/document.py +25 -84
  62. haiku/rag/store/repositories/settings.py +11 -14
  63. haiku/rag/store/upgrades/__init__.py +19 -3
  64. haiku/rag/store/upgrades/v0_10_1.py +1 -1
  65. haiku/rag/store/upgrades/v0_19_6.py +65 -0
  66. haiku/rag/store/upgrades/v0_20_0.py +68 -0
  67. haiku/rag/store/upgrades/v0_23_1.py +100 -0
  68. haiku/rag/store/upgrades/v0_9_3.py +3 -3
  69. haiku/rag/utils.py +371 -146
  70. {haiku_rag_slim-0.16.0.dist-info → haiku_rag_slim-0.24.0.dist-info}/METADATA +15 -12
  71. haiku_rag_slim-0.24.0.dist-info/RECORD +78 -0
  72. {haiku_rag_slim-0.16.0.dist-info → haiku_rag_slim-0.24.0.dist-info}/WHEEL +1 -1
  73. haiku/rag/chunker.py +0 -65
  74. haiku/rag/embeddings/base.py +0 -25
  75. haiku/rag/embeddings/ollama.py +0 -28
  76. haiku/rag/embeddings/openai.py +0 -26
  77. haiku/rag/embeddings/vllm.py +0 -29
  78. haiku/rag/graph/agui/events.py +0 -254
  79. haiku/rag/graph/common/__init__.py +0 -5
  80. haiku/rag/graph/common/models.py +0 -42
  81. haiku/rag/graph/common/nodes.py +0 -265
  82. haiku/rag/graph/common/prompts.py +0 -46
  83. haiku/rag/graph/common/utils.py +0 -44
  84. haiku/rag/graph/deep_qa/__init__.py +0 -1
  85. haiku/rag/graph/deep_qa/dependencies.py +0 -27
  86. haiku/rag/graph/deep_qa/graph.py +0 -243
  87. haiku/rag/graph/deep_qa/models.py +0 -20
  88. haiku/rag/graph/deep_qa/prompts.py +0 -59
  89. haiku/rag/graph/deep_qa/state.py +0 -56
  90. haiku/rag/graph/research/common.py +0 -87
  91. haiku/rag/reader.py +0 -135
  92. haiku_rag_slim-0.16.0.dist-info/RECORD +0 -71
  93. {haiku_rag_slim-0.16.0.dist-info → haiku_rag_slim-0.24.0.dist-info}/entry_points.txt +0 -0
  94. {haiku_rag_slim-0.16.0.dist-info → haiku_rag_slim-0.24.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,78 @@
1
+ haiku/rag/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ haiku/rag/app.py,sha256=2qlhInl44ht6A91rGbelJ37try05_cClGBmuavfVzvs,35660
3
+ haiku/rag/cli.py,sha256=o2eraDHEapSMMuV9rJbYwj58lW1Gm4WygKUMUXtU-js,17752
4
+ haiku/rag/cli_chat.py,sha256=CFKqsI2Ppq-BM8VYl-MeiVDW79d06JiPO8lTFbJPeTY,19662
5
+ haiku/rag/client.py,sha256=CVAJuLlYIKzcm_aVqCc-xSY4s5r01iUKz2rSyT7Nq0g,65286
6
+ haiku/rag/logging.py,sha256=dm65AwADpcQsH5OAPtRA-4hsw0w5DK-sGOvzYkj6jzw,1720
7
+ haiku/rag/mcp.py,sha256=0lkE76fKlqRLFy2Yrvw-NHepKfnjNKNbDTmPVeqWaeo,9219
8
+ haiku/rag/monitor.py,sha256=KNN05YFwCXotgRTN6AMfOZLyqfLyfbrMMe5v8nVubAA,8005
9
+ haiku/rag/utils.py,sha256=_wgx60F_IFqlMT2E9iL6qpHtdwIghCRwRL9Jy0G3xO8,14063
10
+ haiku/rag/chunkers/__init__.py,sha256=V1eMI6bGEDOQxLj5hGE9LbJGQK0Vg8xU-_D3uI7Gwac,984
11
+ haiku/rag/chunkers/base.py,sha256=LONA653zBZ9dkfY6WVNaDY56u5pZU4QL_Ei7MHOHBec,924
12
+ haiku/rag/chunkers/docling_local.py,sha256=ycBV6YlKUPOqQM9FXs2n6oQ5KjEFKPDJJ8uI7fvC8tg,6469
13
+ haiku/rag/chunkers/docling_serve.py,sha256=pOFSRXGc_pH19Qu67XcSQ4nIn_wWb0enXq_B0eaD3K0,6358
14
+ haiku/rag/config/__init__.py,sha256=rDIHz0tRLgoBESPFfpf02826_2X11Cl5TKVtv4fHBIg,1780
15
+ haiku/rag/config/loader.py,sha256=YX2sq2_sn5GLQlmnbxugmF46RK2sBVGYjEHsgSNHdZ0,1564
16
+ haiku/rag/config/models.py,sha256=rQ0wJaxWcaCYhK4BFAMgKwsQHfnv_ikFI-8M1hmropc,6097
17
+ haiku/rag/converters/__init__.py,sha256=w3YXOO0cw175CRXN4y5LseUXZjgh_gZmgMjK0jj4hlQ,1033
18
+ haiku/rag/converters/base.py,sha256=PWPW2KmPqhOeHs6rFjeSKpz9l4lq0TwT6yVTyKt7fP0,1880
19
+ haiku/rag/converters/docling_local.py,sha256=5qMpEVqje_GCSApezHCqd1X-rKgJX6LQfciQvUdowik,6830
20
+ haiku/rag/converters/docling_serve.py,sha256=pWojTRTqqkeBhnP71INYo7_lu_OwJUcGpslF9yntAKg,8220
21
+ haiku/rag/converters/text_utils.py,sha256=G_7YSSxlAYT9UNdxwFXrrxstKTsL2QAtDZ60V-v32wk,7016
22
+ haiku/rag/embeddings/__init__.py,sha256=jFfLesylVjoZk3SWonUsmMnd_Qc1Xgxc30J5ttFGTRs,4896
23
+ haiku/rag/embeddings/voyageai.py,sha256=5QtujhGT-kPh9HmALvxTj9Bqq0OXFlmZXfDlE2UQUWU,6029
24
+ haiku/rag/graph/__init__.py,sha256=DJkmRj_MsoscV-dEtztRwf9kNUEa-5s174JlnfvNk_s,320
25
+ haiku/rag/graph/agui/__init__.py,sha256=qjsGCNYgWGTTwjD0oIMomIkiKt_q_UeqmgZFaOfttpM,1472
26
+ haiku/rag/graph/agui/cli_renderer.py,sha256=jK_FUj17y2ArBFGNAItiu3ItPWII5FxXeDn7FprZZxw,5188
27
+ haiku/rag/graph/agui/emitter.py,sha256=aybeCL85fRuRArJ1woUQ0wF4FJlkskyHHvZKL_k5I40,12148
28
+ haiku/rag/graph/agui/server.py,sha256=njBVWz7GbKb55c4R0BDOWVpOWVRxM7VIW8wvIXTA3x0,8511
29
+ haiku/rag/graph/agui/state.py,sha256=LkuuAY9w32pc0kkXkLJvyNGC0JzhXn05IfIVZzCXAv0,965
30
+ haiku/rag/graph/agui/stream.py,sha256=t2_Y5KCs-HQ-XCQ2J475JJjN7hvNJXylz_hyA_s_DY4,2654
31
+ haiku/rag/graph/research/__init__.py,sha256=hLpyshx6yhTd7QHsg142PRAoSB2lZ8td1A5Vj9ArV_I,196
32
+ haiku/rag/graph/research/dependencies.py,sha256=n8nbim6ZsicjAmBO7OzQHqIsmObYPdAQKFmubdRg9hM,1250
33
+ haiku/rag/graph/research/graph.py,sha256=X5iJGfEBThAEklLwPu5P4mERLgH8Cpd-MPw_FTalowE,20622
34
+ haiku/rag/graph/research/models.py,sha256=TnR6s1ITcFKUzzxWVfuFLBEhVmm6nIV9A2ch6x6TBqQ,4506
35
+ haiku/rag/graph/research/prompts.py,sha256=Y_X6sf66wB0P9TV_86PB2zuBDi2e9zKdq24r1DLJZKA,5071
36
+ haiku/rag/graph/research/state.py,sha256=nsOAwwqtgt8kCOisRbop9GpD2JDyhWtDI-wSJcTxEJo,3274
37
+ haiku/rag/inspector/__init__.py,sha256=39qX_LMtypITucYi_9gdKarGRH2wG4vK0iAt208AKy8,285
38
+ haiku/rag/inspector/app.py,sha256=HiCvBVLnDG4iwrop80ykYkWyNAzYgoH3voLPuVuGSh4,8075
39
+ haiku/rag/inspector/widgets/__init__.py,sha256=XX2Ec-MOgJ9juzs0IfShkjFno_17V0ovpK8s37mqQNE,344
40
+ haiku/rag/inspector/widgets/chunk_list.py,sha256=JJmGQ1emPsOWkwP5PjdCtquIZAfJmu4PxrTAdcAZ5pc,3391
41
+ haiku/rag/inspector/widgets/context_modal.py,sha256=Ywx-eZRq6Qb1hN78Ni-JBamYeVfy8BHWOE91MWnv57s,2645
42
+ haiku/rag/inspector/widgets/detail_view.py,sha256=w8h8WSAN4GpGYOq_stga1YhCQqSx2p-iFO4vLHaoPI4,5074
43
+ haiku/rag/inspector/widgets/document_list.py,sha256=K5P0Y2qUl0mh-psUQzbJJXSitlZrHqtT9WOIcw7mABw,2853
44
+ haiku/rag/inspector/widgets/info_modal.py,sha256=UJ_KHRVcPWD5FR9cr7De2tTIU-qMsCwCYm0xaHuFesM,7156
45
+ haiku/rag/inspector/widgets/search_modal.py,sha256=dYAxCvwdKc3cHLjh4hI5ROQt0nS9mFLzz_1UPV9Shh0,6376
46
+ haiku/rag/inspector/widgets/visual_modal.py,sha256=Pk_3cDIDHE_6_PBxV5MPtY9zhi9f7ODnhZNO4QJnjUQ,3959
47
+ haiku/rag/providers/__init__.py,sha256=Tih4mcHM6bFe1R-fZvvb9KSVennxVX7mb44NrNERNQw,146
48
+ haiku/rag/providers/docling_serve.py,sha256=cT1J3Xo-BW0_lZwHSNeL14wjCJ4TTf9s3H0qBkNkmN0,3834
49
+ haiku/rag/qa/__init__.py,sha256=4E7wyeN6mxyJpKnNsO2Hr0aoK4LqSoaEUBK4sLU4QGs,1112
50
+ haiku/rag/qa/agent.py,sha256=BOon9aRo-5Vs5yCKVSnY1slMiEvXmiaH8VTi0fwVHJk,2698
51
+ haiku/rag/qa/prompts.py,sha256=Q6Pxf_obroiX6aWGvf9qjD__2KFy77_b_XrqCZpI8WQ,1403
52
+ haiku/rag/reranking/__init__.py,sha256=03LKxmcd6Qt03o7yfNtEj1kDLKkmGZv9cQDQdohGm54,2223
53
+ haiku/rag/reranking/base.py,sha256=nwrlGzNkdBg2WVBzPMsrvqGYQPmjwPrOvfPs9KyydVI,456
54
+ haiku/rag/reranking/cohere.py,sha256=KntIQPIHDxa3WlFgx0ETvItirRVw_RnJehFA2ZHvLSE,1130
55
+ haiku/rag/reranking/mxbai.py,sha256=XVIyMHTXHlDsgvml3J1uvm7wIggA2E-0E8ATt7p-PfY,1042
56
+ haiku/rag/reranking/vllm.py,sha256=J-b9S0l3at9H_DwTZ0BkwVRgwVb-D62kunQyQBh2nRE,1459
57
+ haiku/rag/reranking/zeroentropy.py,sha256=bT4_KQd8aksPiyX8wjqdMerPoME-223lCRb1BoxfYvY,1995
58
+ haiku/rag/store/__init__.py,sha256=ixTDcjtFZ1MCqB9CIM1P9c9K-5mlc9uRtvD3ekZCn0E,159
59
+ haiku/rag/store/engine.py,sha256=wcwmxmHBdO4vHXAPpsd3lOtFLL5O1qmycIp37zqhl7w,19129
60
+ haiku/rag/store/exceptions.py,sha256=l7wxxI3CsXTkhRwYZSwH5nXhTTGO2jCg3mRqzG0pPzI,117
61
+ haiku/rag/store/models/__init__.py,sha256=aUgKHt3XYVwqVmiAaW4z2u8sBOrP9mnqTZXxq0zHCHE,202
62
+ haiku/rag/store/models/chunk.py,sha256=n9lCaEtY9B2S8pGW9PdX_c-SSmZvADY6Qprqu-u68Bc,6557
63
+ haiku/rag/store/models/document.py,sha256=MGP2ai9wOQ53vWRTlw6FGAyg--GlVFBj8E0e828qEIE,2045
64
+ haiku/rag/store/repositories/__init__.py,sha256=Olv5dLfBQINRV3HrsfUpjzkZ7Qm7goEYyMNykgo_DaY,291
65
+ haiku/rag/store/repositories/chunk.py,sha256=htGEM5te7ToKQugtz1RzJPP8W-8SY7HEIo-iug834c4,16757
66
+ haiku/rag/store/repositories/document.py,sha256=SsxwdcPvrRNOvJJadxazYn5GyV8pvm4-On8NnodTizY,6588
67
+ haiku/rag/store/repositories/settings.py,sha256=lmk6Fk0abmbl2h3xNSGOscCpi6Y7GzYWzpzMIfEuFmk,6015
68
+ haiku/rag/store/upgrades/__init__.py,sha256=or5dxhgVOCHt-w0R5NnTPWmrlDVVPMrLnZ9vaiAedeg,2589
69
+ haiku/rag/store/upgrades/v0_10_1.py,sha256=fzLNz2nQO7BR25x_H6vz20Uyo4MZjhbz3Kz22sYgaAI,1979
70
+ haiku/rag/store/upgrades/v0_19_6.py,sha256=5k__79mdn7u0UmlaGN7w2t74uVhnmScsFz0zCbnoPAU,1907
71
+ haiku/rag/store/upgrades/v0_20_0.py,sha256=yFkZzOh59WSfcsTUsBVqFu-FGBsBvwGP_Y3Dn4BLh04,2267
72
+ haiku/rag/store/upgrades/v0_23_1.py,sha256=ZuMuIZWWnC7_Rq63QB88fTIBbo121JAFjBrjv1wVpyk,2897
73
+ haiku/rag/store/upgrades/v0_9_3.py,sha256=5zsOCeMaB5tHhx5AR8wGtCJGqqzA944sqYzDUPvYa4c,3382
74
+ haiku_rag_slim-0.24.0.dist-info/METADATA,sha256=XZLY786eWEZjVaoUi_90r_1JqnRA4kLFx6I8YZHLhmw,4384
75
+ haiku_rag_slim-0.24.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
76
+ haiku_rag_slim-0.24.0.dist-info/entry_points.txt,sha256=G1U3nAkNd5YDYd4v0tuYFbriz0i-JheCsFuT9kIoGCI,48
77
+ haiku_rag_slim-0.24.0.dist-info/licenses/LICENSE,sha256=eXZrWjSk9PwYFNK9yUczl3oPl95Z4V9UXH7bPN46iPo,1065
78
+ haiku_rag_slim-0.24.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
haiku/rag/chunker.py DELETED
@@ -1,65 +0,0 @@
1
- from typing import ClassVar
2
-
3
- import tiktoken
4
- from docling_core.transforms.chunker.tokenizer.openai import OpenAITokenizer
5
- from docling_core.types.doc.document import DoclingDocument
6
-
7
- from haiku.rag.config import Config
8
-
9
- # Check if docling is available
10
- try:
11
- import docling # noqa: F401
12
-
13
- DOCLING_AVAILABLE = True
14
- except ImportError:
15
- DOCLING_AVAILABLE = False
16
-
17
-
18
- class Chunker:
19
- """A class that chunks text into smaller pieces for embedding and retrieval.
20
-
21
- Uses docling's structure-aware chunking to create semantically meaningful chunks
22
- that respect document boundaries.
23
-
24
- Args:
25
- chunk_size: The maximum size of a chunk in tokens.
26
- """
27
-
28
- encoder: ClassVar[tiktoken.Encoding] = tiktoken.encoding_for_model("gpt-4o")
29
-
30
- def __init__(
31
- self,
32
- chunk_size: int = Config.processing.chunk_size,
33
- ):
34
- if not DOCLING_AVAILABLE:
35
- raise ImportError(
36
- "Docling is required for chunking. "
37
- "Install with: pip install haiku.rag-slim[docling]"
38
- )
39
- from docling.chunking import HybridChunker # type: ignore
40
-
41
- self.chunk_size = chunk_size
42
- tokenizer = OpenAITokenizer(
43
- tokenizer=tiktoken.encoding_for_model("gpt-4o"), max_tokens=chunk_size
44
- )
45
-
46
- self.chunker = HybridChunker(tokenizer=tokenizer) # type: ignore
47
-
48
- async def chunk(self, document: DoclingDocument) -> list[str]:
49
- """Split the document into chunks using docling's structure-aware chunking.
50
-
51
- Args:
52
- document: The DoclingDocument to be split into chunks.
53
-
54
- Returns:
55
- A list of text chunks with semantic boundaries.
56
- """
57
- if document is None:
58
- return []
59
-
60
- # Chunk using docling's hybrid chunker
61
- chunks = list(self.chunker.chunk(document))
62
- return [self.chunker.contextualize(chunk) for chunk in chunks]
63
-
64
-
65
- chunker = Chunker()
@@ -1,25 +0,0 @@
1
- from typing import overload
2
-
3
- from haiku.rag.config import AppConfig, Config
4
-
5
-
6
- class EmbedderBase:
7
- _model: str = Config.embeddings.model
8
- _vector_dim: int = Config.embeddings.vector_dim
9
- _config: AppConfig = Config
10
-
11
- def __init__(self, model: str, vector_dim: int, config: AppConfig = Config):
12
- self._model = model
13
- self._vector_dim = vector_dim
14
- self._config = config
15
-
16
- @overload
17
- async def embed(self, text: str) -> list[float]: ...
18
-
19
- @overload
20
- async def embed(self, text: list[str]) -> list[list[float]]: ...
21
-
22
- async def embed(self, text: str | list[str]) -> list[float] | list[list[float]]:
23
- raise NotImplementedError(
24
- "Embedder is an abstract class. Please implement the embed method in a subclass."
25
- )
@@ -1,28 +0,0 @@
1
- from typing import overload
2
-
3
- from openai import AsyncOpenAI
4
-
5
- from haiku.rag.embeddings.base import EmbedderBase
6
-
7
-
8
- class Embedder(EmbedderBase):
9
- @overload
10
- async def embed(self, text: str) -> list[float]: ...
11
-
12
- @overload
13
- async def embed(self, text: list[str]) -> list[list[float]]: ...
14
-
15
- async def embed(self, text: str | list[str]) -> list[float] | list[list[float]]:
16
- client = AsyncOpenAI(
17
- base_url=f"{self._config.providers.ollama.base_url}/v1", api_key="dummy"
18
- )
19
- if not text:
20
- return []
21
- response = await client.embeddings.create(
22
- model=self._model,
23
- input=text,
24
- )
25
- if isinstance(text, str):
26
- return response.data[0].embedding
27
- else:
28
- return [item.embedding for item in response.data]
@@ -1,26 +0,0 @@
1
- from typing import overload
2
-
3
- from openai import AsyncOpenAI
4
-
5
- from haiku.rag.embeddings.base import EmbedderBase
6
-
7
-
8
- class Embedder(EmbedderBase):
9
- @overload
10
- async def embed(self, text: str) -> list[float]: ...
11
-
12
- @overload
13
- async def embed(self, text: list[str]) -> list[list[float]]: ...
14
-
15
- async def embed(self, text: str | list[str]) -> list[float] | list[list[float]]:
16
- client = AsyncOpenAI()
17
- if not text:
18
- return []
19
- response = await client.embeddings.create(
20
- model=self._model,
21
- input=text,
22
- )
23
- if isinstance(text, str):
24
- return response.data[0].embedding
25
- else:
26
- return [item.embedding for item in response.data]
@@ -1,29 +0,0 @@
1
- from typing import overload
2
-
3
- from openai import AsyncOpenAI
4
-
5
- from haiku.rag.embeddings.base import EmbedderBase
6
-
7
-
8
- class Embedder(EmbedderBase):
9
- @overload
10
- async def embed(self, text: str) -> list[float]: ...
11
-
12
- @overload
13
- async def embed(self, text: list[str]) -> list[list[float]]: ...
14
-
15
- async def embed(self, text: str | list[str]) -> list[float] | list[list[float]]:
16
- client = AsyncOpenAI(
17
- base_url=f"{self._config.providers.vllm.embeddings_base_url}/v1",
18
- api_key="dummy",
19
- )
20
- if not text:
21
- return []
22
- response = await client.embeddings.create(
23
- model=self._model,
24
- input=text,
25
- )
26
- if isinstance(text, str):
27
- return response.data[0].embedding
28
- else:
29
- return [item.embedding for item in response.data]
@@ -1,254 +0,0 @@
1
- """Generic AG-UI event creation utilities for any graph."""
2
-
3
- from typing import Any
4
- from uuid import uuid4
5
-
6
- from pydantic import BaseModel
7
-
8
- from haiku.rag.graph.agui.state import compute_state_delta
9
-
10
- # Type aliases for AG-UI events (actual types from ag_ui.core will be used at runtime)
11
- AGUIEvent = dict[str, Any]
12
-
13
-
14
- def emit_run_started(
15
- thread_id: str, run_id: str, input_data: str | None = None
16
- ) -> dict[str, Any]:
17
- """Create a RunStarted event.
18
-
19
- Args:
20
- thread_id: Unique identifier for the conversation thread
21
- run_id: Unique identifier for this run
22
- input_data: Optional input that started the run
23
-
24
- Returns:
25
- RunStarted event dict
26
- """
27
- event: dict[str, Any] = {
28
- "type": "RUN_STARTED",
29
- "threadId": thread_id,
30
- "runId": run_id,
31
- }
32
- if input_data:
33
- event["input"] = input_data
34
- return event
35
-
36
-
37
- def emit_run_finished(thread_id: str, run_id: str, result: Any) -> dict[str, Any]:
38
- """Create a RunFinished event.
39
-
40
- Args:
41
- thread_id: Unique identifier for the conversation thread
42
- run_id: Unique identifier for this run
43
- result: The final result of the run
44
-
45
- Returns:
46
- RunFinished event dict
47
- """
48
- # Convert result to dict if it's a Pydantic model
49
- if hasattr(result, "model_dump"):
50
- result = result.model_dump()
51
-
52
- return {
53
- "type": "RUN_FINISHED",
54
- "threadId": thread_id,
55
- "runId": run_id,
56
- "result": result,
57
- }
58
-
59
-
60
- def emit_run_error(message: str, code: str | None = None) -> dict[str, Any]:
61
- """Create a RunError event.
62
-
63
- Args:
64
- message: Error message
65
- code: Optional error code
66
-
67
- Returns:
68
- RunError event dict
69
- """
70
- event: dict[str, Any] = {
71
- "type": "RUN_ERROR",
72
- "message": message,
73
- }
74
- if code:
75
- event["code"] = code
76
- return event
77
-
78
-
79
- def emit_step_started(step_name: str) -> dict[str, Any]:
80
- """Create a StepStarted event.
81
-
82
- Args:
83
- step_name: Name of the step being started
84
-
85
- Returns:
86
- StepStarted event dict
87
- """
88
- return {
89
- "type": "STEP_STARTED",
90
- "stepName": step_name,
91
- }
92
-
93
-
94
- def emit_step_finished(step_name: str) -> dict[str, Any]:
95
- """Create a StepFinished event.
96
-
97
- Args:
98
- step_name: Name of the step that finished
99
-
100
- Returns:
101
- StepFinished event dict
102
- """
103
- return {
104
- "type": "STEP_FINISHED",
105
- "stepName": step_name,
106
- }
107
-
108
-
109
- def emit_text_message(content: str, role: str = "assistant") -> dict[str, Any]:
110
- """Create a TextMessageChunk event (convenience wrapper).
111
-
112
- This creates a complete text message in one event.
113
-
114
- Args:
115
- content: The message content
116
- role: The role of the sender (default: assistant)
117
-
118
- Returns:
119
- TextMessageChunk event dict
120
- """
121
- message_id = str(uuid4())
122
- return {
123
- "type": "TEXT_MESSAGE_CHUNK",
124
- "messageId": message_id,
125
- "role": role,
126
- "delta": content,
127
- }
128
-
129
-
130
- def emit_text_message_start(message_id: str, role: str = "assistant") -> dict[str, Any]:
131
- """Create a TextMessageStart event.
132
-
133
- Args:
134
- message_id: Unique identifier for this message
135
- role: The role of the sender
136
-
137
- Returns:
138
- TextMessageStart event dict
139
- """
140
- return {
141
- "type": "TEXT_MESSAGE_START",
142
- "messageId": message_id,
143
- "role": role,
144
- }
145
-
146
-
147
- def emit_text_message_content(message_id: str, delta: str) -> dict[str, Any]:
148
- """Create a TextMessageContent event.
149
-
150
- Args:
151
- message_id: Identifier for the message being streamed
152
- delta: Content chunk to append
153
-
154
- Returns:
155
- TextMessageContent event dict
156
- """
157
- return {
158
- "type": "TEXT_MESSAGE_CONTENT",
159
- "messageId": message_id,
160
- "delta": delta,
161
- }
162
-
163
-
164
- def emit_text_message_end(message_id: str) -> dict[str, Any]:
165
- """Create a TextMessageEnd event.
166
-
167
- Args:
168
- message_id: Identifier for the message being completed
169
-
170
- Returns:
171
- TextMessageEnd event dict
172
- """
173
- return {
174
- "type": "TEXT_MESSAGE_END",
175
- "messageId": message_id,
176
- }
177
-
178
-
179
- def emit_state_snapshot(state: BaseModel) -> dict[str, Any]:
180
- """Create a StateSnapshot event.
181
-
182
- Args:
183
- state: The complete state to snapshot (any Pydantic BaseModel)
184
-
185
- Returns:
186
- StateSnapshot event dict
187
- """
188
- return {
189
- "type": "STATE_SNAPSHOT",
190
- "snapshot": state.model_dump(),
191
- }
192
-
193
-
194
- def emit_state_delta(old_state: BaseModel, new_state: BaseModel) -> dict[str, Any]:
195
- """Create a StateDelta event with JSON Patch operations.
196
-
197
- Args:
198
- old_state: Previous state (any Pydantic BaseModel)
199
- new_state: Current state (same type as old_state)
200
-
201
- Returns:
202
- StateDelta event dict
203
- """
204
- delta = compute_state_delta(old_state, new_state)
205
- return {
206
- "type": "STATE_DELTA",
207
- "delta": delta,
208
- }
209
-
210
-
211
- def emit_activity(
212
- message_id: str,
213
- activity_type: str,
214
- content: str,
215
- ) -> dict[str, Any]:
216
- """Create an ActivitySnapshot event.
217
-
218
- Args:
219
- message_id: Message ID to associate activity with (required)
220
- activity_type: Type of activity (e.g., "planning", "searching")
221
- content: Description of the activity
222
-
223
- Returns:
224
- ActivitySnapshot event dict
225
- """
226
- return {
227
- "type": "ACTIVITY_SNAPSHOT",
228
- "messageId": message_id,
229
- "activityType": activity_type,
230
- "content": content,
231
- }
232
-
233
-
234
- def emit_activity_delta(
235
- message_id: str,
236
- activity_type: str,
237
- patch: list[dict[str, Any]],
238
- ) -> dict[str, Any]:
239
- """Create an ActivityDelta event with JSON Patch operations.
240
-
241
- Args:
242
- message_id: Message ID of the activity being updated
243
- activity_type: Type of activity being updated
244
- patch: JSON Patch operations to apply
245
-
246
- Returns:
247
- ActivityDelta event dict
248
- """
249
- return {
250
- "type": "ACTIVITY_DELTA",
251
- "messageId": message_id,
252
- "activityType": activity_type,
253
- "patch": patch,
254
- }
@@ -1,5 +0,0 @@
1
- """Common utilities for graph implementations."""
2
-
3
- from haiku.rag.graph.common.utils import get_model
4
-
5
- __all__ = ["get_model"]
@@ -1,42 +0,0 @@
1
- """Common models used across different graph implementations."""
2
-
3
- from pydantic import BaseModel, Field, field_validator
4
-
5
-
6
- class ResearchPlan(BaseModel):
7
- """A structured research plan with sub-questions to explore."""
8
-
9
- sub_questions: list[str] = Field(
10
- ...,
11
- description="Specific questions to research, phrased as complete questions",
12
- )
13
-
14
- @field_validator("sub_questions")
15
- @classmethod
16
- def validate_sub_questions(cls, v: list[str]) -> list[str]:
17
- if len(v) < 1:
18
- raise ValueError("Must have at least 1 sub-question")
19
- if len(v) > 12:
20
- raise ValueError("Cannot have more than 12 sub-questions")
21
- return v
22
-
23
-
24
- class SearchAnswer(BaseModel):
25
- """Answer from a search operation with sources."""
26
-
27
- query: str = Field(..., description="The question that was answered")
28
- answer: str = Field(..., description="The comprehensive answer to the question")
29
- context: list[str] = Field(
30
- default_factory=list,
31
- description="Relevant snippets that directly support the answer",
32
- )
33
- sources: list[str] = Field(
34
- default_factory=list,
35
- description="Source URIs or titles that contributed to this answer",
36
- )
37
- confidence: float = Field(
38
- default=1.0,
39
- description="Confidence score for this answer (0-1)",
40
- ge=0.0,
41
- le=1.0,
42
- )