agno 2.3.15__py3-none-any.whl → 2.3.16__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.
@@ -47,17 +47,16 @@ class CSVReader(Reader):
47
47
  if not file.exists():
48
48
  raise FileNotFoundError(f"Could not find file: {file}")
49
49
  log_debug(f"Reading: {file}")
50
- file_content = file.open(newline="", mode="r", encoding=self.encoding or "utf-8")
50
+ csv_name = name or file.stem
51
+ file_content: Union[io.TextIOWrapper, io.StringIO] = file.open(
52
+ newline="", mode="r", encoding=self.encoding or "utf-8"
53
+ )
51
54
  else:
52
- log_debug(f"Reading retrieved file: {name or file.name}")
55
+ log_debug(f"Reading retrieved file: {getattr(file, 'name', 'BytesIO')}")
56
+ csv_name = name or getattr(file, "name", "csv_file").split(".")[0]
53
57
  file.seek(0)
54
- file_content = io.StringIO(file.read().decode("utf-8")) # type: ignore
58
+ file_content = io.StringIO(file.read().decode("utf-8"))
55
59
 
56
- csv_name = name or (
57
- Path(file.name).stem
58
- if isinstance(file, Path)
59
- else (getattr(file, "name", "csv_file").split(".")[0] if hasattr(file, "name") else "csv_file")
60
- )
61
60
  csv_content = ""
62
61
  with file_content as csvfile:
63
62
  csv_reader = csv.reader(csvfile, delimiter=delimiter, quotechar=quotechar)
@@ -109,16 +108,12 @@ class CSVReader(Reader):
109
108
  async with aiofiles.open(file, mode="r", encoding="utf-8", newline="") as file_content:
110
109
  content = await file_content.read()
111
110
  file_content_io = io.StringIO(content)
111
+ csv_name = name or file.stem
112
112
  else:
113
113
  log_debug(f"Reading retrieved file async: {getattr(file, 'name', 'BytesIO')}")
114
114
  file.seek(0)
115
115
  file_content_io = io.StringIO(file.read().decode("utf-8"))
116
-
117
- csv_name = name or (
118
- Path(file.name).stem
119
- if isinstance(file, Path)
120
- else (getattr(file, "name", "csv_file").split(".")[0] if hasattr(file, "name") else "csv_file")
121
- )
116
+ csv_name = name or getattr(file, "name", "csv_file").split(".")[0]
122
117
 
123
118
  file_content_io.seek(0)
124
119
  csv_reader = csv.reader(file_content_io, delimiter=delimiter, quotechar=quotechar)
@@ -161,4 +156,4 @@ class CSVReader(Reader):
161
156
  return documents
162
157
  except Exception as e:
163
158
  log_error(f"Error reading async: {getattr(file, 'name', str(file)) if isinstance(file, IO) else file}: {e}")
164
- return []
159
+ return []
@@ -47,11 +47,9 @@ class DocxReader(Reader):
47
47
  docx_document = DocxDocument(str(file))
48
48
  doc_name = name or file.stem
49
49
  else:
50
- log_debug(f"Reading uploaded file: {getattr(file, 'name', 'docx_file')}")
50
+ log_debug(f"Reading uploaded file: {getattr(file, 'name', 'BytesIO')}")
51
51
  docx_document = DocxDocument(file)
52
- doc_name = name or (
53
- getattr(file, "name", "docx_file").split(".")[0] if hasattr(file, "name") else "docx_file"
54
- )
52
+ doc_name = name or getattr(file, "name", "docx_file").split(".")[0]
55
53
 
56
54
  doc_content = "\n\n".join([para.text for para in docx_document.paragraphs])
57
55
 
@@ -106,17 +106,15 @@ class FieldLabeledCSVReader(Reader):
106
106
  if not file.exists():
107
107
  raise FileNotFoundError(f"Could not find file: {file}")
108
108
  log_debug(f"Reading: {file}")
109
- file_content = file.open(newline="", mode="r", encoding=self.encoding or "utf-8")
109
+ csv_name = name or file.stem
110
+ file_content: Union[io.TextIOWrapper, io.StringIO] = file.open(
111
+ newline="", mode="r", encoding=self.encoding or "utf-8"
112
+ )
110
113
  else:
111
- log_debug(f"Reading retrieved file: {name or file.name}")
114
+ log_debug(f"Reading retrieved file: {getattr(file, 'name', 'BytesIO')}")
115
+ csv_name = name or getattr(file, "name", "csv_file").split(".")[0]
112
116
  file.seek(0)
113
- file_content = io.StringIO(file.read().decode("utf-8")) # type: ignore
114
-
115
- csv_name = name or (
116
- Path(file.name).stem
117
- if isinstance(file, Path)
118
- else (getattr(file, "name", "csv_file").split(".")[0] if hasattr(file, "name") else "csv_file")
119
- )
117
+ file_content = io.StringIO(file.read().decode("utf-8"))
120
118
 
121
119
  documents = []
122
120
 
@@ -189,16 +187,12 @@ class FieldLabeledCSVReader(Reader):
189
187
  async with aiofiles.open(file, mode="r", encoding=self.encoding or "utf-8", newline="") as file_content:
190
188
  content = await file_content.read()
191
189
  file_content_io = io.StringIO(content)
190
+ csv_name = name or file.stem
192
191
  else:
193
- log_debug(f"Reading retrieved file async: {name or file.name}")
192
+ log_debug(f"Reading retrieved file async: {getattr(file, 'name', 'BytesIO')}")
193
+ csv_name = name or getattr(file, "name", "csv_file").split(".")[0]
194
194
  file.seek(0)
195
- file_content_io = io.StringIO(file.read().decode("utf-8")) # type: ignore
196
-
197
- csv_name = name or (
198
- Path(file.name).stem
199
- if isinstance(file, Path)
200
- else (getattr(file, "name", "csv_file").split(".")[0] if hasattr(file, "name") else "csv_file")
201
- )
195
+ file_content_io = io.StringIO(file.read().decode("utf-8"))
202
196
 
203
197
  file_content_io.seek(0)
204
198
  csv_reader = csv.reader(file_content_io, delimiter=delimiter, quotechar=quotechar)
@@ -287,4 +281,4 @@ class FieldLabeledCSVReader(Reader):
287
281
 
288
282
  except Exception as e:
289
283
  log_error(f"Error reading async: {getattr(file, 'name', str(file)) if isinstance(file, IO) else file}: {e}")
290
- return []
284
+ return []
@@ -1,6 +1,5 @@
1
1
  import asyncio
2
2
  import json
3
- from io import BytesIO
4
3
  from pathlib import Path
5
4
  from typing import IO, Any, List, Optional, Union
6
5
  from uuid import uuid4
@@ -42,17 +41,15 @@ class JSONReader(Reader):
42
41
  if not path.exists():
43
42
  raise FileNotFoundError(f"Could not find file: {path}")
44
43
  log_debug(f"Reading: {path}")
45
- json_name = name or path.name.split(".")[0]
46
- json_contents = json.loads(path.read_text(self.encoding or "utf-8"))
47
-
48
- elif isinstance(path, BytesIO):
49
- json_name = name or path.name.split(".")[0]
50
- log_debug(f"Reading uploaded file: {json_name}")
44
+ json_name = name or path.stem
45
+ json_contents = json.loads(path.read_text(encoding=self.encoding or "utf-8"))
46
+ elif hasattr(path, "seek") and hasattr(path, "read"):
47
+ log_debug(f"Reading uploaded file: {getattr(path, 'name', 'BytesIO')}")
48
+ json_name = name or getattr(path, "name", "json_file").split(".")[0]
51
49
  path.seek(0)
52
50
  json_contents = json.load(path)
53
-
54
51
  else:
55
- raise ValueError("Unsupported file type. Must be Path or BytesIO.")
52
+ raise ValueError("Unsupported file type. Must be Path or file-like object.")
56
53
 
57
54
  if isinstance(json_contents, dict):
58
55
  json_contents = [json_contents]
@@ -72,17 +69,12 @@ class JSONReader(Reader):
72
69
  chunked_documents.extend(self.chunk_document(document))
73
70
  return chunked_documents
74
71
  return documents
72
+ except (FileNotFoundError, ValueError, json.JSONDecodeError):
73
+ raise
75
74
  except Exception as e:
76
75
  log_error(f"Error reading: {path}: {e}")
77
76
  raise
78
77
 
79
78
  async def async_read(self, path: Union[Path, IO[Any]], name: Optional[str] = None) -> List[Document]:
80
- """Asynchronously read JSON files.
81
-
82
- Args:
83
- path (Union[Path, IO[Any]]): Path to a JSON file or a file-like object
84
-
85
- Returns:
86
- List[Document]: List of documents from the JSON file
87
- """
88
- return await asyncio.to_thread(self.read, path, name)
79
+ """Asynchronously read JSON files."""
80
+ return await asyncio.to_thread(self.read, path, name)
@@ -69,8 +69,8 @@ class MarkdownReader(Reader):
69
69
  file_name = name or file.stem
70
70
  file_contents = file.read_text(encoding=self.encoding or "utf-8")
71
71
  else:
72
- log_debug(f"Reading uploaded file: {file.name}")
73
- file_name = name or file.name.split(".")[0]
72
+ log_debug(f"Reading uploaded file: {getattr(file, 'name', 'BytesIO')}")
73
+ file_name = name or getattr(file, "name", "file").split(".")[0]
74
74
  file.seek(0)
75
75
  file_contents = file.read().decode(self.encoding or "utf-8")
76
76
 
@@ -101,16 +101,16 @@ class MarkdownReader(Reader):
101
101
  file_contents = await f.read()
102
102
  except ImportError:
103
103
  log_warning("aiofiles not installed, using synchronous file I/O")
104
- file_contents = file.read_text(self.encoding or "utf-8")
104
+ file_contents = file.read_text(encoding=self.encoding or "utf-8")
105
105
  else:
106
- log_debug(f"Reading uploaded file asynchronously: {file.name}")
107
- file_name = name or file.name.split(".")[0]
106
+ log_debug(f"Reading uploaded file asynchronously: {getattr(file, 'name', 'BytesIO')}")
107
+ file_name = name or getattr(file, "name", "file").split(".")[0]
108
108
  file.seek(0)
109
109
  file_contents = file.read().decode(self.encoding or "utf-8")
110
110
 
111
111
  document = Document(
112
112
  name=file_name,
113
- id=str(uuid.uuid4()), # Fixed an issue with the id creation
113
+ id=str(uuid.uuid4()),
114
114
  content=file_contents,
115
115
  )
116
116
 
@@ -218,16 +218,13 @@ class BasePDFReader(Reader):
218
218
 
219
219
  def _get_doc_name(self, pdf_source: Union[str, Path, IO[Any]], name: Optional[str] = None) -> str:
220
220
  """Determines the document name from the source or a provided name."""
221
- try:
222
- if name:
223
- return name
224
- if isinstance(pdf_source, str):
225
- return pdf_source.split("/")[-1].split(".")[0].replace(" ", "_")
226
- # Assumes a file-like object with a .name attribute
227
- return pdf_source.name.split(".")[0]
228
- except Exception:
229
- # The original code had a bug here, it should check `name` first.
230
- return name or "pdf"
221
+ if name:
222
+ return name
223
+ if isinstance(pdf_source, str):
224
+ return Path(pdf_source).stem.replace(" ", "_")
225
+ if isinstance(pdf_source, Path):
226
+ return pdf_source.stem.replace(" ", "_")
227
+ return getattr(pdf_source, "name", "pdf_file").split(".")[0].replace(" ", "_")
231
228
 
232
229
  def _decrypt_pdf(self, doc_reader: DocumentReader, doc_name: str, password: Optional[str] = None) -> bool:
233
230
  if not doc_reader.is_encrypted:
@@ -341,8 +338,14 @@ class PDFReader(BasePDFReader):
341
338
  return [ContentType.PDF]
342
339
 
343
340
  def read(
344
- self, pdf: Union[str, Path, IO[Any]], name: Optional[str] = None, password: Optional[str] = None
341
+ self,
342
+ pdf: Optional[Union[str, Path, IO[Any]]] = None,
343
+ name: Optional[str] = None,
344
+ password: Optional[str] = None,
345
345
  ) -> List[Document]:
346
+ if pdf is None:
347
+ log_error("No pdf provided")
348
+ return []
346
349
  doc_name = self._get_doc_name(pdf, name)
347
350
  log_debug(f"Reading: {doc_name}")
348
351
 
@@ -47,11 +47,9 @@ class PPTXReader(Reader):
47
47
  presentation = Presentation(str(file))
48
48
  doc_name = name or file.stem
49
49
  else:
50
- log_debug(f"Reading uploaded file: {getattr(file, 'name', 'pptx_file')}")
50
+ log_debug(f"Reading uploaded file: {getattr(file, 'name', 'BytesIO')}")
51
51
  presentation = Presentation(file)
52
- doc_name = name or (
53
- getattr(file, "name", "pptx_file").split(".")[0] if hasattr(file, "name") else "pptx_file"
54
- )
52
+ doc_name = name or getattr(file, "name", "pptx_file").split(".")[0]
55
53
 
56
54
  # Extract text from all slides
57
55
  slide_texts = []
@@ -53,29 +53,20 @@ class S3Reader(Reader):
53
53
  try:
54
54
  log_debug(f"Reading S3 file: {s3_object.uri}")
55
55
 
56
+ doc_name = name or s3_object.name.split("/")[-1].split(".")[0].replace("/", "_").replace(" ", "_")
57
+
56
58
  # Read PDF files
57
59
  if s3_object.uri.endswith(".pdf"):
58
60
  object_resource = s3_object.get_resource()
59
61
  object_body = object_resource.get()["Body"]
60
- doc_name = (
61
- s3_object.name.split("/")[-1].split(".")[0].replace("/", "_").replace(" ", "_")
62
- if name is None
63
- else name
64
- )
65
62
  return PDFReader().read(pdf=BytesIO(object_body.read()), name=doc_name)
66
63
 
67
64
  # Read text files
68
65
  else:
69
- doc_name = (
70
- s3_object.name.split("/")[-1].split(".")[0].replace("/", "_").replace(" ", "_")
71
- if name is None
72
- else name
73
- )
74
66
  obj_name = s3_object.name.split("/")[-1]
75
67
  temporary_file = Path("storage").joinpath(obj_name)
76
68
  s3_object.download(temporary_file)
77
69
  documents = TextReader().read(file=temporary_file, name=doc_name)
78
-
79
70
  temporary_file.unlink()
80
71
  return documents
81
72
 
@@ -39,16 +39,10 @@ class TextReader(Reader):
39
39
  raise FileNotFoundError(f"Could not find file: {file}")
40
40
  log_debug(f"Reading: {file}")
41
41
  file_name = name or file.stem
42
- file_contents = file.read_text(self.encoding or "utf-8")
42
+ file_contents = file.read_text(encoding=self.encoding or "utf-8")
43
43
  else:
44
- # Handle BytesIO and other file-like objects that may not have a name attribute
45
- if name:
46
- file_name = name
47
- elif hasattr(file, "name") and file.name is not None:
48
- file_name = file.name.split(".")[0]
49
- else:
50
- file_name = "text_file"
51
- log_debug(f"Reading uploaded file: {file_name}")
44
+ log_debug(f"Reading uploaded file: {getattr(file, 'name', 'BytesIO')}")
45
+ file_name = name or getattr(file, "name", "text_file").split(".")[0]
52
46
  file.seek(0)
53
47
  file_contents = file.read().decode(self.encoding or "utf-8")
54
48
 
@@ -85,16 +79,10 @@ class TextReader(Reader):
85
79
  file_contents = await f.read()
86
80
  except ImportError:
87
81
  log_warning("aiofiles not installed, using synchronous file I/O")
88
- file_contents = file.read_text(self.encoding or "utf-8")
82
+ file_contents = file.read_text(encoding=self.encoding or "utf-8")
89
83
  else:
90
- # Handle BytesIO and other file-like objects that may not have a name attribute
91
- if name:
92
- file_name = name
93
- elif hasattr(file, "name") and file.name is not None:
94
- file_name = file.name.split(".")[0]
95
- else:
96
- file_name = "text_file"
97
- log_debug(f"Reading uploaded file asynchronously: {file_name}")
84
+ log_debug(f"Reading uploaded file asynchronously: {getattr(file, 'name', 'BytesIO')}")
85
+ file_name = name or getattr(file, "name", "text_file").split(".")[0]
98
86
  file.seek(0)
99
87
  file_contents = file.read().decode(self.encoding or "utf-8")
100
88
 
@@ -263,21 +263,17 @@ class WebSearchReader(Reader):
263
263
 
264
264
  log_debug(f"Starting async web search reader for query: {query}")
265
265
 
266
- # Perform web search (synchronous operation)
267
266
  search_results = self._perform_web_search(query)
268
267
  if not search_results:
269
268
  logger.warning(f"No search results found for query: {query}")
270
269
  return []
271
270
 
272
- # Create tasks for fetching content from each URL
273
271
  async def fetch_url_async(result: Dict[str, str]) -> Optional[Document]:
274
272
  url = result.get("url", "")
275
273
 
276
- # Skip if URL is invalid or already visited
277
274
  if not self._is_valid_url(url):
278
275
  return None
279
276
 
280
- # Mark URL as visited
281
277
  self._visited_urls.add(url)
282
278
 
283
279
  try:
@@ -292,32 +288,25 @@ class WebSearchReader(Reader):
292
288
  else:
293
289
  content = response.text
294
290
 
295
- document = self._create_document_from_url(url, content, result)
296
- return document
291
+ return self._create_document_from_url(url, content, result)
297
292
 
298
293
  except Exception as e:
299
294
  logger.warning(f"Error fetching {url}: {e}")
300
295
  return None
301
296
 
302
- # Create tasks for all URLs
303
- tasks = [fetch_url_async(result) for result in search_results]
304
-
305
- # Execute all tasks concurrently with delays
306
297
  documents = []
307
- for i, task in enumerate(tasks):
308
- if i > 0: # Add delay between requests (except for the first one)
298
+ for i, result in enumerate(search_results):
299
+ if i > 0:
309
300
  await asyncio.sleep(self.delay_between_requests)
310
301
 
311
- doc = await task
302
+ doc = await fetch_url_async(result)
312
303
  if doc is not None:
313
- # Apply chunking if enabled
314
304
  if self.chunk:
315
305
  chunked_docs = await self.chunk_documents_async([doc])
316
306
  documents.extend(chunked_docs)
317
307
  else:
318
308
  documents.append(doc)
319
309
 
320
- # Stop if we've reached max_results
321
310
  if len(documents) >= self.max_results:
322
311
  break
323
312
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agno
3
- Version: 2.3.15
3
+ Version: 2.3.16
4
4
  Summary: Agno: a lightweight library for building Multi-Agent Systems
5
5
  Author-email: Ashpreet Bedi <ashpreet@agno.com>
6
6
  Project-URL: homepage, https://agno.com
@@ -154,19 +154,19 @@ agno/knowledge/embedder/voyageai.py,sha256=E6RjQRaa5d2BHmkW09QG68ncrgBV2Vqq25ZR8
154
154
  agno/knowledge/reader/__init__.py,sha256=edjnCwyDjM9Q5JPMi4K9mll8a3CdV52iagUKAgGiaas,159
155
155
  agno/knowledge/reader/arxiv_reader.py,sha256=PtqP3bB4eZAYUlK9_ytPCFiy4icvMj7bIZNNVlBgY6U,2735
156
156
  agno/knowledge/reader/base.py,sha256=GLfOoy0W7rv8fgjVRUpVmInRgFFvFrPVsok_iJ9aSQ0,3780
157
- agno/knowledge/reader/csv_reader.py,sha256=aCGhFKTkSy4UJFFpPAWNot-9r0_n_2M2oucELaEOV9I,6468
158
- agno/knowledge/reader/docx_reader.py,sha256=edtri5z4PcdiVgjupxbmLmGnsMkvjFFAcnqOrZmWthU,3308
159
- agno/knowledge/reader/field_labeled_csv_reader.py,sha256=yVdfFGTkb7bhM3cpEukgeANu6UB2yrjU7T3BfWlXv0k,11605
157
+ agno/knowledge/reader/csv_reader.py,sha256=I_6Sczz4mvgXinkhHuzUAn33CARATx3DWJxliQThHPU,6321
158
+ agno/knowledge/reader/docx_reader.py,sha256=X6N0XSCP9g1YQ1FQ9l_fwib0AqK1TVEDC1nULs3W4KM,3224
159
+ agno/knowledge/reader/field_labeled_csv_reader.py,sha256=Y8pKgQz6yoMv1mhgfAIsrO-co21K_pu4YvZg1_GEAl0,11456
160
160
  agno/knowledge/reader/firecrawl_reader.py,sha256=SCbcRLkMrUb2WiC6SPuAoZULtHITa2VAmBtZlGmamGM,6855
161
- agno/knowledge/reader/json_reader.py,sha256=mh_SZE7jPaDO5KleFM0X7LsrYCSTimQ7qbvqh2YR8RE,3317
162
- agno/knowledge/reader/markdown_reader.py,sha256=QDg9oZTTRZkXf7D8eFrZ12t5gfXd5KWmJeH43HqNCHo,5284
163
- agno/knowledge/reader/pdf_reader.py,sha256=utUJiXhS9SXSZfsDg5dOo5Fr1PS8ODtOA5exTcS6LbY,17187
164
- agno/knowledge/reader/pptx_reader.py,sha256=_UQZlDf8XtA62uwYDqlJcU7X-KQ00lu4ZevXDCPnZ6k,3929
161
+ agno/knowledge/reader/json_reader.py,sha256=waMaL1V9X-8SzLmmqR14MRyPxzoerA9G5rTMTkvx0xc,3263
162
+ agno/knowledge/reader/markdown_reader.py,sha256=jvmeuRCfwI4eakMBB1MwVasfc7-FsKdXmbANmlfiLB0,5340
163
+ agno/knowledge/reader/pdf_reader.py,sha256=hETLLyy_pk2qIaMj4hqSyN_o22cO4v_pVr2XdoHSb-M,17200
164
+ agno/knowledge/reader/pptx_reader.py,sha256=yokphgHFZCGl_0XPEUmf6g5kJJq2wd015PooeEx9WpY,3845
165
165
  agno/knowledge/reader/reader_factory.py,sha256=1VGnZ4lpGiwa45dqfOyXmVB1dGb_4tOXpsKN9Vaqazs,11408
166
- agno/knowledge/reader/s3_reader.py,sha256=8tBUGw586m72FQReMux0iJoz8FhhLjpH5lxYamEilHk,3549
166
+ agno/knowledge/reader/s3_reader.py,sha256=3rB5PtCjYIck8v8hYhgsVnKp5TkQETE2T63HW8Ffl-E,3234
167
167
  agno/knowledge/reader/tavily_reader.py,sha256=kwQXj3QWSW-snv7R3VPValmEngc862UkhSo9lQrjXCk,7183
168
- agno/knowledge/reader/text_reader.py,sha256=pRsboWTo8RGt0tU_2T1poDpLb0jLaSj4i_kNMW9eqs4,5036
169
- agno/knowledge/reader/web_search_reader.py,sha256=QacYjE5u36zsUzdPdpXzLi0Zj550UhKltzG9HScgb7I,12598
168
+ agno/knowledge/reader/text_reader.py,sha256=2bmwxMaR88Xzh-y_SD61SbUo7KG05g0l1ixOAFUekco,4570
169
+ agno/knowledge/reader/web_search_reader.py,sha256=WDa0yXlqqIjHaLaN7SymHLqaQsrKtzzYyBDYhBPTjfA,12073
170
170
  agno/knowledge/reader/website_reader.py,sha256=8R_71uVjx_tHAWhvvHNQqyc4nysV6HksJBMLZITpwS8,19349
171
171
  agno/knowledge/reader/wikipedia_reader.py,sha256=HXcp17xMnSFSYMrvBQDVKWqzoitlHuWZIQtYUqnE818,3092
172
172
  agno/knowledge/reader/youtube_reader.py,sha256=z0Udminq7XkUpob129Oq_8w8SvmRVn0CkXHp2S0KUg4,2986
@@ -608,8 +608,8 @@ agno/workflow/step.py,sha256=voTmWWihLKDAMeLgYoie96KLCiVpxPFrZoFHEMhA6QM,75046
608
608
  agno/workflow/steps.py,sha256=rbfue2M4qYEkgHueojCY1-cB4i1MFjO-jX6uTxyoKwk,27118
609
609
  agno/workflow/types.py,sha256=OJXn4sYQ1VQ1H7UO_BwOO3_6q-OgcDX2XLDw3H4LIx0,20508
610
610
  agno/workflow/workflow.py,sha256=ylRulasAlJXDC90BpPaFxXNnlO_xcf5LxAbmcTU-Ltg,193481
611
- agno-2.3.15.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
612
- agno-2.3.15.dist-info/METADATA,sha256=b8wMpod_FDa0Q7AxuquuiY36XHIQojsIzFu6zhfj82A,31588
613
- agno-2.3.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
614
- agno-2.3.15.dist-info/top_level.txt,sha256=MKyeuVesTyOKIXUhc-d_tPa2Hrh0oTA4LM0izowpx70,5
615
- agno-2.3.15.dist-info/RECORD,,
611
+ agno-2.3.16.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
612
+ agno-2.3.16.dist-info/METADATA,sha256=yC4XU3rJgtlQKQi7UwuaHiizC6G9aoGuMiZw5FiCmqo,31588
613
+ agno-2.3.16.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
614
+ agno-2.3.16.dist-info/top_level.txt,sha256=MKyeuVesTyOKIXUhc-d_tPa2Hrh0oTA4LM0izowpx70,5
615
+ agno-2.3.16.dist-info/RECORD,,
File without changes