agno 2.1.2__py3-none-any.whl → 2.3.13__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.
Files changed (314) hide show
  1. agno/agent/agent.py +5540 -2273
  2. agno/api/api.py +2 -0
  3. agno/api/os.py +1 -1
  4. agno/compression/__init__.py +3 -0
  5. agno/compression/manager.py +247 -0
  6. agno/culture/__init__.py +3 -0
  7. agno/culture/manager.py +956 -0
  8. agno/db/async_postgres/__init__.py +3 -0
  9. agno/db/base.py +689 -6
  10. agno/db/dynamo/dynamo.py +933 -37
  11. agno/db/dynamo/schemas.py +174 -10
  12. agno/db/dynamo/utils.py +63 -4
  13. agno/db/firestore/firestore.py +831 -9
  14. agno/db/firestore/schemas.py +51 -0
  15. agno/db/firestore/utils.py +102 -4
  16. agno/db/gcs_json/gcs_json_db.py +660 -12
  17. agno/db/gcs_json/utils.py +60 -26
  18. agno/db/in_memory/in_memory_db.py +287 -14
  19. agno/db/in_memory/utils.py +60 -2
  20. agno/db/json/json_db.py +590 -14
  21. agno/db/json/utils.py +60 -26
  22. agno/db/migrations/manager.py +199 -0
  23. agno/db/migrations/v1_to_v2.py +43 -13
  24. agno/db/migrations/versions/__init__.py +0 -0
  25. agno/db/migrations/versions/v2_3_0.py +938 -0
  26. agno/db/mongo/__init__.py +15 -1
  27. agno/db/mongo/async_mongo.py +2760 -0
  28. agno/db/mongo/mongo.py +879 -11
  29. agno/db/mongo/schemas.py +42 -0
  30. agno/db/mongo/utils.py +80 -8
  31. agno/db/mysql/__init__.py +2 -1
  32. agno/db/mysql/async_mysql.py +2912 -0
  33. agno/db/mysql/mysql.py +946 -68
  34. agno/db/mysql/schemas.py +72 -10
  35. agno/db/mysql/utils.py +198 -7
  36. agno/db/postgres/__init__.py +2 -1
  37. agno/db/postgres/async_postgres.py +2579 -0
  38. agno/db/postgres/postgres.py +942 -57
  39. agno/db/postgres/schemas.py +81 -18
  40. agno/db/postgres/utils.py +164 -2
  41. agno/db/redis/redis.py +671 -7
  42. agno/db/redis/schemas.py +50 -0
  43. agno/db/redis/utils.py +65 -7
  44. agno/db/schemas/__init__.py +2 -1
  45. agno/db/schemas/culture.py +120 -0
  46. agno/db/schemas/evals.py +1 -0
  47. agno/db/schemas/memory.py +17 -2
  48. agno/db/singlestore/schemas.py +63 -0
  49. agno/db/singlestore/singlestore.py +949 -83
  50. agno/db/singlestore/utils.py +60 -2
  51. agno/db/sqlite/__init__.py +2 -1
  52. agno/db/sqlite/async_sqlite.py +2911 -0
  53. agno/db/sqlite/schemas.py +62 -0
  54. agno/db/sqlite/sqlite.py +965 -46
  55. agno/db/sqlite/utils.py +169 -8
  56. agno/db/surrealdb/__init__.py +3 -0
  57. agno/db/surrealdb/metrics.py +292 -0
  58. agno/db/surrealdb/models.py +334 -0
  59. agno/db/surrealdb/queries.py +71 -0
  60. agno/db/surrealdb/surrealdb.py +1908 -0
  61. agno/db/surrealdb/utils.py +147 -0
  62. agno/db/utils.py +2 -0
  63. agno/eval/__init__.py +10 -0
  64. agno/eval/accuracy.py +75 -55
  65. agno/eval/agent_as_judge.py +861 -0
  66. agno/eval/base.py +29 -0
  67. agno/eval/performance.py +16 -7
  68. agno/eval/reliability.py +28 -16
  69. agno/eval/utils.py +35 -17
  70. agno/exceptions.py +27 -2
  71. agno/filters.py +354 -0
  72. agno/guardrails/prompt_injection.py +1 -0
  73. agno/hooks/__init__.py +3 -0
  74. agno/hooks/decorator.py +164 -0
  75. agno/integrations/discord/client.py +1 -1
  76. agno/knowledge/chunking/agentic.py +13 -10
  77. agno/knowledge/chunking/fixed.py +4 -1
  78. agno/knowledge/chunking/semantic.py +9 -4
  79. agno/knowledge/chunking/strategy.py +59 -15
  80. agno/knowledge/embedder/fastembed.py +1 -1
  81. agno/knowledge/embedder/nebius.py +1 -1
  82. agno/knowledge/embedder/ollama.py +8 -0
  83. agno/knowledge/embedder/openai.py +8 -8
  84. agno/knowledge/embedder/sentence_transformer.py +6 -2
  85. agno/knowledge/embedder/vllm.py +262 -0
  86. agno/knowledge/knowledge.py +1618 -318
  87. agno/knowledge/reader/base.py +6 -2
  88. agno/knowledge/reader/csv_reader.py +8 -10
  89. agno/knowledge/reader/docx_reader.py +5 -6
  90. agno/knowledge/reader/field_labeled_csv_reader.py +16 -20
  91. agno/knowledge/reader/json_reader.py +5 -4
  92. agno/knowledge/reader/markdown_reader.py +8 -8
  93. agno/knowledge/reader/pdf_reader.py +17 -19
  94. agno/knowledge/reader/pptx_reader.py +101 -0
  95. agno/knowledge/reader/reader_factory.py +32 -3
  96. agno/knowledge/reader/s3_reader.py +3 -3
  97. agno/knowledge/reader/tavily_reader.py +193 -0
  98. agno/knowledge/reader/text_reader.py +22 -10
  99. agno/knowledge/reader/web_search_reader.py +1 -48
  100. agno/knowledge/reader/website_reader.py +10 -10
  101. agno/knowledge/reader/wikipedia_reader.py +33 -1
  102. agno/knowledge/types.py +1 -0
  103. agno/knowledge/utils.py +72 -7
  104. agno/media.py +22 -6
  105. agno/memory/__init__.py +14 -1
  106. agno/memory/manager.py +544 -83
  107. agno/memory/strategies/__init__.py +15 -0
  108. agno/memory/strategies/base.py +66 -0
  109. agno/memory/strategies/summarize.py +196 -0
  110. agno/memory/strategies/types.py +37 -0
  111. agno/models/aimlapi/aimlapi.py +17 -0
  112. agno/models/anthropic/claude.py +515 -40
  113. agno/models/aws/bedrock.py +102 -21
  114. agno/models/aws/claude.py +131 -274
  115. agno/models/azure/ai_foundry.py +41 -19
  116. agno/models/azure/openai_chat.py +39 -8
  117. agno/models/base.py +1249 -525
  118. agno/models/cerebras/cerebras.py +91 -21
  119. agno/models/cerebras/cerebras_openai.py +21 -2
  120. agno/models/cohere/chat.py +40 -6
  121. agno/models/cometapi/cometapi.py +18 -1
  122. agno/models/dashscope/dashscope.py +2 -3
  123. agno/models/deepinfra/deepinfra.py +18 -1
  124. agno/models/deepseek/deepseek.py +69 -3
  125. agno/models/fireworks/fireworks.py +18 -1
  126. agno/models/google/gemini.py +877 -80
  127. agno/models/google/utils.py +22 -0
  128. agno/models/groq/groq.py +51 -18
  129. agno/models/huggingface/huggingface.py +17 -6
  130. agno/models/ibm/watsonx.py +16 -6
  131. agno/models/internlm/internlm.py +18 -1
  132. agno/models/langdb/langdb.py +13 -1
  133. agno/models/litellm/chat.py +44 -9
  134. agno/models/litellm/litellm_openai.py +18 -1
  135. agno/models/message.py +28 -5
  136. agno/models/meta/llama.py +47 -14
  137. agno/models/meta/llama_openai.py +22 -17
  138. agno/models/mistral/mistral.py +8 -4
  139. agno/models/nebius/nebius.py +6 -7
  140. agno/models/nvidia/nvidia.py +20 -3
  141. agno/models/ollama/chat.py +24 -8
  142. agno/models/openai/chat.py +104 -29
  143. agno/models/openai/responses.py +101 -81
  144. agno/models/openrouter/openrouter.py +60 -3
  145. agno/models/perplexity/perplexity.py +17 -1
  146. agno/models/portkey/portkey.py +7 -6
  147. agno/models/requesty/requesty.py +24 -4
  148. agno/models/response.py +73 -2
  149. agno/models/sambanova/sambanova.py +20 -3
  150. agno/models/siliconflow/siliconflow.py +19 -2
  151. agno/models/together/together.py +20 -3
  152. agno/models/utils.py +254 -8
  153. agno/models/vercel/v0.py +20 -3
  154. agno/models/vertexai/__init__.py +0 -0
  155. agno/models/vertexai/claude.py +190 -0
  156. agno/models/vllm/vllm.py +19 -14
  157. agno/models/xai/xai.py +19 -2
  158. agno/os/app.py +549 -152
  159. agno/os/auth.py +190 -3
  160. agno/os/config.py +23 -0
  161. agno/os/interfaces/a2a/router.py +8 -11
  162. agno/os/interfaces/a2a/utils.py +1 -1
  163. agno/os/interfaces/agui/router.py +18 -3
  164. agno/os/interfaces/agui/utils.py +152 -39
  165. agno/os/interfaces/slack/router.py +55 -37
  166. agno/os/interfaces/slack/slack.py +9 -1
  167. agno/os/interfaces/whatsapp/router.py +0 -1
  168. agno/os/interfaces/whatsapp/security.py +3 -1
  169. agno/os/mcp.py +110 -52
  170. agno/os/middleware/__init__.py +2 -0
  171. agno/os/middleware/jwt.py +676 -112
  172. agno/os/router.py +40 -1478
  173. agno/os/routers/agents/__init__.py +3 -0
  174. agno/os/routers/agents/router.py +599 -0
  175. agno/os/routers/agents/schema.py +261 -0
  176. agno/os/routers/evals/evals.py +96 -39
  177. agno/os/routers/evals/schemas.py +65 -33
  178. agno/os/routers/evals/utils.py +80 -10
  179. agno/os/routers/health.py +10 -4
  180. agno/os/routers/knowledge/knowledge.py +196 -38
  181. agno/os/routers/knowledge/schemas.py +82 -22
  182. agno/os/routers/memory/memory.py +279 -52
  183. agno/os/routers/memory/schemas.py +46 -17
  184. agno/os/routers/metrics/metrics.py +20 -8
  185. agno/os/routers/metrics/schemas.py +16 -16
  186. agno/os/routers/session/session.py +462 -34
  187. agno/os/routers/teams/__init__.py +3 -0
  188. agno/os/routers/teams/router.py +512 -0
  189. agno/os/routers/teams/schema.py +257 -0
  190. agno/os/routers/traces/__init__.py +3 -0
  191. agno/os/routers/traces/schemas.py +414 -0
  192. agno/os/routers/traces/traces.py +499 -0
  193. agno/os/routers/workflows/__init__.py +3 -0
  194. agno/os/routers/workflows/router.py +624 -0
  195. agno/os/routers/workflows/schema.py +75 -0
  196. agno/os/schema.py +256 -693
  197. agno/os/scopes.py +469 -0
  198. agno/os/utils.py +514 -36
  199. agno/reasoning/anthropic.py +80 -0
  200. agno/reasoning/gemini.py +73 -0
  201. agno/reasoning/openai.py +5 -0
  202. agno/reasoning/vertexai.py +76 -0
  203. agno/run/__init__.py +6 -0
  204. agno/run/agent.py +155 -32
  205. agno/run/base.py +55 -3
  206. agno/run/requirement.py +181 -0
  207. agno/run/team.py +125 -38
  208. agno/run/workflow.py +72 -18
  209. agno/session/agent.py +102 -89
  210. agno/session/summary.py +56 -15
  211. agno/session/team.py +164 -90
  212. agno/session/workflow.py +405 -40
  213. agno/table.py +10 -0
  214. agno/team/team.py +3974 -1903
  215. agno/tools/dalle.py +2 -4
  216. agno/tools/eleven_labs.py +23 -25
  217. agno/tools/exa.py +21 -16
  218. agno/tools/file.py +153 -23
  219. agno/tools/file_generation.py +16 -10
  220. agno/tools/firecrawl.py +15 -7
  221. agno/tools/function.py +193 -38
  222. agno/tools/gmail.py +238 -14
  223. agno/tools/google_drive.py +271 -0
  224. agno/tools/googlecalendar.py +36 -8
  225. agno/tools/googlesheets.py +20 -5
  226. agno/tools/jira.py +20 -0
  227. agno/tools/mcp/__init__.py +10 -0
  228. agno/tools/mcp/mcp.py +331 -0
  229. agno/tools/mcp/multi_mcp.py +347 -0
  230. agno/tools/mcp/params.py +24 -0
  231. agno/tools/mcp_toolbox.py +3 -3
  232. agno/tools/models/nebius.py +5 -5
  233. agno/tools/models_labs.py +20 -10
  234. agno/tools/nano_banana.py +151 -0
  235. agno/tools/notion.py +204 -0
  236. agno/tools/parallel.py +314 -0
  237. agno/tools/postgres.py +76 -36
  238. agno/tools/redshift.py +406 -0
  239. agno/tools/scrapegraph.py +1 -1
  240. agno/tools/shopify.py +1519 -0
  241. agno/tools/slack.py +18 -3
  242. agno/tools/spotify.py +919 -0
  243. agno/tools/tavily.py +146 -0
  244. agno/tools/toolkit.py +25 -0
  245. agno/tools/workflow.py +8 -1
  246. agno/tools/yfinance.py +12 -11
  247. agno/tracing/__init__.py +12 -0
  248. agno/tracing/exporter.py +157 -0
  249. agno/tracing/schemas.py +276 -0
  250. agno/tracing/setup.py +111 -0
  251. agno/utils/agent.py +938 -0
  252. agno/utils/cryptography.py +22 -0
  253. agno/utils/dttm.py +33 -0
  254. agno/utils/events.py +151 -3
  255. agno/utils/gemini.py +15 -5
  256. agno/utils/hooks.py +118 -4
  257. agno/utils/http.py +113 -2
  258. agno/utils/knowledge.py +12 -5
  259. agno/utils/log.py +1 -0
  260. agno/utils/mcp.py +92 -2
  261. agno/utils/media.py +187 -1
  262. agno/utils/merge_dict.py +3 -3
  263. agno/utils/message.py +60 -0
  264. agno/utils/models/ai_foundry.py +9 -2
  265. agno/utils/models/claude.py +49 -14
  266. agno/utils/models/cohere.py +9 -2
  267. agno/utils/models/llama.py +9 -2
  268. agno/utils/models/mistral.py +4 -2
  269. agno/utils/print_response/agent.py +109 -16
  270. agno/utils/print_response/team.py +223 -30
  271. agno/utils/print_response/workflow.py +251 -34
  272. agno/utils/streamlit.py +1 -1
  273. agno/utils/team.py +98 -9
  274. agno/utils/tokens.py +657 -0
  275. agno/vectordb/base.py +39 -7
  276. agno/vectordb/cassandra/cassandra.py +21 -5
  277. agno/vectordb/chroma/chromadb.py +43 -12
  278. agno/vectordb/clickhouse/clickhousedb.py +21 -5
  279. agno/vectordb/couchbase/couchbase.py +29 -5
  280. agno/vectordb/lancedb/lance_db.py +92 -181
  281. agno/vectordb/langchaindb/langchaindb.py +24 -4
  282. agno/vectordb/lightrag/lightrag.py +17 -3
  283. agno/vectordb/llamaindex/llamaindexdb.py +25 -5
  284. agno/vectordb/milvus/milvus.py +50 -37
  285. agno/vectordb/mongodb/__init__.py +7 -1
  286. agno/vectordb/mongodb/mongodb.py +36 -30
  287. agno/vectordb/pgvector/pgvector.py +201 -77
  288. agno/vectordb/pineconedb/pineconedb.py +41 -23
  289. agno/vectordb/qdrant/qdrant.py +67 -54
  290. agno/vectordb/redis/__init__.py +9 -0
  291. agno/vectordb/redis/redisdb.py +682 -0
  292. agno/vectordb/singlestore/singlestore.py +50 -29
  293. agno/vectordb/surrealdb/surrealdb.py +31 -41
  294. agno/vectordb/upstashdb/upstashdb.py +34 -6
  295. agno/vectordb/weaviate/weaviate.py +53 -14
  296. agno/workflow/__init__.py +2 -0
  297. agno/workflow/agent.py +299 -0
  298. agno/workflow/condition.py +120 -18
  299. agno/workflow/loop.py +77 -10
  300. agno/workflow/parallel.py +231 -143
  301. agno/workflow/router.py +118 -17
  302. agno/workflow/step.py +609 -170
  303. agno/workflow/steps.py +73 -6
  304. agno/workflow/types.py +96 -21
  305. agno/workflow/workflow.py +2039 -262
  306. {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/METADATA +201 -66
  307. agno-2.3.13.dist-info/RECORD +613 -0
  308. agno/tools/googlesearch.py +0 -98
  309. agno/tools/mcp.py +0 -679
  310. agno/tools/memori.py +0 -339
  311. agno-2.1.2.dist-info/RECORD +0 -543
  312. {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +0 -0
  313. {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/licenses/LICENSE +0 -0
  314. {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,15 @@
1
+ """Memory optimization strategy implementations."""
2
+
3
+ from agno.memory.strategies.base import MemoryOptimizationStrategy
4
+ from agno.memory.strategies.summarize import SummarizeStrategy
5
+ from agno.memory.strategies.types import (
6
+ MemoryOptimizationStrategyFactory,
7
+ MemoryOptimizationStrategyType,
8
+ )
9
+
10
+ __all__ = [
11
+ "MemoryOptimizationStrategy",
12
+ "MemoryOptimizationStrategyFactory",
13
+ "MemoryOptimizationStrategyType",
14
+ "SummarizeStrategy",
15
+ ]
@@ -0,0 +1,66 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import List
3
+
4
+ from agno.db.schemas import UserMemory
5
+ from agno.models.base import Model
6
+ from agno.utils.tokens import count_text_tokens
7
+
8
+
9
+ class MemoryOptimizationStrategy(ABC):
10
+ """Abstract base class for memory optimization strategies.
11
+
12
+ Subclasses must implement optimize() and aoptimize().
13
+ get_system_prompt() is optional and only needed for LLM-based strategies.
14
+ """
15
+
16
+ def get_system_prompt(self) -> str:
17
+ """Get system prompt for this optimization strategy.
18
+
19
+ Returns:
20
+ System prompt string for LLM-based strategies.
21
+ """
22
+ raise NotImplementedError
23
+
24
+ @abstractmethod
25
+ def optimize(
26
+ self,
27
+ memories: List[UserMemory],
28
+ model: Model,
29
+ ) -> List[UserMemory]:
30
+ """Optimize memories synchronously.
31
+
32
+ Args:
33
+ memories: List of UserMemory objects to optimize
34
+ model: Model to use for optimization (if needed)
35
+
36
+ Returns:
37
+ List of optimized UserMemory objects
38
+ """
39
+ raise NotImplementedError
40
+
41
+ @abstractmethod
42
+ async def aoptimize(
43
+ self,
44
+ memories: List[UserMemory],
45
+ model: Model,
46
+ ) -> List[UserMemory]:
47
+ """Optimize memories asynchronously.
48
+
49
+ Args:
50
+ memories: List of UserMemory objects to optimize
51
+ model: Model to use for optimization (if needed)
52
+
53
+ Returns:
54
+ List of optimized UserMemory objects
55
+ """
56
+ raise NotImplementedError
57
+
58
+ def count_tokens(self, memories: List[UserMemory]) -> int:
59
+ """Count total tokens across all memories.
60
+
61
+ Args:
62
+ memories: List of UserMemory objects
63
+ Returns:
64
+ Total token count
65
+ """
66
+ return sum(count_text_tokens(m.memory or "") for m in memories)
@@ -0,0 +1,196 @@
1
+ """Summarize strategy: Combine all memories into single comprehensive summary."""
2
+
3
+ from textwrap import dedent
4
+ from typing import List
5
+ from uuid import uuid4
6
+
7
+ from agno.db.schemas import UserMemory
8
+ from agno.memory.strategies import MemoryOptimizationStrategy
9
+ from agno.models.base import Model
10
+ from agno.models.message import Message
11
+ from agno.utils.dttm import now_epoch_s
12
+ from agno.utils.log import log_debug
13
+
14
+
15
+ class SummarizeStrategy(MemoryOptimizationStrategy):
16
+ """Combine all memories into single comprehensive summary.
17
+
18
+ This strategy summarizes all memories into one coherent narrative,
19
+ achieving maximum compression by eliminating redundancy. All
20
+ metadata (topics, user_id) is preserved in the summarized memory.
21
+ """
22
+
23
+ def _get_system_prompt(self) -> str:
24
+ """Get system prompt for memory summarization.
25
+
26
+ Returns:
27
+ System prompt string for LLM
28
+ """
29
+ return dedent("""\
30
+ You are a memory compression assistant. Your task is to summarize multiple memories about a user
31
+ into a single comprehensive summary while preserving all key facts.
32
+
33
+ Requirements:
34
+ - Combine related information from all memories
35
+ - Preserve all factual information
36
+ - Remove redundancy and consolidate repeated facts
37
+ - Create a coherent narrative about the user
38
+ - Maintain third-person perspective
39
+ - Do not add information not present in the original memories
40
+
41
+ Return only the summarized memory text, nothing else.\
42
+ """)
43
+
44
+ def optimize(
45
+ self,
46
+ memories: List[UserMemory],
47
+ model: Model,
48
+ ) -> List[UserMemory]:
49
+ """Summarize multiple memories into single comprehensive summary.
50
+
51
+ Args:
52
+ memories: List of UserMemory objects to summarize
53
+ model: Model to use for summarization
54
+
55
+ Returns:
56
+ List containing single summarized UserMemory object
57
+
58
+ Raises:
59
+ ValueError: If memories list is empty or if user_id cannot be determined
60
+ """
61
+ # Validate memories list
62
+ if not memories:
63
+ raise ValueError("No Memories found")
64
+
65
+ # Extract user_id from first memory
66
+ user_id = memories[0].user_id
67
+ if user_id is None:
68
+ raise ValueError("Cannot determine user_id: first memory does not have a valid user_id or is None")
69
+
70
+ # Collect all memory contents
71
+ memory_contents = [mem.memory for mem in memories if mem.memory]
72
+
73
+ # Combine topics - get unique topics from all memories
74
+ all_topics: List[str] = []
75
+ for mem in memories:
76
+ if mem.topics:
77
+ all_topics.extend(mem.topics)
78
+ summarized_topics = list(set(all_topics)) if all_topics else None
79
+
80
+ # Check if agent_id and team_id are consistent
81
+ agent_ids = {mem.agent_id for mem in memories if mem.agent_id}
82
+ summarized_agent_id = list(agent_ids)[0] if len(agent_ids) == 1 else None
83
+
84
+ team_ids = {mem.team_id for mem in memories if mem.team_id}
85
+ summarized_team_id = list(team_ids)[0] if len(team_ids) == 1 else None
86
+
87
+ # Create comprehensive prompt for summarization
88
+ combined_content = "\n\n".join([f"Memory {i + 1}: {content}" for i, content in enumerate(memory_contents)])
89
+
90
+ system_prompt = self._get_system_prompt()
91
+
92
+ messages_for_model = [
93
+ Message(role="system", content=system_prompt),
94
+ Message(role="user", content=f"Summarize these memories into a single summary:\n\n{combined_content}"),
95
+ ]
96
+
97
+ # Generate summarized content
98
+ response = model.response(messages=messages_for_model)
99
+ summarized_content = response.content or " ".join(memory_contents)
100
+
101
+ # Generate new memory_id
102
+ new_memory_id = str(uuid4())
103
+
104
+ # Create summarized memory
105
+ summarized_memory = UserMemory(
106
+ memory_id=new_memory_id,
107
+ memory=summarized_content.strip(),
108
+ topics=summarized_topics,
109
+ user_id=user_id,
110
+ agent_id=summarized_agent_id,
111
+ team_id=summarized_team_id,
112
+ updated_at=now_epoch_s(),
113
+ )
114
+
115
+ log_debug(
116
+ f"Summarized {len(memories)} memories into 1: {self.count_tokens(memories)} -> {self.count_tokens([summarized_memory])} tokens"
117
+ )
118
+
119
+ return [summarized_memory]
120
+
121
+ async def aoptimize(
122
+ self,
123
+ memories: List[UserMemory],
124
+ model: Model,
125
+ ) -> List[UserMemory]:
126
+ """Async version: Summarize multiple memories into single comprehensive summary.
127
+
128
+ Args:
129
+ memories: List of UserMemory objects to summarize
130
+ model: Model to use for summarization
131
+
132
+ Returns:
133
+ List containing single summarized UserMemory object
134
+
135
+ Raises:
136
+ ValueError: If memories list is empty or if user_id cannot be determined
137
+ """
138
+ # Validate memories list
139
+ if not memories:
140
+ raise ValueError("No Memories found")
141
+
142
+ # Extract user_id from first memory
143
+ user_id = memories[0].user_id
144
+ if user_id is None:
145
+ raise ValueError("Cannot determine user_id: first memory does not have a valid user_id or is None")
146
+
147
+ # Collect all memory contents
148
+ memory_contents = [mem.memory for mem in memories if mem.memory]
149
+
150
+ # Combine topics - get unique topics from all memories
151
+ all_topics: List[str] = []
152
+ for mem in memories:
153
+ if mem.topics:
154
+ all_topics.extend(mem.topics)
155
+ summarized_topics = list(set(all_topics)) if all_topics else None
156
+
157
+ # Check if agent_id and team_id are consistent
158
+ agent_ids = {mem.agent_id for mem in memories if mem.agent_id}
159
+ summarized_agent_id = list(agent_ids)[0] if len(agent_ids) == 1 else None
160
+
161
+ team_ids = {mem.team_id for mem in memories if mem.team_id}
162
+ summarized_team_id = list(team_ids)[0] if len(team_ids) == 1 else None
163
+
164
+ # Create comprehensive prompt for summarization
165
+ combined_content = "\n\n".join([f"Memory {i + 1}: {content}" for i, content in enumerate(memory_contents)])
166
+
167
+ system_prompt = self._get_system_prompt()
168
+
169
+ messages_for_model = [
170
+ Message(role="system", content=system_prompt),
171
+ Message(role="user", content=f"Summarize these memories into a single summary:\n\n{combined_content}"),
172
+ ]
173
+
174
+ # Generate summarized content (async)
175
+ response = await model.aresponse(messages=messages_for_model)
176
+ summarized_content = response.content or " ".join(memory_contents)
177
+
178
+ # Generate new memory_id
179
+ new_memory_id = str(uuid4())
180
+
181
+ # Create summarized memory
182
+ summarized_memory = UserMemory(
183
+ memory_id=new_memory_id,
184
+ memory=summarized_content.strip(),
185
+ topics=summarized_topics,
186
+ user_id=user_id,
187
+ agent_id=summarized_agent_id,
188
+ team_id=summarized_team_id,
189
+ updated_at=now_epoch_s(),
190
+ )
191
+
192
+ log_debug(
193
+ f"Summarized {len(memories)} memories into 1: {self.count_tokens(memories)} -> {self.count_tokens([summarized_memory])} tokens"
194
+ )
195
+
196
+ return [summarized_memory]
@@ -0,0 +1,37 @@
1
+ """Memory optimization strategy types and factory."""
2
+
3
+ from enum import Enum
4
+
5
+ from agno.memory.strategies import MemoryOptimizationStrategy
6
+
7
+
8
+ class MemoryOptimizationStrategyType(str, Enum):
9
+ """Enumeration of available memory optimization strategies."""
10
+
11
+ SUMMARIZE = "summarize"
12
+
13
+
14
+ class MemoryOptimizationStrategyFactory:
15
+ """Factory for creating memory optimization strategy instances."""
16
+
17
+ @classmethod
18
+ def create_strategy(cls, strategy_type: MemoryOptimizationStrategyType, **kwargs) -> MemoryOptimizationStrategy:
19
+ """Create an instance of the optimization strategy with given parameters.
20
+
21
+ Args:
22
+ strategy_type: Type of strategy to create
23
+ **kwargs: Additional parameters for strategy initialization
24
+
25
+ Returns:
26
+ MemoryOptimizationStrategy instance
27
+ """
28
+ strategy_map = {
29
+ MemoryOptimizationStrategyType.SUMMARIZE: cls._create_summarize_strategy,
30
+ }
31
+ return strategy_map[strategy_type](**kwargs)
32
+
33
+ @classmethod
34
+ def _create_summarize_strategy(cls, **kwargs) -> MemoryOptimizationStrategy:
35
+ from agno.memory.strategies.summarize import SummarizeStrategy
36
+
37
+ return SummarizeStrategy(**kwargs)
@@ -2,6 +2,7 @@ from dataclasses import dataclass, field
2
2
  from os import getenv
3
3
  from typing import Any, Dict, Optional
4
4
 
5
+ from agno.exceptions import ModelAuthenticationError
5
6
  from agno.models.message import Message
6
7
  from agno.models.openai.like import OpenAILike
7
8
 
@@ -28,6 +29,22 @@ class AIMLAPI(OpenAILike):
28
29
  base_url: str = "https://api.aimlapi.com/v1"
29
30
  max_tokens: int = 4096
30
31
 
32
+ def _get_client_params(self) -> Dict[str, Any]:
33
+ """
34
+ Returns client parameters for API requests, checking for AIMLAPI_API_KEY.
35
+
36
+ Returns:
37
+ Dict[str, Any]: A dictionary of client parameters for API requests.
38
+ """
39
+ if not self.api_key:
40
+ self.api_key = getenv("AIMLAPI_API_KEY")
41
+ if not self.api_key:
42
+ raise ModelAuthenticationError(
43
+ message="AIMLAPI_API_KEY not set. Please set the AIMLAPI_API_KEY environment variable.",
44
+ model_name=self.name,
45
+ )
46
+ return super()._get_client_params()
47
+
31
48
  def _format_message(self, message: Message) -> Dict[str, Any]:
32
49
  """
33
50
  Minimal additional formatter that only replaces None with empty string.