agno 2.3.7__py3-none-any.whl → 2.3.8__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/workflow/parallel.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import asyncio
2
2
  import warnings
3
3
  from concurrent.futures import ThreadPoolExecutor, as_completed
4
+ from contextvars import copy_context
4
5
  from copy import deepcopy
5
6
  from dataclasses import dataclass
6
7
  from typing import Any, AsyncIterator, Awaitable, Callable, Dict, Iterator, List, Optional, Union
@@ -267,8 +268,9 @@ class Parallel:
267
268
 
268
269
  with ThreadPoolExecutor(max_workers=len(self.steps)) as executor:
269
270
  # Submit all tasks with their original indices
271
+ # Use copy_context().run to propagate context variables to child threads
270
272
  future_to_index = {
271
- executor.submit(execute_step_with_index, indexed_step): indexed_step[0]
273
+ executor.submit(copy_context().run, execute_step_with_index, indexed_step): indexed_step[0]
272
274
  for indexed_step in indexed_steps
273
275
  }
274
276
 
@@ -449,7 +451,11 @@ class Parallel:
449
451
 
450
452
  with ThreadPoolExecutor(max_workers=len(self.steps)) as executor:
451
453
  # Submit all tasks
452
- futures = [executor.submit(execute_step_stream_with_index, indexed_step) for indexed_step in indexed_steps]
454
+ # Use copy_context().run to propagate context variables to child threads
455
+ futures = [
456
+ executor.submit(copy_context().run, execute_step_stream_with_index, indexed_step)
457
+ for indexed_step in indexed_steps
458
+ ]
453
459
 
454
460
  # Process events from queue as they arrive
455
461
  completed_steps = 0
agno/workflow/step.py CHANGED
@@ -644,7 +644,7 @@ class Step:
644
644
  session_state=session_state_copy, # Send a copy to the executor
645
645
  stream=True,
646
646
  stream_events=stream_events,
647
- yield_run_response=True,
647
+ yield_run_output=True,
648
648
  run_context=run_context,
649
649
  **kwargs,
650
650
  )
@@ -653,7 +653,7 @@ class Step:
653
653
  for event in response_stream:
654
654
  if isinstance(event, RunOutput) or isinstance(event, TeamRunOutput):
655
655
  active_executor_run_response = event
656
- break
656
+ continue
657
657
  # Only yield executor events if stream_executor_events is True
658
658
  if stream_executor_events:
659
659
  enriched_event = self._enrich_event_with_context(
@@ -1174,7 +1174,7 @@ class Step:
1174
1174
  stream=True,
1175
1175
  stream_events=stream_events,
1176
1176
  run_context=run_context,
1177
- yield_run_response=True,
1177
+ yield_run_output=True,
1178
1178
  **kwargs,
1179
1179
  )
1180
1180
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agno
3
- Version: 2.3.7
3
+ Version: 2.3.8
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
@@ -153,7 +153,7 @@ Requires-Dist: mcp>=1.9.2; extra == "mcp"
153
153
  Provides-Extra: mem0
154
154
  Requires-Dist: mem0ai; extra == "mem0"
155
155
  Provides-Extra: memori
156
- Requires-Dist: memorisdk==2.3.3; extra == "memori"
156
+ Requires-Dist: memorisdk==3.0.5; extra == "memori"
157
157
  Provides-Extra: newspaper
158
158
  Requires-Dist: newspaper4k; extra == "newspaper"
159
159
  Requires-Dist: lxml_html_clean; extra == "newspaper"
@@ -6,7 +6,7 @@ agno/media.py,sha256=eTfYb_pwhX_PCIVPSrW4VYRqmoxKABEF1aZClrVvQ30,16500
6
6
  agno/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  agno/table.py,sha256=9hHFnInNsrj0ZKtWjGDP5c6kbmNdtQvDDYT2j2CZJ6o,198
8
8
  agno/agent/__init__.py,sha256=s7S3FgsjZxuaabzi8L5n4aSH8IZAiZ7XaNNcySGR-EQ,1051
9
- agno/agent/agent.py,sha256=hxNxn2tyhR8q7gIGujTUiaSRRw9wfnfsr6-i_vodcsY,496743
9
+ agno/agent/agent.py,sha256=ljgnuhq2UTjMC6-hSSnb4eM66x8ItubRpNWvR4tpNtE,497820
10
10
  agno/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  agno/api/agent.py,sha256=fKlQ62E_C9Rjd7Zus3Gs3R1RG-IhzFV-ICpkb6SLqYc,932
12
12
  agno/api/api.py,sha256=gFhVjxJYkQsw8mBl2fhoStMPGlyJ37DJaqgUOwZVvQI,1021
@@ -60,21 +60,21 @@ agno/db/migrations/v1_to_v2.py,sha256=gj8deaEWUxOr0qJyMfjOpV3LxEh-otOSOxDckeUq0q
60
60
  agno/db/migrations/versions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
61
61
  agno/db/migrations/versions/v2_3_0.py,sha256=WikuOtgQs_Tq8o3JndCMG6HAMzKvz4GVth9V5V5RuvE,35161
62
62
  agno/db/mongo/__init__.py,sha256=NG2WC2jE5PX1kMXTYCVHjhomf5DAJgvzSj45QHdvl2E,466
63
- agno/db/mongo/async_mongo.py,sha256=7s26a6NH5y6Wdb_8vSRG4cHyk2rzkx6rhbFAbizqV1M,108485
64
- agno/db/mongo/mongo.py,sha256=zQG3uyiBgJZQlnkBOth9EXc8KedKr14p7gRkyMn3HNM,99320
63
+ agno/db/mongo/async_mongo.py,sha256=0jh36UmtYqeQOyMT9MB-2GE7aqCUEN0jGWJzuv8ZfCo,107154
64
+ agno/db/mongo/mongo.py,sha256=GHeDRw2VhhuTDtLcXpsf2UMU_WlJbJCc6n131Omn3Bw,98457
65
65
  agno/db/mongo/schemas.py,sha256=Q3JrMZ3zCKZcHilh5CoQePI5d5dRjHAtjs5QuWrxiWc,3098
66
66
  agno/db/mongo/utils.py,sha256=1KrbF1PR_707e9SqXZcquaw_N7mRYm9HjJnvYwBjgG8,9921
67
67
  agno/db/mysql/__init__.py,sha256=ohBMZ1E6ctioEF0XX5PjC4LtUQrc6lFkjsE4ojyXA8g,63
68
- agno/db/mysql/mysql.py,sha256=Ve4ojP3slr_qMxXQ0hi4XDQPtOtgm2jBR4CEg5ao6j8,121370
68
+ agno/db/mysql/mysql.py,sha256=io5bOVEXvcM85DJsJhYUf5w4nCeeF6TtU9ypZAM3eiQ,120209
69
69
  agno/db/mysql/schemas.py,sha256=_4p2IWt0zVq-fHuxFhEpWLWxlp3QPKk8xtNMiB1TNOY,9067
70
70
  agno/db/mysql/utils.py,sha256=PdqN-SxM-ox8HU9CZyxzvs2D1FE2vdZFVCyFgFcQsyU,12366
71
71
  agno/db/postgres/__init__.py,sha256=Ojk00nTCzQFiH2ViD7KIBjgpkTKLRNPCwWnuXMKtNXY,154
72
- agno/db/postgres/async_postgres.py,sha256=TQTS6u15RNaQFwvgU6lGxo8eJavElw9TlBO6lPq7amw,107237
73
- agno/db/postgres/postgres.py,sha256=ouC5XrcGL95R30OEEjfdtMIb7jdJTjS_l6xzf1kS2cw,118023
72
+ agno/db/postgres/async_postgres.py,sha256=pZAVNSk41_nD5B4DtUJ1jDX1l2ZDe-tAdkhGR-ru5pQ,106024
73
+ agno/db/postgres/postgres.py,sha256=rbkI4YJQYHqryMrpZOLtP07i8izbcschg7XQZlVI160,116664
74
74
  agno/db/postgres/schemas.py,sha256=G0BRG9GcUcO43-TU52nKSEog8v3tdJNwIhEjts9dCns,8405
75
75
  agno/db/postgres/utils.py,sha256=UE3UQZ-h7fADAKBsX4BWcDka54YNROEpBrlfTmDvpqc,15471
76
76
  agno/db/redis/__init__.py,sha256=rZWeZ4CpVeKP-enVQ-SRoJ777i0rdGNgoNDRS9gsfAc,63
77
- agno/db/redis/redis.py,sha256=CDv2no3UEycJkKESgsggDyIFfM2rToDp_Gcb2yZuNUA,82524
77
+ agno/db/redis/redis.py,sha256=WgP-f8OfPTUEISY8O8meYbcJsFA3rpmXEthVQZRKdoM,82222
78
78
  agno/db/redis/schemas.py,sha256=90rDTGUyN1kYZ2KgeFjyOu1SwqYoTc1ErePxGqFlbj0,5217
79
79
  agno/db/redis/utils.py,sha256=vQpLI-V442B6m0q_l8IVEJctLD4P-kawbCm5A_Fnotg,11326
80
80
  agno/db/schemas/__init__.py,sha256=g72Zr5_nm00yXHStv4pf9PG9bGLKXEK7Av6YQtrDbCQ,147
@@ -85,12 +85,12 @@ agno/db/schemas/memory.py,sha256=dA7It1cN60dId-GpowmKTORy4Q6r9L49ZpGnnZkXmds,212
85
85
  agno/db/schemas/metrics.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
86
86
  agno/db/singlestore/__init__.py,sha256=dufbaod8ZZIeZIVi0hYJQ8Eu2DfIfWdIy00cpqAsx9U,87
87
87
  agno/db/singlestore/schemas.py,sha256=gnCpoRAztbPiZOCfx9MGBx1sySijwogajSjxIeGpsaA,8923
88
- agno/db/singlestore/singlestore.py,sha256=Q0MhS41gCm4xgtoHuLQjvUEHJYurqtlJD7aP5_46rx0,118882
88
+ agno/db/singlestore/singlestore.py,sha256=mShU-mGdOamf82VihF96e1tVjzSNol8Zs94f0S--HLs,118169
89
89
  agno/db/singlestore/utils.py,sha256=w2FVFIBpFJK6nKJVt1sgv9N-esmfpGY_8ViFRI69I2I,13677
90
90
  agno/db/sqlite/__init__.py,sha256=09V3i4y0-tBjt60--57ivZ__SaaS67GCsDT4Apzv-5Y,138
91
- agno/db/sqlite/async_sqlite.py,sha256=Amv3zha6FTHCuwAuYUzw0jGoIbNC5s6sv6QTJoMRPEw,123366
91
+ agno/db/sqlite/async_sqlite.py,sha256=62P-HurucmK3pk5aM8vjqHbHuuor5pDSuJW-vCLyE74,121942
92
92
  agno/db/sqlite/schemas.py,sha256=1lrIFWEhXYZJIlQYEnOl3XLp3UfsE5ILj2HUPmOf3cg,8265
93
- agno/db/sqlite/sqlite.py,sha256=3jiDLjs1vM3sTd6526v4JJhrpjL6cMaW9Xik0nTA57k,120340
93
+ agno/db/sqlite/sqlite.py,sha256=XjRJAmClEzYS6itHuPRD6RB9-iTtHgDkBmNLKy2vJOM,119118
94
94
  agno/db/sqlite/utils.py,sha256=sgp-KR7A5naTqTORHYHyP_21hG9LffOzCgqbx5S8RfE,15171
95
95
  agno/db/surrealdb/__init__.py,sha256=C8qp5-Nx9YnSmgKEtGua-sqG_ntCXONBw1qqnNyKPqI,75
96
96
  agno/db/surrealdb/metrics.py,sha256=oKDRyjRQ6KR3HaO8zDHQLVMG7-0NDkOFOKX5I7mD5FA,10336
@@ -181,7 +181,7 @@ agno/memory/strategies/base.py,sha256=13xCiBPtFUrpDaWbiz8zmNGjopT4VSIkcHVxfnvJ4W
181
181
  agno/memory/strategies/summarize.py,sha256=4M9zWTsooC3EtHpZoC7Z-yFaQgQoebRMNfZPitdsvB0,7307
182
182
  agno/memory/strategies/types.py,sha256=b3N5jOG_dM4AxT7vGagFIc9sqUUjxFtRHSoH4_AhEx8,1225
183
183
  agno/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
184
- agno/models/base.py,sha256=3ZZpyACrsSjhpK3YOjRaLXR2hQFSQnKGpIKWPVGj9Ww,108826
184
+ agno/models/base.py,sha256=_ldhrYebV77fEzHtnILNILPW2aG4KwMjsT-THnYDwHA,114403
185
185
  agno/models/defaults.py,sha256=1_fe4-ZbNriE8BgqxVRVi4KGzEYxYKYsz4hn6CZNEEM,40
186
186
  agno/models/message.py,sha256=5-Nvqd6rXNca37yiVVQgBJY4w_gudVawg-ZQHcUX4SE,19763
187
187
  agno/models/metrics.py,sha256=81IILXZwGmOTiWK003bi5mg4bM1f4LCWbwyamjFzp18,4500
@@ -247,7 +247,7 @@ agno/models/ollama/chat.py,sha256=Szc8rEWRvQ2CW50V5xAuccX4Ozc1BAV9wUPbFJhY_J8,16
247
247
  agno/models/openai/__init__.py,sha256=OssVgQRpsriU6aJZ3lIp_jFuqvX6y78L4Fd3uTlmI3E,225
248
248
  agno/models/openai/chat.py,sha256=KZupbtQxrNiHH9m-y6hrldLq0dGe0XYjvShJQsz-Kjw,40096
249
249
  agno/models/openai/like.py,sha256=wmw9PfAVqluBs4MMY73dgjelKn1yl5JDKyCRvaNFjFw,745
250
- agno/models/openai/responses.py,sha256=270XSJx6HaYi_vn9ENxZ_xL22x3tqmVChmHsm4z6coA,46643
250
+ agno/models/openai/responses.py,sha256=SahBoPgh8KFhRIE1QymhNhQoydFHFEmpBWxmFuixT88,46702
251
251
  agno/models/openrouter/__init__.py,sha256=ZpZhNyy_EGSXp58uC9e2iyjnxBctql7GaY8rUG-599I,90
252
252
  agno/models/openrouter/openrouter.py,sha256=fdFZy-1ZwvDKlO0b9TiXdtNe5ScSU4RJSYw08DojK_4,3284
253
253
  agno/models/perplexity/__init__.py,sha256=JNmOElDLwcZ9_Lk5owkEdgwmAhaH3YJ-VJqOI8rgp5c,90
@@ -284,7 +284,7 @@ agno/os/interfaces/base.py,sha256=vXkr1tRjWHTcmBlQFzvQjqURLhObmFtUAx82uij_j48,54
284
284
  agno/os/interfaces/a2a/__init__.py,sha256=Fs7--dx9drvtVS9QjsCCm0P7c-hJ7TzU8gNwKTQsZDA,62
285
285
  agno/os/interfaces/a2a/a2a.py,sha256=UiTX-GOuXxp1CQzRgtmgSSYNn2iFC_vKYnC37OidygM,1337
286
286
  agno/os/interfaces/a2a/router.py,sha256=OpNCHhYoCUyfcuRtiOdvUrUZnxfFB1jhMWraLA85XMg,10985
287
- agno/os/interfaces/a2a/utils.py,sha256=rTn9x0UGbX53EiAsljf87PmzYwLuvqaobUWpCn35ut0,39285
287
+ agno/os/interfaces/a2a/utils.py,sha256=J_m_l3noqfjjRRQ-kQQMAab1CnvDPh-M1regJ9_o5Yg,39286
288
288
  agno/os/interfaces/agui/__init__.py,sha256=1zrGICk4roXUINwSFZfqH6sBsbHmD5KjGYVJMGg4fKQ,66
289
289
  agno/os/interfaces/agui/agui.py,sha256=PKGoDDbtQFmEC0zRwZmsjS_5t9bJWJ-ZGwxEQsu9P-U,1415
290
290
  agno/os/interfaces/agui/router.py,sha256=U2w26v2oOCCOl5t5XduQChO3_eJBNH4Mk9BH77KKJag,5257
@@ -298,7 +298,7 @@ agno/os/interfaces/whatsapp/router.py,sha256=K7Ex4Xq-4hPcRKoVxBkb8KoGxH6WXC1bubd
298
298
  agno/os/interfaces/whatsapp/security.py,sha256=0GYdG28yeSpV47nMWASaFSTiGESSstcFAeL6amobvFE,1772
299
299
  agno/os/interfaces/whatsapp/whatsapp.py,sha256=tNJncEu_hm0lFOHbjaSoz5-VIKORR_pyW26cseBLfbs,989
300
300
  agno/os/middleware/__init__.py,sha256=EYsNzeixFgL3n8kepKWXT42fTTmrNyD8b8rOdXecMRI,94
301
- agno/os/middleware/jwt.py,sha256=xw9jQkVFMTTzUVird1k-egAYBmPd174L06YflYCvB5Q,9468
301
+ agno/os/middleware/jwt.py,sha256=O3O_h7WeO7xN6uj4NiBMgz9tTvJpfX2c-f4w4-ykBNA,9575
302
302
  agno/os/routers/__init__.py,sha256=du4LO9aZwiY1t59VcV9M6wiAfftFFlUZc-YXsTGy9LI,97
303
303
  agno/os/routers/health.py,sha256=AO3ec6Xi1wXOwUUFJhEcM45488qu6aZRJTwF2GLz6Ak,992
304
304
  agno/os/routers/home.py,sha256=xe8DYJkRgad55qiza0lHt8pUIV5PLSyu2MkybjuPDDE,1708
@@ -346,7 +346,7 @@ agno/session/summary.py,sha256=9JnDyQyggckd3zx6L8Q5f-lglZvrFQxvPjGU8gLCgR4,10292
346
346
  agno/session/team.py,sha256=-MkB6qQCrnXLKko8L5s9fJOWPsjeK5Gx0SXEPoOwSFQ,13437
347
347
  agno/session/workflow.py,sha256=nPHnh1N0SJby5JRjysCUI-kTDCelQMFfqosEnnLzPIg,19690
348
348
  agno/team/__init__.py,sha256=toHidBOo5M3n_TIVtIKHgcDbLL9HR-_U-YQYuIt_XtE,847
349
- agno/team/team.py,sha256=55zfNQ7JvK2XNovOsABhgkjZ0xtHcX80p1d6ZT5gYnY,434720
349
+ agno/team/team.py,sha256=TOc7jPk0sTVqV-3nm6By9QlX_632fsJtn-FjIvAC2Co,434423
350
350
  agno/tools/__init__.py,sha256=jNll2sELhPPbqm5nPeT4_uyzRO2_KRTW-8Or60kioS0,210
351
351
  agno/tools/agentql.py,sha256=S82Z9aTNr-E5wnA4fbFs76COljJtiQIjf2grjz3CkHU,4104
352
352
  agno/tools/airflow.py,sha256=uf2rOzZpSU64l_qRJ5Raku-R3Gky-uewmYkh6W0-oxg,2610
@@ -405,7 +405,6 @@ agno/tools/local_file_system.py,sha256=wWyhM5-lqDgDO_YNzRA8ekG-m2n89k8fWr8M1BWiQ
405
405
  agno/tools/lumalab.py,sha256=6WnZXbThKY2jL9zLswq1PVsbFm2jz81qshWqBZi59oo,6808
406
406
  agno/tools/mcp_toolbox.py,sha256=z6qZqUOmYueBoiQtTqRWV9GohhCAd3s5D4GyqtezHeY,12760
407
407
  agno/tools/mem0.py,sha256=5W5pZwJmBTt-_l4nvBdNQHavXFSKV9mVdJg5aso4JBI,7680
408
- agno/tools/memori.py,sha256=tubBYj0rQFbBXadhWxwTjjmb3Rnims536AVPkGdCMcw,13181
409
408
  agno/tools/memory.py,sha256=vpMoKtCqs3m6vkuqmZ4fW9IRf1OhXHQGGaq3exJK0Xo,18449
410
409
  agno/tools/mlx_transcribe.py,sha256=kuiYZAM5ZAdkiOfFdbGJsCb0gacnJRtSTFzuX8eWGLw,6379
411
410
  agno/tools/models_labs.py,sha256=E91DZDJOU2ldgI3U_ueFiZcXLLWfbh0MsZ2pYP9c0eQ,7933
@@ -457,7 +456,7 @@ agno/tools/website.py,sha256=jzcXLEsCfGIEqV88OLePiCEjfDoAbXQDCPAr9JbP8cU,1798
457
456
  agno/tools/webtools.py,sha256=5Dyp8U2ov32DkJMpj-7plzQZcfnCL7wlXbQIfRh8jmw,1305
458
457
  agno/tools/whatsapp.py,sha256=DaDyNogtbgrinJohfU7CmVQJSZsZO-00XUbRJegN_eE,11055
459
458
  agno/tools/wikipedia.py,sha256=u6xhc5wkEGcjng4leVCmo28o6Ti7OzDgRqiOqTMnmoc,2277
460
- agno/tools/workflow.py,sha256=4EJlPWEf1Y9sGK_cWENevh3NbdKnGZjzW1cJOJVtI30,12556
459
+ agno/tools/workflow.py,sha256=8__QqwLQ0uWXiwk99SoLl2rC3Sr_5nJur6CeGeU0xx4,12744
461
460
  agno/tools/x.py,sha256=gaFCel9FyDPnKLL03nkjsc9NGsfQOsS92XByp3hdwMo,14495
462
461
  agno/tools/yfinance.py,sha256=1bPUMZ7BWxEyblJLxyhzV6y4O-EBmljUM_aKfr0cf0o,11540
463
462
  agno/tools/youtube.py,sha256=H6SbBfWrmkazR8QrgXvLpqBOGAy4eHbRxkgTRJEt91Q,6667
@@ -585,14 +584,14 @@ agno/workflow/__init__.py,sha256=Ze2j811jwnsS8Sjv6u0Ap4l7Pyw_ivRof1uBYNJhb1w,609
585
584
  agno/workflow/agent.py,sha256=fKLB4kop7YYFeM1e-d3IzvVPsVF5cLNX6Z0gPn81ZR4,12170
586
585
  agno/workflow/condition.py,sha256=2zKLgrvwa3Up4aDKWSACOa7vZD0lSLX_lUW-LYJa0Yc,33939
587
586
  agno/workflow/loop.py,sha256=nDBXCRMhXHaRb-jnIbtEgY78h69zCdUrHwiJ6VXl5zo,33986
588
- agno/workflow/parallel.py,sha256=JusRfiYesmjwM2k0d6j3Ulm1_dVD4XupeRjuQFqXX5I,37714
587
+ agno/workflow/parallel.py,sha256=yTtc6dkNmIGU6zOI_7EZ3mATrJZFEArUUcUG47L-DwE,38007
589
588
  agno/workflow/router.py,sha256=HQDOnErjtiQdY_EskJBV_mZq_k6d1gH6JJPIM2Yfelw,32016
590
- agno/workflow/step.py,sha256=2BAZQI9nNs-qR0_r1I4WSuIB_sOXI7Q-OeQtb-bzSXU,74268
589
+ agno/workflow/step.py,sha256=BbzpETSMtlDkUsm47-TwhfGAgRM6TcWnp-orIJgOTQY,74267
591
590
  agno/workflow/steps.py,sha256=rbfue2M4qYEkgHueojCY1-cB4i1MFjO-jX6uTxyoKwk,27118
592
591
  agno/workflow/types.py,sha256=LObJ0VkUtepZ-uewv3j283S4hrCXy0eCplQzIzRG1ic,19175
593
592
  agno/workflow/workflow.py,sha256=6khBK6tbO9i2aSovduwNoQUfbcyEdoKyF4F86Uyj4gM,193181
594
- agno-2.3.7.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
595
- agno-2.3.7.dist-info/METADATA,sha256=RZjF1ZE-fHQ_aXUeGZjrU5GO0HZhfkB4kiQ5zYHboE0,31018
596
- agno-2.3.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
597
- agno-2.3.7.dist-info/top_level.txt,sha256=MKyeuVesTyOKIXUhc-d_tPa2Hrh0oTA4LM0izowpx70,5
598
- agno-2.3.7.dist-info/RECORD,,
593
+ agno-2.3.8.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
594
+ agno-2.3.8.dist-info/METADATA,sha256=ANDODVqjcZLqQzSxWL-lXsxjWQUUjUl8XThT9VSy4Og,31018
595
+ agno-2.3.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
596
+ agno-2.3.8.dist-info/top_level.txt,sha256=MKyeuVesTyOKIXUhc-d_tPa2Hrh0oTA4LM0izowpx70,5
597
+ agno-2.3.8.dist-info/RECORD,,
agno/tools/memori.py DELETED
@@ -1,339 +0,0 @@
1
- import json
2
- from typing import Any, Dict, List, Optional
3
-
4
- from agno.tools.toolkit import Toolkit
5
- from agno.utils.log import log_debug, log_error, log_info, log_warning
6
-
7
- try:
8
- from memori import Memori, create_memory_tool
9
- except ImportError:
10
- raise ImportError("`memorisdk` package not found. Please install it with `pip install memorisdk`")
11
-
12
-
13
- class MemoriTools(Toolkit):
14
- """
15
- Memori ToolKit for Agno Agents and Teams, providing persistent memory capabilities.
16
-
17
- This toolkit integrates Memori's memory system with Agno, allowing Agents and Teams to:
18
- - Store and retrieve conversation history
19
- - Search through past interactions
20
- - Maintain user preferences and context
21
- - Build long-term memory across sessions
22
-
23
- Requirements:
24
- - pip install memorisdk
25
- - Database connection string (SQLite, PostgreSQL, etc.)
26
-
27
- Example:
28
- ```python
29
- from agno.tools.memori import MemoriTools
30
-
31
- # Initialize with SQLite (default)
32
- memori_tools = MemoriTools(
33
- database_connect="sqlite:///agent_memory.db",
34
- namespace="my_agent",
35
- auto_ingest=True # Automatically ingest conversations
36
- )
37
-
38
- # Add to agent
39
- agent = Agent(
40
- model=OpenAIChat(),
41
- tools=[memori_tools],
42
- description="An AI assistant with persistent memory"
43
- )
44
- ```
45
- """
46
-
47
- def __init__(
48
- self,
49
- database_connect: Optional[str] = None,
50
- namespace: Optional[str] = None,
51
- conscious_ingest: bool = True,
52
- auto_ingest: bool = True,
53
- verbose: bool = False,
54
- config: Optional[Dict[str, Any]] = None,
55
- auto_enable: bool = True,
56
- enable_search_memory: bool = True,
57
- enable_record_conversation: bool = True,
58
- enable_get_memory_stats: bool = True,
59
- all: bool = False,
60
- **kwargs,
61
- ):
62
- """
63
- Initialize Memori toolkit.
64
-
65
- Args:
66
- database_connect: Database connection string (e.g., "sqlite:///memory.db")
67
- namespace: Namespace for organizing memories (e.g., "agent_v1", "user_session")
68
- conscious_ingest: Whether to use conscious memory ingestion
69
- auto_ingest: Whether to automatically ingest conversations into memory
70
- verbose: Enable verbose logging from Memori
71
- config: Additional Memori configuration
72
- auto_enable: Automatically enable the memory system on initialization
73
- **kwargs: Additional arguments passed to Toolkit base class
74
- """
75
- tools: List[Any] = []
76
- if all or enable_search_memory:
77
- tools.append(self.search_memory)
78
- if all or enable_record_conversation:
79
- tools.append(self.record_conversation)
80
- if all or enable_get_memory_stats:
81
- tools.append(self.get_memory_stats)
82
-
83
- super().__init__(name="memori_tools", tools=tools, **kwargs)
84
-
85
- # Set default database connection if not provided
86
- if not database_connect:
87
- sqlite_db = "sqlite:///agno_memori_memory.db"
88
- log_info(f"No database connection provided, using default SQLite database at {sqlite_db}")
89
- database_connect = sqlite_db
90
-
91
- self.database_connect = database_connect
92
- self.namespace = namespace or "agno_default"
93
- self.conscious_ingest = conscious_ingest
94
- self.auto_ingest = auto_ingest
95
- self.verbose = verbose
96
- self.config = config or {}
97
-
98
- try:
99
- # Initialize Memori memory system
100
- log_debug(f"Initializing Memori with database: {self.database_connect}")
101
- self.memory_system = Memori(
102
- database_connect=self.database_connect,
103
- conscious_ingest=self.conscious_ingest,
104
- auto_ingest=self.auto_ingest,
105
- verbose=self.verbose,
106
- namespace=self.namespace,
107
- **self.config,
108
- )
109
-
110
- # Enable the memory system if auto_enable is True
111
- if auto_enable:
112
- self.memory_system.enable()
113
- log_debug("Memori memory system enabled")
114
-
115
- # Create the memory tool for internal use
116
- self._memory_tool = create_memory_tool(self.memory_system)
117
-
118
- except Exception as e:
119
- log_error(f"Failed to initialize Memori: {e}")
120
- raise ConnectionError("Failed to initialize Memori memory system") from e
121
-
122
- def search_memory(
123
- self,
124
- query: str,
125
- limit: Optional[int] = None,
126
- ) -> str:
127
- """
128
- Search the Agent's memory for past conversations and information.
129
-
130
- This performs semantic search across all stored memories to find
131
- relevant information based on the provided query.
132
-
133
- Args:
134
- query: What to search for in memory (e.g., "past conversations about AI", "user preferences")
135
- limit: Maximum number of results to return (optional)
136
-
137
- Returns:
138
- str: JSON-encoded search results or error message
139
-
140
- Example:
141
- search_memory("user's favorite programming languages")
142
- search_memory("previous discussions about machine learning")
143
- """
144
- try:
145
- if not query.strip():
146
- return json.dumps({"error": "Please provide a search query"})
147
-
148
- log_debug(f"Searching memory for: {query}")
149
-
150
- # Execute search using Memori's memory tool
151
- result = self._memory_tool.execute(query=query.strip())
152
-
153
- if result:
154
- # If limit is specified, truncate results
155
- if limit and isinstance(result, list):
156
- result = result[:limit]
157
-
158
- return json.dumps(
159
- {
160
- "success": True,
161
- "query": query,
162
- "results": result,
163
- "count": len(result) if isinstance(result, list) else 1,
164
- }
165
- )
166
- else:
167
- return json.dumps(
168
- {
169
- "success": True,
170
- "query": query,
171
- "results": [],
172
- "count": 0,
173
- "message": "No relevant memories found",
174
- }
175
- )
176
-
177
- except Exception as e:
178
- log_error(f"Error searching memory: {e}")
179
- return json.dumps({"success": False, "error": f"Memory search error: {str(e)}"})
180
-
181
- def record_conversation(self, content: str) -> str:
182
- """
183
- Add important information or facts to memory.
184
-
185
- Use this tool to store important information, user preferences, facts, or context that should be remembered
186
- for future conversations.
187
-
188
- Args:
189
- content: The information/facts to store in memory
190
-
191
- Returns:
192
- str: Success message or error details
193
-
194
- Example:
195
- record_conversation("User prefers Python over JavaScript")
196
- record_conversation("User is working on an e-commerce project using Django")
197
- record_conversation("User's name is John and they live in NYC")
198
- """
199
- try:
200
- if not content.strip():
201
- return json.dumps({"success": False, "error": "Content cannot be empty"})
202
-
203
- log_debug(f"Adding conversation: {content}")
204
-
205
- # Extract the actual AI response from the agent's conversation history
206
- ai_output = "I've noted this information and will remember it."
207
-
208
- self.memory_system.record_conversation(user_input=content, ai_output=str(ai_output))
209
- return json.dumps(
210
- {
211
- "success": True,
212
- "message": "Memory added successfully via conversation recording",
213
- "content_length": len(content),
214
- }
215
- )
216
-
217
- except Exception as e:
218
- log_error(f"Error adding memory: {e}")
219
- return json.dumps({"success": False, "error": f"Failed to add memory: {str(e)}"})
220
-
221
- def get_memory_stats(
222
- self,
223
- ) -> str:
224
- """
225
- Get statistics about the memory system.
226
-
227
- Returns information about the current state of the memory system,
228
- including total memories, memory distribution by retention type
229
- (short-term vs long-term), and system configuration.
230
-
231
- Returns:
232
- str: JSON-encoded memory statistics
233
-
234
- Example:
235
- Returns statistics like:
236
- {
237
- "success": true,
238
- "total_memories": 42,
239
- "memories_by_retention": {
240
- "short_term": 5,
241
- "long_term": 37
242
- },
243
- "namespace": "my_agent",
244
- "conscious_ingest": true,
245
- "auto_ingest": true,
246
- "memory_system_enabled": true
247
- }
248
- """
249
- try:
250
- log_debug("Retrieving memory statistics")
251
-
252
- # Base stats about the system configuration
253
- stats = {
254
- "success": True,
255
- "namespace": self.namespace,
256
- "database_connect": self.database_connect,
257
- "conscious_ingest": self.conscious_ingest,
258
- "auto_ingest": self.auto_ingest,
259
- "verbose": self.verbose,
260
- "memory_system_enabled": hasattr(self.memory_system, "_enabled") and self.memory_system._enabled,
261
- }
262
-
263
- # Get Memori's built-in memory statistics
264
- try:
265
- if hasattr(self.memory_system, "get_memory_stats"):
266
- # Use the get_memory_stats method as shown in the example
267
- memori_stats = self.memory_system.get_memory_stats()
268
-
269
- # Add the Memori-specific stats to our response
270
- if isinstance(memori_stats, dict):
271
- # Include total memories
272
- if "total_memories" in memori_stats:
273
- stats["total_memories"] = memori_stats["total_memories"]
274
-
275
- # Include memory distribution by retention type
276
- if "memories_by_retention" in memori_stats:
277
- stats["memories_by_retention"] = memori_stats["memories_by_retention"]
278
-
279
- # Also add individual counts for convenience
280
- retention_info = memori_stats["memories_by_retention"]
281
- stats["short_term_memories"] = retention_info.get("short_term", 0)
282
- stats["long_term_memories"] = retention_info.get("long_term", 0)
283
-
284
- # Include any other available stats
285
- for key, value in memori_stats.items():
286
- if key not in stats:
287
- stats[key] = value
288
-
289
- log_debug(
290
- f"Retrieved memory stats: total={stats.get('total_memories', 0)}, "
291
- f"short_term={stats.get('short_term_memories', 0)}, "
292
- f"long_term={stats.get('long_term_memories', 0)}"
293
- )
294
-
295
- else:
296
- log_debug("get_memory_stats method not available, providing basic stats only")
297
- stats["total_memories"] = 0
298
- stats["memories_by_retention"] = {"short_term": 0, "long_term": 0}
299
- stats["short_term_memories"] = 0
300
- stats["long_term_memories"] = 0
301
-
302
- except Exception as e:
303
- log_debug(f"Could not retrieve detailed memory stats: {e}")
304
- # Provide basic stats if detailed stats fail
305
- stats["total_memories"] = 0
306
- stats["memories_by_retention"] = {"short_term": 0, "long_term": 0}
307
- stats["short_term_memories"] = 0
308
- stats["long_term_memories"] = 0
309
- stats["stats_warning"] = "Detailed memory statistics not available"
310
-
311
- return json.dumps(stats)
312
-
313
- except Exception as e:
314
- log_error(f"Error getting memory stats: {e}")
315
- return json.dumps({"success": False, "error": f"Failed to get memory statistics: {str(e)}"})
316
-
317
- def enable_memory_system(self) -> bool:
318
- """Enable the Memori memory system."""
319
- try:
320
- self.memory_system.enable()
321
- log_debug("Memori memory system enabled")
322
- return True
323
- except Exception as e:
324
- log_error(f"Failed to enable memory system: {e}")
325
- return False
326
-
327
- def disable_memory_system(self) -> bool:
328
- """Disable the Memori memory system."""
329
- try:
330
- if hasattr(self.memory_system, "disable"):
331
- self.memory_system.disable()
332
- log_debug("Memori memory system disabled")
333
- return True
334
- else:
335
- log_warning("Memory system disable method not available")
336
- return False
337
- except Exception as e:
338
- log_error(f"Failed to disable memory system: {e}")
339
- return False
File without changes