langroid 0.35.1__py3-none-any.whl → 0.36.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.
- langroid/agent/special/doc_chat_agent.py +11 -7
- langroid/parsing/parser.py +5 -3
- langroid/parsing/utils.py +2 -2
- langroid/utils/output/citations.py +32 -12
- langroid/vector_store/__init__.py +11 -0
- langroid/vector_store/base.py +4 -1
- langroid/vector_store/weaviatedb.py +271 -0
- {langroid-0.35.1.dist-info → langroid-0.36.1.dist-info}/METADATA +18 -6
- {langroid-0.35.1.dist-info → langroid-0.36.1.dist-info}/RECORD +11 -10
- {langroid-0.35.1.dist-info → langroid-0.36.1.dist-info}/WHEEL +0 -0
- {langroid-0.35.1.dist-info → langroid-0.36.1.dist-info}/licenses/LICENSE +0 -0
@@ -15,6 +15,7 @@ pip install "langroid[hf-embeddings]"
|
|
15
15
|
"""
|
16
16
|
|
17
17
|
import logging
|
18
|
+
import textwrap
|
18
19
|
from collections import OrderedDict
|
19
20
|
from functools import cache
|
20
21
|
from typing import Any, Callable, Dict, List, Optional, Set, Tuple, no_type_check
|
@@ -81,7 +82,7 @@ You will be given various passages from these documents, and asked to answer que
|
|
81
82
|
about them, or summarize them into coherent answers.
|
82
83
|
"""
|
83
84
|
|
84
|
-
CHUNK_ENRICHMENT_DELIMITER = "<##-##-##>"
|
85
|
+
CHUNK_ENRICHMENT_DELIMITER = "\n<##-##-##>"
|
85
86
|
|
86
87
|
has_sentence_transformers = False
|
87
88
|
try:
|
@@ -810,9 +811,11 @@ class DocChatAgent(ChatAgent):
|
|
810
811
|
return "\n".join(
|
811
812
|
[
|
812
813
|
f"""
|
813
|
-
[{i+1}]
|
814
|
+
-----[EXTRACT #{i+1}]----------
|
814
815
|
{content}
|
815
816
|
{source}
|
817
|
+
-----END OF EXTRACT------------
|
818
|
+
|
816
819
|
"""
|
817
820
|
for i, (content, source) in enumerate(zip(contents, sources))
|
818
821
|
]
|
@@ -949,12 +952,13 @@ class DocChatAgent(ChatAgent):
|
|
949
952
|
continue
|
950
953
|
|
951
954
|
# Combine original content with questions in a structured way
|
952
|
-
combined_content =
|
953
|
-
|
954
|
-
|
955
|
+
combined_content = textwrap.dedent(
|
956
|
+
f"""\
|
957
|
+
{doc.content}
|
955
958
|
{enrichment_config.delimiter}
|
956
959
|
{enrichment}
|
957
|
-
"""
|
960
|
+
"""
|
961
|
+
)
|
958
962
|
|
959
963
|
new_doc = doc.copy(
|
960
964
|
update={
|
@@ -1440,7 +1444,7 @@ class DocChatAgent(ChatAgent):
|
|
1440
1444
|
delimiter = self.config.chunk_enrichment_config.delimiter
|
1441
1445
|
return [
|
1442
1446
|
(
|
1443
|
-
doc.copy(update={"content": doc.content.split(delimiter)[0]
|
1447
|
+
doc.copy(update={"content": doc.content.split(delimiter)[0]})
|
1444
1448
|
if doc.content and getattr(doc.metadata, "has_enrichment", False)
|
1445
1449
|
else doc
|
1446
1450
|
)
|
langroid/parsing/parser.py
CHANGED
@@ -267,9 +267,11 @@ class Parser:
|
|
267
267
|
# Truncate the chunk text at the punctuation mark
|
268
268
|
chunk_text = chunk_text[: last_punctuation + 1]
|
269
269
|
|
270
|
-
#
|
271
|
-
#
|
272
|
-
|
270
|
+
# Replace redundant (3 or more) newlines with 2 newlines to preser
|
271
|
+
# paragraph separation!
|
272
|
+
# But do NOT strip leading/trailing whitespace, to preserve formatting
|
273
|
+
# (e.g. code blocks, or in case we want to stitch chunks back together)
|
274
|
+
chunk_text_to_append = re.sub(r"\n{3,}", "\n\n", chunk_text)
|
273
275
|
|
274
276
|
if len(chunk_text_to_append) > self.config.discard_chunk_chars:
|
275
277
|
# Append the chunk text to the list of chunks
|
langroid/parsing/utils.py
CHANGED
@@ -310,9 +310,9 @@ def extract_numbered_segments(s: str, specs: str) -> str:
|
|
310
310
|
]
|
311
311
|
|
312
312
|
# If we extracted any segments from this paragraph,
|
313
|
-
# join them and append to results
|
313
|
+
# join them with ellipsis (...) and append to results.
|
314
314
|
if extracted_segments:
|
315
|
-
extracted_paragraphs.append("
|
315
|
+
extracted_paragraphs.append("...".join(extracted_segments))
|
316
316
|
|
317
317
|
return "\n\n".join(extracted_paragraphs)
|
318
318
|
|
@@ -17,25 +17,45 @@ def extract_markdown_references(md_string: str) -> list[int]:
|
|
17
17
|
return sorted(set(int(match) for match in matches))
|
18
18
|
|
19
19
|
|
20
|
-
def format_footnote_text(content: str, width: int =
|
20
|
+
def format_footnote_text(content: str, width: int = 0) -> str:
|
21
21
|
"""
|
22
|
-
Formats the content
|
23
|
-
|
24
|
-
|
25
|
-
lines
|
22
|
+
Formats the content so that each original line is individually processed.
|
23
|
+
- If width=0, no wrapping is done (lines remain as is).
|
24
|
+
- If width>0, lines are wrapped to that width.
|
25
|
+
- Blank lines remain blank (with indentation).
|
26
|
+
- Everything is indented by 4 spaces (for markdown footnotes).
|
26
27
|
|
27
28
|
Args:
|
28
29
|
content (str): The text of the footnote to be formatted.
|
29
|
-
width (int): Maximum width of the text lines.
|
30
|
+
width (int): Maximum width of the text lines. If 0, lines are not wrapped.
|
30
31
|
|
31
32
|
Returns:
|
32
33
|
str: Properly formatted markdown footnote text.
|
33
34
|
"""
|
34
35
|
import textwrap
|
35
36
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
indent = " " # 4 spaces for markdown footnotes
|
38
|
+
lines = content.split("\n") # keep original line structure
|
39
|
+
|
40
|
+
output_lines = []
|
41
|
+
for line in lines:
|
42
|
+
# If the line is empty (or just spaces), keep it blank (but indented)
|
43
|
+
if not line.strip():
|
44
|
+
output_lines.append(indent)
|
45
|
+
continue
|
46
|
+
|
47
|
+
if width > 0:
|
48
|
+
# Wrap each non-empty line to the specified width
|
49
|
+
wrapped = textwrap.wrap(line, width=width)
|
50
|
+
if not wrapped:
|
51
|
+
# If textwrap gives nothing, add a blank (indented) line
|
52
|
+
output_lines.append(indent)
|
53
|
+
else:
|
54
|
+
for subline in wrapped:
|
55
|
+
output_lines.append(indent + subline)
|
56
|
+
else:
|
57
|
+
# No wrapping: just indent the original line
|
58
|
+
output_lines.append(indent + line)
|
59
|
+
|
60
|
+
# Join them with newline so we preserve the paragraph/blank line structure
|
61
|
+
return "\n".join(output_lines)
|
@@ -48,3 +48,14 @@ try:
|
|
48
48
|
__all__.extend(["chromadb", "ChromaDBConfig", "ChromaDB"])
|
49
49
|
except ImportError:
|
50
50
|
pass
|
51
|
+
|
52
|
+
try:
|
53
|
+
from . import weaviatedb
|
54
|
+
from .weaviatedb import WeaviateDBConfig, WeaviateDB
|
55
|
+
|
56
|
+
weaviatedb
|
57
|
+
WeaviateDB
|
58
|
+
WeaviateDBConfig
|
59
|
+
__all__.extend(["weaviatedb", "WeaviateDB", "WeaviateDBConfig"])
|
60
|
+
except ImportError:
|
61
|
+
pass
|
langroid/vector_store/base.py
CHANGED
@@ -59,6 +59,7 @@ class VectorStore(ABC):
|
|
59
59
|
from langroid.vector_store.meilisearch import MeiliSearch, MeiliSearchConfig
|
60
60
|
from langroid.vector_store.momento import MomentoVI, MomentoVIConfig
|
61
61
|
from langroid.vector_store.qdrantdb import QdrantDB, QdrantDBConfig
|
62
|
+
from langroid.vector_store.weaviatedb import WeaviateDB, WeaviateDBConfig
|
62
63
|
|
63
64
|
if isinstance(config, QdrantDBConfig):
|
64
65
|
return QdrantDB(config)
|
@@ -70,6 +71,8 @@ class VectorStore(ABC):
|
|
70
71
|
return LanceDB(config)
|
71
72
|
elif isinstance(config, MeiliSearchConfig):
|
72
73
|
return MeiliSearch(config)
|
74
|
+
elif isinstance(config, WeaviateDBConfig):
|
75
|
+
return WeaviateDB(config)
|
73
76
|
|
74
77
|
else:
|
75
78
|
logger.warning(
|
@@ -261,7 +264,7 @@ class VectorStore(ABC):
|
|
261
264
|
metadata = copy.deepcopy(id2metadata[w[0]])
|
262
265
|
metadata.window_ids = w
|
263
266
|
document = Document(
|
264
|
-
content="
|
267
|
+
content="".join([d.content for d in self.get_documents_by_ids(w)]),
|
265
268
|
metadata=metadata,
|
266
269
|
)
|
267
270
|
# make a fresh id since content is in general different
|
@@ -0,0 +1,271 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
import re
|
4
|
+
from typing import Any, List, Optional, Sequence, Tuple
|
5
|
+
|
6
|
+
from dotenv import load_dotenv
|
7
|
+
|
8
|
+
from langroid.embedding_models.base import (
|
9
|
+
EmbeddingModelsConfig,
|
10
|
+
)
|
11
|
+
from langroid.embedding_models.models import OpenAIEmbeddingsConfig
|
12
|
+
from langroid.exceptions import LangroidImportError
|
13
|
+
from langroid.mytypes import DocMetaData, Document, EmbeddingFunction
|
14
|
+
from langroid.utils.configuration import settings
|
15
|
+
from langroid.vector_store.base import VectorStore, VectorStoreConfig
|
16
|
+
|
17
|
+
logger = logging.getLogger(__name__)
|
18
|
+
try:
|
19
|
+
import weaviate
|
20
|
+
from weaviate.classes.config import (
|
21
|
+
Configure,
|
22
|
+
VectorDistances,
|
23
|
+
)
|
24
|
+
from weaviate.classes.init import Auth
|
25
|
+
from weaviate.classes.query import Filter, MetadataQuery
|
26
|
+
from weaviate.util import generate_uuid5, get_valid_uuid
|
27
|
+
except ImportError:
|
28
|
+
raise LangroidImportError("weaviate", "weaviate")
|
29
|
+
|
30
|
+
|
31
|
+
class WeaviateDBConfig(VectorStoreConfig):
|
32
|
+
collection_name: str | None = "temp"
|
33
|
+
embedding: EmbeddingModelsConfig = OpenAIEmbeddingsConfig()
|
34
|
+
distance: str = VectorDistances.COSINE
|
35
|
+
|
36
|
+
|
37
|
+
class WeaviateDB(VectorStore):
|
38
|
+
def __init__(self, config: WeaviateDBConfig = WeaviateDBConfig()):
|
39
|
+
super().__init__(config)
|
40
|
+
self.config: WeaviateDBConfig = config
|
41
|
+
self.embedding_fn: EmbeddingFunction = self.embedding_model.embedding_fn()
|
42
|
+
self.embedding_dim = self.embedding_model.embedding_dims
|
43
|
+
load_dotenv()
|
44
|
+
key = os.getenv("WEAVIATE_API_KEY")
|
45
|
+
url = os.getenv("WEAVIATE_API_URL")
|
46
|
+
if None in [key, url]:
|
47
|
+
logger.warning(
|
48
|
+
"""WEAVIATE_API_KEY, WEAVIATE_API_URL env variable must be set to use
|
49
|
+
WeaviateDB in cloud mode. Please set these values
|
50
|
+
in your .env file.
|
51
|
+
"""
|
52
|
+
)
|
53
|
+
self.client = weaviate.connect_to_weaviate_cloud(
|
54
|
+
cluster_url=url,
|
55
|
+
auth_credentials=Auth.api_key(key),
|
56
|
+
)
|
57
|
+
if config.collection_name is not None:
|
58
|
+
WeaviateDB.validate_and_format_collection_name(config.collection_name)
|
59
|
+
|
60
|
+
def clear_empty_collections(self) -> int:
|
61
|
+
colls = self.client.collections.list_all()
|
62
|
+
n_deletes = 0
|
63
|
+
for coll_name, _ in colls.items():
|
64
|
+
val = self.client.collections.get(coll_name)
|
65
|
+
if len(val) == 0:
|
66
|
+
n_deletes += 1
|
67
|
+
self.client.collections.delete(coll_name)
|
68
|
+
return n_deletes
|
69
|
+
|
70
|
+
def list_collections(self, empty: bool = False) -> List[str]:
|
71
|
+
colls = self.client.collections.list_all()
|
72
|
+
if empty:
|
73
|
+
return list(colls.keys())
|
74
|
+
non_empty_colls = [
|
75
|
+
coll_name
|
76
|
+
for coll_name in colls.keys()
|
77
|
+
if len(self.client.collections.get(coll_name)) > 0
|
78
|
+
]
|
79
|
+
|
80
|
+
return non_empty_colls
|
81
|
+
|
82
|
+
def clear_all_collections(self, really: bool = False, prefix: str = "") -> int:
|
83
|
+
if not really:
|
84
|
+
logger.warning(
|
85
|
+
"Not really deleting all collections ,set really=True to confirm"
|
86
|
+
)
|
87
|
+
return 0
|
88
|
+
coll_names = [
|
89
|
+
c for c in self.list_collections(empty=True) if c.startswith(prefix)
|
90
|
+
]
|
91
|
+
if len(coll_names) == 0:
|
92
|
+
logger.warning(f"No collections found with prefix {prefix}")
|
93
|
+
return 0
|
94
|
+
n_empty_deletes = 0
|
95
|
+
n_non_empty_deletes = 0
|
96
|
+
for name in coll_names:
|
97
|
+
info = self.client.collections.get(name)
|
98
|
+
points_count = len(info)
|
99
|
+
|
100
|
+
n_empty_deletes += points_count == 0
|
101
|
+
n_non_empty_deletes += points_count > 0
|
102
|
+
self.client.collections.delete(name)
|
103
|
+
logger.warning(
|
104
|
+
f"""
|
105
|
+
Deleted {n_empty_deletes} empty collections and
|
106
|
+
{n_non_empty_deletes} non-empty collections.
|
107
|
+
"""
|
108
|
+
)
|
109
|
+
return n_empty_deletes + n_non_empty_deletes
|
110
|
+
|
111
|
+
def delete_collection(self, collection_name: str) -> None:
|
112
|
+
self.client.collections.delete(name=collection_name)
|
113
|
+
|
114
|
+
def create_collection(self, collection_name: str, replace: bool = False) -> None:
|
115
|
+
collection_name = WeaviateDB.validate_and_format_collection_name(
|
116
|
+
collection_name
|
117
|
+
)
|
118
|
+
self.config.collection_name = collection_name
|
119
|
+
if self.client.collections.exists(name=collection_name):
|
120
|
+
coll = self.client.collections.get(name=collection_name)
|
121
|
+
if len(coll) > 0:
|
122
|
+
logger.warning(f"Non-empty Collection {collection_name} already exists")
|
123
|
+
if not replace:
|
124
|
+
logger.warning("Not replacing collection")
|
125
|
+
return
|
126
|
+
else:
|
127
|
+
logger.warning("Recreating fresh collection")
|
128
|
+
self.client.collections.delete(name=collection_name)
|
129
|
+
|
130
|
+
vector_index_config = Configure.VectorIndex.hnsw(
|
131
|
+
distance_metric=VectorDistances.COSINE,
|
132
|
+
)
|
133
|
+
if self.config.embedding == OpenAIEmbeddingsConfig:
|
134
|
+
vectorizer_config = Configure.Vectorizer.text2vec_openai(
|
135
|
+
model=self.embedding_model
|
136
|
+
)
|
137
|
+
else:
|
138
|
+
vectorizer_config = None
|
139
|
+
|
140
|
+
collection_info = self.client.collections.create(
|
141
|
+
name=collection_name,
|
142
|
+
vector_index_config=vector_index_config,
|
143
|
+
vectorizer_config=vectorizer_config,
|
144
|
+
)
|
145
|
+
collection_info = self.client.collections.get(name=collection_name)
|
146
|
+
assert len(collection_info) in [0, None]
|
147
|
+
if settings.debug:
|
148
|
+
level = logger.getEffectiveLevel()
|
149
|
+
logger.setLevel(logging.INFO)
|
150
|
+
logger.info(collection_info)
|
151
|
+
logger.setLevel(level)
|
152
|
+
|
153
|
+
def add_documents(self, documents: Sequence[Document]) -> None:
|
154
|
+
super().maybe_add_ids(documents)
|
155
|
+
colls = self.list_collections(empty=True)
|
156
|
+
for doc in documents:
|
157
|
+
doc.metadata.id = str(self._create_valid_uuid_id(doc.metadata.id))
|
158
|
+
if len(documents) == 0:
|
159
|
+
return
|
160
|
+
|
161
|
+
document_dicts = [doc.dict() for doc in documents]
|
162
|
+
embedding_vecs = self.embedding_fn([doc.content for doc in documents])
|
163
|
+
if self.config.collection_name is None:
|
164
|
+
raise ValueError("No collection name set, cannot ingest docs")
|
165
|
+
if self.config.collection_name not in colls:
|
166
|
+
self.create_collection(self.config.collection_name, replace=True)
|
167
|
+
coll_name = self.client.collections.get(self.config.collection_name)
|
168
|
+
with coll_name.batch.dynamic() as batch:
|
169
|
+
for i, doc_dict in enumerate(document_dicts):
|
170
|
+
id = doc_dict["metadata"].pop("id", None)
|
171
|
+
batch.add_object(properties=doc_dict, uuid=id, vector=embedding_vecs[i])
|
172
|
+
|
173
|
+
def get_all_documents(self, where: str = "") -> List[Document]:
|
174
|
+
if self.config.collection_name is None:
|
175
|
+
raise ValueError("No collection name set, cannot retrieve docs")
|
176
|
+
# cannot use filter as client does not support json type queries
|
177
|
+
coll = self.client.collections.get(self.config.collection_name)
|
178
|
+
return [self.weaviate_obj_to_doc(item) for item in coll.iterator()]
|
179
|
+
|
180
|
+
def get_documents_by_ids(self, ids: List[str]) -> List[Document]:
|
181
|
+
if self.config.collection_name is None:
|
182
|
+
raise ValueError("No collection name set, cannot retrieve docs")
|
183
|
+
|
184
|
+
docs = []
|
185
|
+
coll_name = self.client.collections.get(self.config.collection_name)
|
186
|
+
|
187
|
+
result = coll_name.query.fetch_objects(
|
188
|
+
filters=Filter.by_property("_id").contains_any(ids), limit=len(coll_name)
|
189
|
+
)
|
190
|
+
|
191
|
+
id_to_doc = {}
|
192
|
+
for item in result.objects:
|
193
|
+
doc = self.weaviate_obj_to_doc(item)
|
194
|
+
id_to_doc[doc.metadata.id] = doc
|
195
|
+
|
196
|
+
# Reconstruct the list of documents in the original order of input ids
|
197
|
+
docs = [id_to_doc[id] for id in ids if id in id_to_doc]
|
198
|
+
|
199
|
+
return docs
|
200
|
+
|
201
|
+
def similar_texts_with_scores(
|
202
|
+
self, text: str, k: int = 1, where: Optional[str] = None
|
203
|
+
) -> List[Tuple[Document, float]]:
|
204
|
+
embedding = self.embedding_fn([text])[0]
|
205
|
+
if self.config.collection_name is None:
|
206
|
+
raise ValueError("No collections name set,cannot search")
|
207
|
+
coll = self.client.collections.get(self.config.collection_name)
|
208
|
+
response = coll.query.near_vector(
|
209
|
+
near_vector=embedding,
|
210
|
+
limit=k,
|
211
|
+
return_properties=True,
|
212
|
+
return_metadata=MetadataQuery(distance=True),
|
213
|
+
)
|
214
|
+
return [
|
215
|
+
(self.weaviate_obj_to_doc(item), 1 - item.metadata.distance)
|
216
|
+
for item in response.objects
|
217
|
+
]
|
218
|
+
|
219
|
+
def _create_valid_uuid_id(self, id: str) -> Any:
|
220
|
+
try:
|
221
|
+
id = get_valid_uuid(id)
|
222
|
+
return id
|
223
|
+
except Exception:
|
224
|
+
return generate_uuid5(id)
|
225
|
+
|
226
|
+
def weaviate_obj_to_doc(self, input_object: Any) -> Document:
|
227
|
+
content = input_object.properties.get("content", "")
|
228
|
+
metadata_dict = input_object.properties.get("metadata", {})
|
229
|
+
|
230
|
+
window_ids = metadata_dict.pop("window_ids", [])
|
231
|
+
window_ids = [str(uuid) for uuid in window_ids]
|
232
|
+
|
233
|
+
# Ensure the id is a valid UUID string
|
234
|
+
id_value = get_valid_uuid(input_object.uuid)
|
235
|
+
|
236
|
+
metadata = DocMetaData(id=id_value, window_ids=window_ids, **metadata_dict)
|
237
|
+
|
238
|
+
return Document(content=content, metadata=metadata)
|
239
|
+
|
240
|
+
@staticmethod
|
241
|
+
def validate_and_format_collection_name(name: str) -> str:
|
242
|
+
"""
|
243
|
+
Formats the collection name to comply with Weaviate's naming rules:
|
244
|
+
- Name must start with a capital letter.
|
245
|
+
- Name can only contain letters, numbers, and underscores.
|
246
|
+
- Replaces invalid characters with underscores.
|
247
|
+
"""
|
248
|
+
if not name:
|
249
|
+
raise ValueError("Collection name cannot be empty.")
|
250
|
+
|
251
|
+
formatted_name = re.sub(r"[^a-zA-Z0-9_]", "_", name)
|
252
|
+
|
253
|
+
# Ensure the first letter is capitalized
|
254
|
+
if not formatted_name[0].isupper():
|
255
|
+
formatted_name = formatted_name.capitalize()
|
256
|
+
|
257
|
+
# Check if the name now meets the criteria
|
258
|
+
if not re.match(r"^[A-Z][A-Za-z0-9_]*$", formatted_name):
|
259
|
+
raise ValueError(
|
260
|
+
f"Invalid collection name '{name}'."
|
261
|
+
" Names must start with a capital letter "
|
262
|
+
"and contain only letters, numbers, and underscores."
|
263
|
+
)
|
264
|
+
|
265
|
+
if formatted_name != name:
|
266
|
+
logger.warning(
|
267
|
+
f"Collection name '{name}' was reformatted to '{formatted_name}' "
|
268
|
+
"to comply with Weaviate's rules."
|
269
|
+
)
|
270
|
+
|
271
|
+
return formatted_name
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: langroid
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.36.1
|
4
4
|
Summary: Harness LLMs with Multi-Agent Programming
|
5
5
|
Author-email: Prasad Chalasani <pchalasani@gmail.com>
|
6
6
|
License: MIT
|
@@ -75,6 +75,7 @@ Requires-Dist: sqlalchemy<3.0.0,>=2.0.19; extra == 'all'
|
|
75
75
|
Requires-Dist: torch<3.0.0,>=2.0.0; extra == 'all'
|
76
76
|
Requires-Dist: transformers<5.0.0,>=4.40.1; extra == 'all'
|
77
77
|
Requires-Dist: unstructured[docx,pdf,pptx]<0.10.18,>=0.10.16; extra == 'all'
|
78
|
+
Requires-Dist: weaviate-client>=4.9.6; extra == 'all'
|
78
79
|
Provides-Extra: arango
|
79
80
|
Requires-Dist: arango-datasets<2.0.0,>=1.2.2; extra == 'arango'
|
80
81
|
Requires-Dist: python-arango<9.0.0,>=8.1.2; extra == 'arango'
|
@@ -148,6 +149,9 @@ Requires-Dist: chromadb<=0.4.23,>=0.4.21; extra == 'vecdbs'
|
|
148
149
|
Requires-Dist: lancedb<0.9.0,>=0.8.2; extra == 'vecdbs'
|
149
150
|
Requires-Dist: pyarrow<16.0.0,>=15.0.0; extra == 'vecdbs'
|
150
151
|
Requires-Dist: tantivy<0.22.0,>=0.21.0; extra == 'vecdbs'
|
152
|
+
Requires-Dist: weaviate-client>=4.9.6; extra == 'vecdbs'
|
153
|
+
Provides-Extra: weaviate
|
154
|
+
Requires-Dist: weaviate-client>=4.9.6; extra == 'weaviate'
|
151
155
|
Description-Content-Type: text/markdown
|
152
156
|
|
153
157
|
<div align="center">
|
@@ -288,20 +292,28 @@ teacher_task.run()
|
|
288
292
|
<summary> <b>Click to expand</b></summary>
|
289
293
|
|
290
294
|
- **Jan 2025:**
|
291
|
-
- [0.
|
295
|
+
- [0.36.0](https://github.com/langroid/langroid/releases/tag/0.36.0): Weaviate vector-db support (thanks @abab-dev).
|
296
|
+
- [0.35.0](https://github.com/langroid/langroid/releases/tag/0.35.0): Capture/Stream reasoning content from
|
297
|
+
Reasoning LLMs (e.g. DeepSeek, OpenAI o1) in addition to final answer.
|
298
|
+
- [0.34.0](https://github.com/langroid/langroid/releases/tag/0.34.0): DocChatAgent
|
299
|
+
chunk enrichment to improve retrieval. (collaboration with @dfm88).
|
300
|
+
- [0.33.0](https://github.com/langroid/langroid/releases/tag/0.33.3) Move from Poetry to uv! (thanks @abab-dev).
|
292
301
|
- [0.32.0](https://github.com/langroid/langroid/releases/tag/0.32.0) DeepSeek v3 support.
|
293
302
|
- **Dec 2024:**
|
294
303
|
- [0.31.0](https://github.com/langroid/langroid/releases/tag/0.31.0) Azure OpenAI Embeddings
|
295
|
-
- [0.30.0](https://github.com/langroid/langroid/releases/tag/0.30.0) Llama-cpp embeddings.
|
296
|
-
- [0.29.0](https://github.com/langroid/langroid/releases/tag/0.29.0) Custom Azure OpenAI Client
|
304
|
+
- [0.30.0](https://github.com/langroid/langroid/releases/tag/0.30.0) Llama-cpp embeddings (thanks @Kwigg).
|
305
|
+
- [0.29.0](https://github.com/langroid/langroid/releases/tag/0.29.0) Custom Azure OpenAI Client (thanks
|
306
|
+
@johannestang).
|
297
307
|
- [0.28.0](https://github.com/langroid/langroid/releases/tag/0.28.0) `ToolMessage`: `_handler` field to override
|
298
|
-
default handler method name in `request` field.
|
308
|
+
default handler method name in `request` field (thanks @alexagr).
|
299
309
|
- [0.27.0](https://github.com/langroid/langroid/releases/tag/0.27.0) OpenRouter Support.
|
300
310
|
- [0.26.0](https://github.com/langroid/langroid/releases/tag/0.26.0) Update to latest Chainlit.
|
301
|
-
- [0.25.0](https://github.com/langroid/langroid/releases/tag/0.25.0) True Async Methods for agent and
|
311
|
+
- [0.25.0](https://github.com/langroid/langroid/releases/tag/0.25.0) True Async Methods for agent and
|
312
|
+
user-response (thanks @alexagr).
|
302
313
|
- **Nov 2024:**
|
303
314
|
- **[0.24.0](https://langroid.github.io/langroid/notes/structured-output/)**:
|
304
315
|
Enables support for `Agent`s with strict JSON schema output format on compatible LLMs and strict mode for the OpenAI tools API.
|
316
|
+
(thanks @nilspalumbo).
|
305
317
|
- **[0.23.0](https://langroid.github.io/langroid/tutorials/local-llm-setup/#local-llms-hosted-on-glhfchat)**:
|
306
318
|
support for LLMs (e.g. `Qwen2.5-Coder-32b-Instruct`) hosted on glhf.chat
|
307
319
|
- **[0.22.0](https://langroid.github.io/langroid/notes/large-tool-results/)**:
|
@@ -14,7 +14,7 @@ langroid/agent/xml_tool_message.py,sha256=6SshYZJKIfi4mkE-gIoSwjkEYekQ8GwcSiCv7a
|
|
14
14
|
langroid/agent/callbacks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
15
|
langroid/agent/callbacks/chainlit.py,sha256=RH8qUXaZE5o2WQz3WJQ1SdFtASGlxWCA6_HYz_3meDQ,20822
|
16
16
|
langroid/agent/special/__init__.py,sha256=gik_Xtm_zV7U9s30Mn8UX3Gyuy4jTjQe9zjiE3HWmEo,1273
|
17
|
-
langroid/agent/special/doc_chat_agent.py,sha256=
|
17
|
+
langroid/agent/special/doc_chat_agent.py,sha256=PCpdaVocIWt6ftO5OfmI1l20abVbKUSZWdMcu9hJDD0,64816
|
18
18
|
langroid/agent/special/lance_doc_chat_agent.py,sha256=s8xoRs0gGaFtDYFUSIRchsgDVbS5Q3C2b2mr3V1Fd-Q,10419
|
19
19
|
langroid/agent/special/lance_tools.py,sha256=qS8x4wi8mrqfbYV2ztFzrcxyhHQ0ZWOc-zkYiH7awj0,2105
|
20
20
|
langroid/agent/special/relevance_extractor_agent.py,sha256=zIx8GUdVo1aGW6ASla0NPQjYYIpmriK_TYMijqAx3F8,4796
|
@@ -81,7 +81,7 @@ langroid/parsing/code_parser.py,sha256=AOxb3xbYpTBPP3goOm5dKfJdh5hS_2BhLVCEkifWZ
|
|
81
81
|
langroid/parsing/document_parser.py,sha256=9xUOyrVNBAS9cpCvCptr2XK4Kq47W574i8zzGEoXc3c,24933
|
82
82
|
langroid/parsing/para_sentence_split.py,sha256=AJBzZojP3zpB-_IMiiHismhqcvkrVBQ3ZINoQyx_bE4,2000
|
83
83
|
langroid/parsing/parse_json.py,sha256=aADo38bAHQhC8on4aWZZzVzSDy-dK35vRLZsFI2ewh8,4756
|
84
|
-
langroid/parsing/parser.py,sha256=
|
84
|
+
langroid/parsing/parser.py,sha256=Wq204V1wqLdXS8kZ5J81dU2jE8fjoRY9zzNFbzLFDIs,12205
|
85
85
|
langroid/parsing/repo_loader.py,sha256=3GjvPJS6Vf5L6gV2zOU8s-Tf1oq_fZm-IB_RL_7CTsY,29373
|
86
86
|
langroid/parsing/routing.py,sha256=-FcnlqldzL4ZoxuDwXjQPNHgBe9F9-F4R6q7b_z9CvI,1232
|
87
87
|
langroid/parsing/search.py,sha256=0i_r0ESb5HEQfagA2g7_uMQyxYPADWVbdcN9ixZhS4E,8992
|
@@ -89,7 +89,7 @@ langroid/parsing/spider.py,sha256=hAVM6wxh1pQ0EN4tI5wMBtAjIk0T-xnpi-ZUzWybhos,32
|
|
89
89
|
langroid/parsing/table_loader.py,sha256=qNM4obT_0Y4tjrxNBCNUYjKQ9oETCZ7FbolKBTcz-GM,3410
|
90
90
|
langroid/parsing/url_loader.py,sha256=JK48KktLRDBfjrt4nsUfy92M6yGdEeicAqOum2MdULM,4656
|
91
91
|
langroid/parsing/urls.py,sha256=XjpaV5onG7gKQ5iQeFTzHSw5P08Aqw0g-rMUu61lR6s,7988
|
92
|
-
langroid/parsing/utils.py,sha256=
|
92
|
+
langroid/parsing/utils.py,sha256=YrV2GNL4EOBGknA4AClPGdJ4S5B31radrt-Ou8OAKoU,12749
|
93
93
|
langroid/parsing/web_search.py,sha256=8rW8EI3tyHITaB2l9MT_6yLMeQfo8y-Ih-8N2v2uMpk,4931
|
94
94
|
langroid/prompts/__init__.py,sha256=RW11vK6jiLPuaUh4GpeFvstti73gkm8_rDMtrbo2YsU,142
|
95
95
|
langroid/prompts/dialog.py,sha256=SpfiSyofSgy2pwD1YboHR_yHO3LEEMbv6j2sm874jKo,331
|
@@ -111,17 +111,18 @@ langroid/utils/types.py,sha256=4GrOnU3HLWh-UwaUPp7LlB3V413q3K5OSzc0ggDoQ6A,2510
|
|
111
111
|
langroid/utils/algorithms/__init__.py,sha256=WylYoZymA0fnzpB4vrsH_0n7WsoLhmuZq8qxsOCjUpM,41
|
112
112
|
langroid/utils/algorithms/graph.py,sha256=JbdpPnUOhw4-D6O7ou101JLA3xPCD0Lr3qaPoFCaRfo,2866
|
113
113
|
langroid/utils/output/__init__.py,sha256=7P0f--4IZneNsTxXY5fd6d6iW-CeVe-KSsl-87sbBPc,340
|
114
|
-
langroid/utils/output/citations.py,sha256=
|
114
|
+
langroid/utils/output/citations.py,sha256=mQhRXVN-uhmKd2z32UZQBE0adZGEaQJ7cVXLfkrcZJI,2221
|
115
115
|
langroid/utils/output/printing.py,sha256=yzPJZN-8_jyOJmI9N_oLwEDfjMwVgk3IDiwnZ4eK_AE,2962
|
116
116
|
langroid/utils/output/status.py,sha256=rzbE7mDJcgNNvdtylCseQcPGCGghtJvVq3lB-OPJ49E,1049
|
117
|
-
langroid/vector_store/__init__.py,sha256=
|
118
|
-
langroid/vector_store/base.py,sha256=
|
117
|
+
langroid/vector_store/__init__.py,sha256=BcoOm1tG3y0EqjkIGmMOHkY9iTUhDHgyruknWDKgqIg,1214
|
118
|
+
langroid/vector_store/base.py,sha256=suBanIt0iKEgnMnGdQOyWS58guG20Jyy-GK4DMMuYL0,14208
|
119
119
|
langroid/vector_store/chromadb.py,sha256=9WXW9IoSnhOmGEtMruVhEtVWL_VO6NXnPIz-nzh0gIQ,8235
|
120
120
|
langroid/vector_store/lancedb.py,sha256=b3_vWkTjG8mweZ7ZNlUD-NjmQP_rLBZfyKWcxt2vosA,14855
|
121
121
|
langroid/vector_store/meilisearch.py,sha256=6frB7GFWeWmeKzRfLZIvzRjllniZ1cYj3HmhHQICXLs,11663
|
122
122
|
langroid/vector_store/momento.py,sha256=UNHGT6jXuQtqY9f6MdqGU14bVnS0zHgIJUa30ULpUJo,10474
|
123
123
|
langroid/vector_store/qdrantdb.py,sha256=HRLCt-FG8y4718omwpFaQZnWeYxPj0XCwS4tjokI1sU,18116
|
124
|
-
langroid
|
125
|
-
langroid-0.
|
126
|
-
langroid-0.
|
127
|
-
langroid-0.
|
124
|
+
langroid/vector_store/weaviatedb.py,sha256=Jxe-cp2PyZdQ9NQVNZJ-CnsYsNxgUBdfAOoLZQEN650,10602
|
125
|
+
langroid-0.36.1.dist-info/METADATA,sha256=OzErGoPlFwxWia7jrFUx4M9FolTjexpJbgpTfhwT9Nk,60103
|
126
|
+
langroid-0.36.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
127
|
+
langroid-0.36.1.dist-info/licenses/LICENSE,sha256=EgVbvA6VSYgUlvC3RvPKehSg7MFaxWDsFuzLOsPPfJg,1065
|
128
|
+
langroid-0.36.1.dist-info/RECORD,,
|
File without changes
|
File without changes
|