agno 2.4.5__py3-none-any.whl → 2.4.7__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.
- agno/agent/agent.py +2 -1
- agno/db/singlestore/singlestore.py +4 -5
- agno/db/surrealdb/models.py +1 -1
- agno/knowledge/chunking/agentic.py +1 -5
- agno/knowledge/chunking/code.py +1 -1
- agno/knowledge/chunking/document.py +22 -42
- agno/knowledge/chunking/fixed.py +1 -5
- agno/knowledge/chunking/markdown.py +9 -25
- agno/knowledge/chunking/recursive.py +1 -3
- agno/knowledge/chunking/row.py +3 -2
- agno/knowledge/chunking/semantic.py +1 -1
- agno/knowledge/chunking/strategy.py +19 -0
- agno/knowledge/embedder/aws_bedrock.py +325 -106
- agno/knowledge/knowledge.py +173 -14
- agno/knowledge/reader/text_reader.py +1 -1
- agno/knowledge/reranker/aws_bedrock.py +299 -0
- agno/learn/machine.py +5 -6
- agno/learn/stores/learned_knowledge.py +108 -131
- agno/run/workflow.py +3 -0
- agno/tools/mcp/mcp.py +26 -1
- agno/utils/print_response/agent.py +8 -8
- agno/utils/print_response/team.py +8 -8
- agno/vectordb/lancedb/lance_db.py +9 -9
- agno/workflow/condition.py +135 -56
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/METADATA +34 -59
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/RECORD +29 -28
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/WHEEL +0 -0
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/licenses/LICENSE +0 -0
- {agno-2.4.5.dist-info → agno-2.4.7.dist-info}/top_level.txt +0 -0
agno/agent/agent.py
CHANGED
|
@@ -858,8 +858,9 @@ class Agent:
|
|
|
858
858
|
return
|
|
859
859
|
|
|
860
860
|
# Handle learning=True: create default LearningMachine
|
|
861
|
+
# Enables user_profile (structured fields) and user_memory (unstructured observations)
|
|
861
862
|
if self.learning is True:
|
|
862
|
-
self._learning = LearningMachine(db=self.db, model=self.model, user_profile=True)
|
|
863
|
+
self._learning = LearningMachine(db=self.db, model=self.model, user_profile=True, user_memory=True)
|
|
863
864
|
return
|
|
864
865
|
|
|
865
866
|
# Handle learning=LearningMachine(...): inject dependencies
|
|
@@ -173,8 +173,7 @@ class SingleStoreDb(BaseDb):
|
|
|
173
173
|
column_kwargs["unique"] = True
|
|
174
174
|
columns.append(Column(*column_args, **column_kwargs))
|
|
175
175
|
|
|
176
|
-
|
|
177
|
-
table = Table(table_name, self.metadata, *columns, schema=self.db_schema)
|
|
176
|
+
table = Table(table_name, self.metadata, *columns, schema=self.db_schema, extend_existing=True)
|
|
178
177
|
|
|
179
178
|
return table
|
|
180
179
|
|
|
@@ -240,8 +239,7 @@ class SingleStoreDb(BaseDb):
|
|
|
240
239
|
|
|
241
240
|
columns.append(Column(*column_args, **column_kwargs))
|
|
242
241
|
|
|
243
|
-
|
|
244
|
-
table = Table(table_name, self.metadata, *columns, schema=self.db_schema)
|
|
242
|
+
table = Table(table_name, self.metadata, *columns, schema=self.db_schema, extend_existing=True)
|
|
245
243
|
|
|
246
244
|
# Add multi-column unique constraints with table-specific names
|
|
247
245
|
for constraint in schema_unique_constraints:
|
|
@@ -396,7 +394,8 @@ class SingleStoreDb(BaseDb):
|
|
|
396
394
|
|
|
397
395
|
if table_type == "spans":
|
|
398
396
|
# Ensure traces table exists first (for foreign key)
|
|
399
|
-
|
|
397
|
+
if create_table_if_not_found:
|
|
398
|
+
self._get_table(table_type="traces", create_table_if_not_found=True)
|
|
400
399
|
self.spans_table = self._get_or_create_table(
|
|
401
400
|
table_name=self.span_table_name,
|
|
402
401
|
table_type="spans",
|
agno/db/surrealdb/models.py
CHANGED
|
@@ -48,7 +48,7 @@ def surrealize_dates(record: dict) -> dict:
|
|
|
48
48
|
if isinstance(value, date):
|
|
49
49
|
copy[key] = datetime.combine(value, datetime.min.time()).replace(tzinfo=timezone.utc)
|
|
50
50
|
elif key in ["created_at", "updated_at"] and isinstance(value, (int, float)):
|
|
51
|
-
copy[key] = datetime.fromtimestamp(value
|
|
51
|
+
copy[key] = datetime.fromtimestamp(value, tz=timezone.utc)
|
|
52
52
|
elif key in ["created_at", "updated_at"] and isinstance(value, str):
|
|
53
53
|
# Handle ISO string format - convert back to datetime object for SurrealDB
|
|
54
54
|
try:
|
|
@@ -55,11 +55,7 @@ class AgenticChunking(ChunkingStrategy):
|
|
|
55
55
|
chunk = remaining_text[:break_point].strip()
|
|
56
56
|
meta_data = chunk_meta_data.copy()
|
|
57
57
|
meta_data["chunk"] = chunk_number
|
|
58
|
-
chunk_id =
|
|
59
|
-
if document.id:
|
|
60
|
-
chunk_id = f"{document.id}_{chunk_number}"
|
|
61
|
-
elif document.name:
|
|
62
|
-
chunk_id = f"{document.name}_{chunk_number}"
|
|
58
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, chunk)
|
|
63
59
|
meta_data["chunk_size"] = len(chunk)
|
|
64
60
|
chunks.append(
|
|
65
61
|
Document(
|
agno/knowledge/chunking/code.py
CHANGED
|
@@ -82,7 +82,7 @@ class CodeChunking(ChunkingStrategy):
|
|
|
82
82
|
for i, chunk in enumerate(chunks, 1):
|
|
83
83
|
meta_data = document.meta_data.copy()
|
|
84
84
|
meta_data["chunk"] = i
|
|
85
|
-
chunk_id =
|
|
85
|
+
chunk_id = self._generate_chunk_id(document, i, chunk.text)
|
|
86
86
|
meta_data["chunk_size"] = len(chunk.text)
|
|
87
87
|
|
|
88
88
|
chunked_documents.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk.text))
|
|
@@ -38,17 +38,10 @@ class DocumentChunking(ChunkingStrategy):
|
|
|
38
38
|
if current_chunk:
|
|
39
39
|
meta_data = chunk_meta_data.copy()
|
|
40
40
|
meta_data["chunk"] = chunk_number
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
chunk_id = f"{document.name}_{chunk_number}"
|
|
46
|
-
meta_data["chunk_size"] = len("\n\n".join(current_chunk))
|
|
47
|
-
chunks.append(
|
|
48
|
-
Document(
|
|
49
|
-
id=chunk_id, name=document.name, meta_data=meta_data, content="\n\n".join(current_chunk)
|
|
50
|
-
)
|
|
51
|
-
)
|
|
41
|
+
chunk_content = "\n\n".join(current_chunk)
|
|
42
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, chunk_content)
|
|
43
|
+
meta_data["chunk_size"] = len(chunk_content)
|
|
44
|
+
chunks.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk_content))
|
|
52
45
|
chunk_number += 1
|
|
53
46
|
current_chunk = []
|
|
54
47
|
current_size = 0
|
|
@@ -70,18 +63,15 @@ class DocumentChunking(ChunkingStrategy):
|
|
|
70
63
|
if current_chunk:
|
|
71
64
|
meta_data = chunk_meta_data.copy()
|
|
72
65
|
meta_data["chunk"] = chunk_number
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
elif document.name:
|
|
77
|
-
chunk_id = f"{document.name}_{chunk_number}"
|
|
78
|
-
meta_data["chunk_size"] = len(" ".join(current_chunk))
|
|
66
|
+
chunk_content = " ".join(current_chunk)
|
|
67
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, chunk_content)
|
|
68
|
+
meta_data["chunk_size"] = len(chunk_content)
|
|
79
69
|
chunks.append(
|
|
80
70
|
Document(
|
|
81
71
|
id=chunk_id,
|
|
82
72
|
name=document.name,
|
|
83
73
|
meta_data=meta_data,
|
|
84
|
-
content=
|
|
74
|
+
content=chunk_content,
|
|
85
75
|
)
|
|
86
76
|
)
|
|
87
77
|
chunk_number += 1
|
|
@@ -94,18 +84,11 @@ class DocumentChunking(ChunkingStrategy):
|
|
|
94
84
|
else:
|
|
95
85
|
meta_data = chunk_meta_data.copy()
|
|
96
86
|
meta_data["chunk"] = chunk_number
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
elif document.name:
|
|
101
|
-
chunk_id = f"{document.name}_{chunk_number}"
|
|
102
|
-
meta_data["chunk_size"] = len("\n\n".join(current_chunk))
|
|
87
|
+
chunk_content = "\n\n".join(current_chunk)
|
|
88
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, chunk_content)
|
|
89
|
+
meta_data["chunk_size"] = len(chunk_content)
|
|
103
90
|
if current_chunk:
|
|
104
|
-
chunks.append(
|
|
105
|
-
Document(
|
|
106
|
-
id=chunk_id, name=document.name, meta_data=meta_data, content="\n\n".join(current_chunk)
|
|
107
|
-
)
|
|
108
|
-
)
|
|
91
|
+
chunks.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk_content))
|
|
109
92
|
chunk_number += 1
|
|
110
93
|
current_chunk = [para]
|
|
111
94
|
current_size = para_size
|
|
@@ -113,15 +96,10 @@ class DocumentChunking(ChunkingStrategy):
|
|
|
113
96
|
if current_chunk:
|
|
114
97
|
meta_data = chunk_meta_data.copy()
|
|
115
98
|
meta_data["chunk"] = chunk_number
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
chunk_id = f"{document.name}_{chunk_number}"
|
|
121
|
-
meta_data["chunk_size"] = len("\n\n".join(current_chunk))
|
|
122
|
-
chunks.append(
|
|
123
|
-
Document(id=chunk_id, name=document.name, meta_data=meta_data, content="\n\n".join(current_chunk))
|
|
124
|
-
)
|
|
99
|
+
chunk_content = "\n\n".join(current_chunk)
|
|
100
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, chunk_content)
|
|
101
|
+
meta_data["chunk_size"] = len(chunk_content)
|
|
102
|
+
chunks.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk_content))
|
|
125
103
|
|
|
126
104
|
# Handle overlap if specified
|
|
127
105
|
if self.overlap > 0:
|
|
@@ -131,11 +109,11 @@ class DocumentChunking(ChunkingStrategy):
|
|
|
131
109
|
# Add overlap from previous chunk
|
|
132
110
|
prev_text = chunks[i - 1].content[-self.overlap :]
|
|
133
111
|
meta_data = chunk_meta_data.copy()
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
chunk_id = f"{document.id}_{chunk_number}"
|
|
112
|
+
# Use the chunk's existing metadata and ID instead of stale chunk_number
|
|
113
|
+
meta_data["chunk"] = chunks[i].meta_data["chunk"]
|
|
114
|
+
chunk_id = chunks[i].id
|
|
138
115
|
meta_data["chunk_size"] = len(prev_text + chunks[i].content)
|
|
116
|
+
|
|
139
117
|
if prev_text:
|
|
140
118
|
overlapped_chunks.append(
|
|
141
119
|
Document(
|
|
@@ -145,6 +123,8 @@ class DocumentChunking(ChunkingStrategy):
|
|
|
145
123
|
content=prev_text + chunks[i].content,
|
|
146
124
|
)
|
|
147
125
|
)
|
|
126
|
+
else:
|
|
127
|
+
overlapped_chunks.append(chunks[i])
|
|
148
128
|
else:
|
|
149
129
|
overlapped_chunks.append(chunks[i])
|
|
150
130
|
chunks = overlapped_chunks
|
agno/knowledge/chunking/fixed.py
CHANGED
|
@@ -38,11 +38,7 @@ class FixedSizeChunking(ChunkingStrategy):
|
|
|
38
38
|
chunk = content[start:end]
|
|
39
39
|
meta_data = chunk_meta_data.copy()
|
|
40
40
|
meta_data["chunk"] = chunk_number
|
|
41
|
-
chunk_id =
|
|
42
|
-
if document.id:
|
|
43
|
-
chunk_id = f"{document.id}_{chunk_number}"
|
|
44
|
-
elif document.name:
|
|
45
|
-
chunk_id = f"{document.name}_{chunk_number}"
|
|
41
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, chunk)
|
|
46
42
|
meta_data["chunk_size"] = len(chunk)
|
|
47
43
|
chunked_documents.append(
|
|
48
44
|
Document(
|
|
@@ -267,11 +267,7 @@ class MarkdownChunking(ChunkingStrategy):
|
|
|
267
267
|
for sub_chunk in sub_chunks:
|
|
268
268
|
meta_data = chunk_meta_data.copy()
|
|
269
269
|
meta_data["chunk"] = chunk_number
|
|
270
|
-
chunk_id =
|
|
271
|
-
if document.id:
|
|
272
|
-
chunk_id = f"{document.id}_{chunk_number}"
|
|
273
|
-
elif document.name:
|
|
274
|
-
chunk_id = f"{document.name}_{chunk_number}"
|
|
270
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, sub_chunk)
|
|
275
271
|
meta_data["chunk_size"] = len(sub_chunk)
|
|
276
272
|
|
|
277
273
|
chunks.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=sub_chunk))
|
|
@@ -282,19 +278,12 @@ class MarkdownChunking(ChunkingStrategy):
|
|
|
282
278
|
else:
|
|
283
279
|
meta_data = chunk_meta_data.copy()
|
|
284
280
|
meta_data["chunk"] = chunk_number
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
elif document.name:
|
|
289
|
-
chunk_id = f"{document.name}_{chunk_number}"
|
|
290
|
-
meta_data["chunk_size"] = len("\n\n".join(current_chunk))
|
|
281
|
+
chunk_content = "\n\n".join(current_chunk)
|
|
282
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, chunk_content)
|
|
283
|
+
meta_data["chunk_size"] = len(chunk_content)
|
|
291
284
|
|
|
292
285
|
if current_chunk:
|
|
293
|
-
chunks.append(
|
|
294
|
-
Document(
|
|
295
|
-
id=chunk_id, name=document.name, meta_data=meta_data, content="\n\n".join(current_chunk)
|
|
296
|
-
)
|
|
297
|
-
)
|
|
286
|
+
chunks.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk_content))
|
|
298
287
|
chunk_number += 1
|
|
299
288
|
|
|
300
289
|
current_chunk = [section]
|
|
@@ -304,15 +293,10 @@ class MarkdownChunking(ChunkingStrategy):
|
|
|
304
293
|
if current_chunk and not self.split_on_headings:
|
|
305
294
|
meta_data = chunk_meta_data.copy()
|
|
306
295
|
meta_data["chunk"] = chunk_number
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
chunk_id = f"{document.name}_{chunk_number}"
|
|
312
|
-
meta_data["chunk_size"] = len("\n\n".join(current_chunk))
|
|
313
|
-
chunks.append(
|
|
314
|
-
Document(id=chunk_id, name=document.name, meta_data=meta_data, content="\n\n".join(current_chunk))
|
|
315
|
-
)
|
|
296
|
+
chunk_content = "\n\n".join(current_chunk)
|
|
297
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, chunk_content)
|
|
298
|
+
meta_data["chunk_size"] = len(chunk_content)
|
|
299
|
+
chunks.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk_content))
|
|
316
300
|
|
|
317
301
|
# Handle overlap if specified
|
|
318
302
|
if self.overlap > 0:
|
|
@@ -46,9 +46,7 @@ class RecursiveChunking(ChunkingStrategy):
|
|
|
46
46
|
chunk = self.clean_text(content[start:end])
|
|
47
47
|
meta_data = chunk_meta_data.copy()
|
|
48
48
|
meta_data["chunk"] = chunk_number
|
|
49
|
-
chunk_id =
|
|
50
|
-
if document.id:
|
|
51
|
-
chunk_id = f"{document.id}_{chunk_number}"
|
|
49
|
+
chunk_id = self._generate_chunk_id(document, chunk_number, chunk)
|
|
52
50
|
chunk_number += 1
|
|
53
51
|
meta_data["chunk_size"] = len(chunk)
|
|
54
52
|
chunks.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk))
|
agno/knowledge/chunking/row.py
CHANGED
|
@@ -33,7 +33,8 @@ class RowChunking(ChunkingStrategy):
|
|
|
33
33
|
|
|
34
34
|
if chunk_content: # Skip empty rows
|
|
35
35
|
meta_data = document.meta_data.copy()
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
row_number = start_index + i
|
|
37
|
+
meta_data["row_number"] = row_number # Preserve logical row numbering
|
|
38
|
+
chunk_id = self._generate_chunk_id(document, row_number, chunk_content, prefix="row")
|
|
38
39
|
chunks.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk_content))
|
|
39
40
|
return chunks
|
|
@@ -160,7 +160,7 @@ class SemanticChunking(ChunkingStrategy):
|
|
|
160
160
|
for i, chunk in enumerate(chunks, 1):
|
|
161
161
|
meta_data = document.meta_data.copy()
|
|
162
162
|
meta_data["chunk"] = i
|
|
163
|
-
chunk_id =
|
|
163
|
+
chunk_id = self._generate_chunk_id(document, i, chunk.text)
|
|
164
164
|
meta_data["chunk_size"] = len(chunk.text)
|
|
165
165
|
|
|
166
166
|
chunked_documents.append(Document(id=chunk_id, name=document.name, meta_data=meta_data, content=chunk.text))
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import hashlib
|
|
1
2
|
from abc import ABC, abstractmethod
|
|
2
3
|
from enum import Enum
|
|
3
4
|
from typing import List, Optional
|
|
@@ -12,6 +13,24 @@ class ChunkingStrategy(ABC):
|
|
|
12
13
|
def chunk(self, document: Document) -> List[Document]:
|
|
13
14
|
raise NotImplementedError
|
|
14
15
|
|
|
16
|
+
def _generate_chunk_id(
|
|
17
|
+
self, document: Document, chunk_number: int, content: Optional[str] = None, prefix: Optional[str] = None
|
|
18
|
+
) -> Optional[str]:
|
|
19
|
+
"""Generate a deterministic ID for the chunk."""
|
|
20
|
+
suffix = f"_{prefix}_{chunk_number}" if prefix else f"_{chunk_number}"
|
|
21
|
+
|
|
22
|
+
if document.id:
|
|
23
|
+
return f"{document.id}{suffix}"
|
|
24
|
+
elif document.name:
|
|
25
|
+
return f"{document.name}{suffix}"
|
|
26
|
+
else:
|
|
27
|
+
# Hash the chunk content for a deterministic ID when no identifier exists
|
|
28
|
+
hash_source = content if content else document.content
|
|
29
|
+
if hash_source:
|
|
30
|
+
content_hash = hashlib.md5(hash_source.encode("utf-8")).hexdigest()[:12] # nosec B324
|
|
31
|
+
return f"chunk_{content_hash}{suffix}"
|
|
32
|
+
return None
|
|
33
|
+
|
|
15
34
|
async def achunk(self, document: Document) -> List[Document]:
|
|
16
35
|
"""Async version of chunk. Override for truly async implementations."""
|
|
17
36
|
return self.chunk(document)
|