agno 1.8.1__py3-none-any.whl → 2.0.0a1__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 (580) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +19 -27
  3. agno/agent/agent.py +2778 -4123
  4. agno/api/agent.py +9 -65
  5. agno/api/api.py +5 -46
  6. agno/api/evals.py +6 -17
  7. agno/api/os.py +17 -0
  8. agno/api/routes.py +6 -41
  9. agno/api/schemas/__init__.py +9 -0
  10. agno/api/schemas/agent.py +5 -21
  11. agno/api/schemas/evals.py +7 -16
  12. agno/api/schemas/os.py +14 -0
  13. agno/api/schemas/team.py +5 -21
  14. agno/api/schemas/utils.py +21 -0
  15. agno/api/schemas/workflows.py +11 -7
  16. agno/api/settings.py +53 -0
  17. agno/api/team.py +9 -64
  18. agno/api/workflow.py +28 -0
  19. agno/cloud/aws/base.py +214 -0
  20. agno/cloud/aws/s3/__init__.py +2 -0
  21. agno/cloud/aws/s3/api_client.py +43 -0
  22. agno/cloud/aws/s3/bucket.py +195 -0
  23. agno/cloud/aws/s3/object.py +57 -0
  24. agno/db/__init__.py +24 -0
  25. agno/db/base.py +245 -0
  26. agno/db/dynamo/__init__.py +3 -0
  27. agno/db/dynamo/dynamo.py +1749 -0
  28. agno/db/dynamo/schemas.py +278 -0
  29. agno/db/dynamo/utils.py +684 -0
  30. agno/db/firestore/__init__.py +3 -0
  31. agno/db/firestore/firestore.py +1438 -0
  32. agno/db/firestore/schemas.py +130 -0
  33. agno/db/firestore/utils.py +278 -0
  34. agno/db/gcs_json/__init__.py +3 -0
  35. agno/db/gcs_json/gcs_json_db.py +1001 -0
  36. agno/db/gcs_json/utils.py +194 -0
  37. agno/db/in_memory/__init__.py +3 -0
  38. agno/db/in_memory/in_memory_db.py +888 -0
  39. agno/db/in_memory/utils.py +172 -0
  40. agno/db/json/__init__.py +3 -0
  41. agno/db/json/json_db.py +1051 -0
  42. agno/db/json/utils.py +196 -0
  43. agno/db/migrations/v1_to_v2.py +162 -0
  44. agno/db/mongo/__init__.py +3 -0
  45. agno/db/mongo/mongo.py +1417 -0
  46. agno/db/mongo/schemas.py +77 -0
  47. agno/db/mongo/utils.py +204 -0
  48. agno/db/mysql/__init__.py +3 -0
  49. agno/db/mysql/mysql.py +1719 -0
  50. agno/db/mysql/schemas.py +124 -0
  51. agno/db/mysql/utils.py +298 -0
  52. agno/db/postgres/__init__.py +3 -0
  53. agno/db/postgres/postgres.py +1720 -0
  54. agno/db/postgres/schemas.py +124 -0
  55. agno/db/postgres/utils.py +281 -0
  56. agno/db/redis/__init__.py +3 -0
  57. agno/db/redis/redis.py +1371 -0
  58. agno/db/redis/schemas.py +109 -0
  59. agno/db/redis/utils.py +288 -0
  60. agno/db/schemas/__init__.py +3 -0
  61. agno/db/schemas/evals.py +33 -0
  62. agno/db/schemas/knowledge.py +40 -0
  63. agno/db/schemas/memory.py +46 -0
  64. agno/db/singlestore/__init__.py +3 -0
  65. agno/db/singlestore/schemas.py +116 -0
  66. agno/db/singlestore/singlestore.py +1722 -0
  67. agno/db/singlestore/utils.py +327 -0
  68. agno/db/sqlite/__init__.py +3 -0
  69. agno/db/sqlite/schemas.py +119 -0
  70. agno/db/sqlite/sqlite.py +1680 -0
  71. agno/db/sqlite/utils.py +269 -0
  72. agno/db/utils.py +88 -0
  73. agno/eval/__init__.py +14 -0
  74. agno/eval/accuracy.py +142 -43
  75. agno/eval/performance.py +88 -23
  76. agno/eval/reliability.py +73 -20
  77. agno/eval/utils.py +23 -13
  78. agno/integrations/discord/__init__.py +3 -0
  79. agno/{app → integrations}/discord/client.py +10 -10
  80. agno/knowledge/__init__.py +2 -2
  81. agno/{document → knowledge}/chunking/agentic.py +2 -2
  82. agno/{document → knowledge}/chunking/document.py +2 -2
  83. agno/{document → knowledge}/chunking/fixed.py +3 -3
  84. agno/{document → knowledge}/chunking/markdown.py +2 -2
  85. agno/{document → knowledge}/chunking/recursive.py +2 -2
  86. agno/{document → knowledge}/chunking/row.py +2 -2
  87. agno/knowledge/chunking/semantic.py +59 -0
  88. agno/knowledge/chunking/strategy.py +121 -0
  89. agno/knowledge/content.py +74 -0
  90. agno/knowledge/document/__init__.py +5 -0
  91. agno/{document → knowledge/document}/base.py +12 -2
  92. agno/knowledge/embedder/__init__.py +5 -0
  93. agno/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
  94. agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
  95. agno/{embedder → knowledge/embedder}/base.py +6 -0
  96. agno/{embedder → knowledge/embedder}/cohere.py +72 -1
  97. agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
  98. agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
  99. agno/{embedder → knowledge/embedder}/google.py +74 -1
  100. agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
  101. agno/{embedder → knowledge/embedder}/jina.py +48 -2
  102. agno/knowledge/embedder/langdb.py +22 -0
  103. agno/knowledge/embedder/mistral.py +139 -0
  104. agno/{embedder → knowledge/embedder}/nebius.py +1 -1
  105. agno/{embedder → knowledge/embedder}/ollama.py +54 -3
  106. agno/knowledge/embedder/openai.py +223 -0
  107. agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
  108. agno/{embedder → knowledge/embedder}/together.py +1 -1
  109. agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
  110. agno/knowledge/knowledge.py +1515 -0
  111. agno/knowledge/reader/__init__.py +7 -0
  112. agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
  113. agno/knowledge/reader/base.py +88 -0
  114. agno/{document → knowledge}/reader/csv_reader.py +68 -15
  115. agno/knowledge/reader/docx_reader.py +83 -0
  116. agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
  117. agno/knowledge/reader/gcs_reader.py +67 -0
  118. agno/{document → knowledge}/reader/json_reader.py +30 -9
  119. agno/{document → knowledge}/reader/markdown_reader.py +36 -9
  120. agno/{document → knowledge}/reader/pdf_reader.py +79 -21
  121. agno/knowledge/reader/reader_factory.py +275 -0
  122. agno/knowledge/reader/s3_reader.py +171 -0
  123. agno/{document → knowledge}/reader/text_reader.py +31 -10
  124. agno/knowledge/reader/url_reader.py +84 -0
  125. agno/knowledge/reader/web_search_reader.py +389 -0
  126. agno/{document → knowledge}/reader/website_reader.py +37 -10
  127. agno/knowledge/reader/wikipedia_reader.py +59 -0
  128. agno/knowledge/reader/youtube_reader.py +78 -0
  129. agno/knowledge/remote_content/remote_content.py +88 -0
  130. agno/{reranker → knowledge/reranker}/base.py +1 -1
  131. agno/{reranker → knowledge/reranker}/cohere.py +2 -2
  132. agno/{reranker → knowledge/reranker}/infinity.py +2 -2
  133. agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
  134. agno/knowledge/types.py +30 -0
  135. agno/knowledge/utils.py +169 -0
  136. agno/memory/__init__.py +2 -10
  137. agno/memory/manager.py +1003 -148
  138. agno/models/aimlapi/__init__.py +2 -2
  139. agno/models/aimlapi/aimlapi.py +6 -6
  140. agno/models/anthropic/claude.py +129 -82
  141. agno/models/aws/bedrock.py +107 -175
  142. agno/models/aws/claude.py +64 -18
  143. agno/models/azure/ai_foundry.py +73 -23
  144. agno/models/base.py +347 -287
  145. agno/models/cerebras/cerebras.py +84 -27
  146. agno/models/cohere/chat.py +106 -98
  147. agno/models/google/gemini.py +100 -42
  148. agno/models/groq/groq.py +97 -35
  149. agno/models/huggingface/huggingface.py +92 -27
  150. agno/models/ibm/watsonx.py +72 -13
  151. agno/models/litellm/chat.py +85 -13
  152. agno/models/message.py +38 -144
  153. agno/models/meta/llama.py +85 -49
  154. agno/models/metrics.py +120 -0
  155. agno/models/mistral/mistral.py +90 -21
  156. agno/models/ollama/__init__.py +0 -2
  157. agno/models/ollama/chat.py +84 -46
  158. agno/models/openai/chat.py +121 -23
  159. agno/models/openai/responses.py +178 -105
  160. agno/models/perplexity/perplexity.py +26 -2
  161. agno/models/portkey/portkey.py +0 -7
  162. agno/models/response.py +14 -8
  163. agno/models/utils.py +20 -0
  164. agno/models/vercel/__init__.py +2 -2
  165. agno/models/vercel/v0.py +1 -1
  166. agno/models/vllm/__init__.py +2 -2
  167. agno/models/vllm/vllm.py +3 -3
  168. agno/models/xai/xai.py +10 -10
  169. agno/os/__init__.py +3 -0
  170. agno/os/app.py +393 -0
  171. agno/os/auth.py +47 -0
  172. agno/os/config.py +103 -0
  173. agno/os/interfaces/agui/__init__.py +3 -0
  174. agno/os/interfaces/agui/agui.py +31 -0
  175. agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
  176. agno/{app → os/interfaces}/agui/utils.py +65 -28
  177. agno/os/interfaces/base.py +21 -0
  178. agno/os/interfaces/slack/__init__.py +3 -0
  179. agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
  180. agno/os/interfaces/slack/slack.py +33 -0
  181. agno/os/interfaces/whatsapp/__init__.py +3 -0
  182. agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
  183. agno/os/interfaces/whatsapp/whatsapp.py +30 -0
  184. agno/os/router.py +843 -0
  185. agno/os/routers/__init__.py +3 -0
  186. agno/os/routers/evals/__init__.py +3 -0
  187. agno/os/routers/evals/evals.py +204 -0
  188. agno/os/routers/evals/schemas.py +142 -0
  189. agno/os/routers/evals/utils.py +161 -0
  190. agno/os/routers/knowledge/__init__.py +3 -0
  191. agno/os/routers/knowledge/knowledge.py +413 -0
  192. agno/os/routers/knowledge/schemas.py +118 -0
  193. agno/os/routers/memory/__init__.py +3 -0
  194. agno/os/routers/memory/memory.py +179 -0
  195. agno/os/routers/memory/schemas.py +58 -0
  196. agno/os/routers/metrics/__init__.py +3 -0
  197. agno/os/routers/metrics/metrics.py +58 -0
  198. agno/os/routers/metrics/schemas.py +47 -0
  199. agno/os/routers/session/__init__.py +3 -0
  200. agno/os/routers/session/session.py +163 -0
  201. agno/os/schema.py +892 -0
  202. agno/{app/playground → os}/settings.py +8 -15
  203. agno/os/utils.py +270 -0
  204. agno/reasoning/azure_ai_foundry.py +4 -4
  205. agno/reasoning/deepseek.py +4 -4
  206. agno/reasoning/default.py +6 -11
  207. agno/reasoning/groq.py +4 -4
  208. agno/reasoning/helpers.py +4 -6
  209. agno/reasoning/ollama.py +4 -4
  210. agno/reasoning/openai.py +4 -4
  211. agno/run/{response.py → agent.py} +144 -72
  212. agno/run/base.py +44 -58
  213. agno/run/cancel.py +83 -0
  214. agno/run/team.py +133 -77
  215. agno/run/workflow.py +537 -12
  216. agno/session/__init__.py +10 -0
  217. agno/session/agent.py +244 -0
  218. agno/session/summary.py +225 -0
  219. agno/session/team.py +262 -0
  220. agno/{storage/session/v2 → session}/workflow.py +47 -24
  221. agno/team/__init__.py +15 -16
  222. agno/team/team.py +2961 -4253
  223. agno/tools/agentql.py +14 -5
  224. agno/tools/airflow.py +9 -4
  225. agno/tools/api.py +7 -3
  226. agno/tools/apify.py +2 -46
  227. agno/tools/arxiv.py +8 -3
  228. agno/tools/aws_lambda.py +7 -5
  229. agno/tools/aws_ses.py +7 -1
  230. agno/tools/baidusearch.py +4 -1
  231. agno/tools/bitbucket.py +4 -4
  232. agno/tools/brandfetch.py +14 -11
  233. agno/tools/bravesearch.py +4 -1
  234. agno/tools/brightdata.py +42 -22
  235. agno/tools/browserbase.py +13 -4
  236. agno/tools/calcom.py +12 -10
  237. agno/tools/calculator.py +10 -27
  238. agno/tools/cartesia.py +18 -13
  239. agno/tools/{clickup_tool.py → clickup.py} +12 -25
  240. agno/tools/confluence.py +8 -8
  241. agno/tools/crawl4ai.py +7 -1
  242. agno/tools/csv_toolkit.py +9 -8
  243. agno/tools/dalle.py +18 -11
  244. agno/tools/daytona.py +13 -16
  245. agno/tools/decorator.py +6 -3
  246. agno/tools/desi_vocal.py +16 -7
  247. agno/tools/discord.py +11 -8
  248. agno/tools/docker.py +30 -42
  249. agno/tools/duckdb.py +34 -53
  250. agno/tools/duckduckgo.py +8 -7
  251. agno/tools/e2b.py +61 -61
  252. agno/tools/eleven_labs.py +35 -28
  253. agno/tools/email.py +4 -1
  254. agno/tools/evm.py +7 -1
  255. agno/tools/exa.py +19 -14
  256. agno/tools/fal.py +29 -29
  257. agno/tools/file.py +9 -8
  258. agno/tools/financial_datasets.py +25 -44
  259. agno/tools/firecrawl.py +22 -22
  260. agno/tools/function.py +68 -17
  261. agno/tools/giphy.py +22 -10
  262. agno/tools/github.py +48 -126
  263. agno/tools/gmail.py +45 -61
  264. agno/tools/google_bigquery.py +7 -6
  265. agno/tools/google_maps.py +11 -26
  266. agno/tools/googlesearch.py +7 -2
  267. agno/tools/googlesheets.py +21 -17
  268. agno/tools/hackernews.py +9 -5
  269. agno/tools/jina.py +5 -4
  270. agno/tools/jira.py +18 -9
  271. agno/tools/knowledge.py +31 -32
  272. agno/tools/linear.py +18 -33
  273. agno/tools/linkup.py +5 -1
  274. agno/tools/local_file_system.py +8 -5
  275. agno/tools/lumalab.py +31 -19
  276. agno/tools/mem0.py +18 -12
  277. agno/tools/memori.py +14 -10
  278. agno/tools/mlx_transcribe.py +3 -2
  279. agno/tools/models/azure_openai.py +32 -14
  280. agno/tools/models/gemini.py +58 -31
  281. agno/tools/models/groq.py +29 -20
  282. agno/tools/models/nebius.py +27 -11
  283. agno/tools/models_labs.py +39 -15
  284. agno/tools/moviepy_video.py +7 -6
  285. agno/tools/neo4j.py +10 -8
  286. agno/tools/newspaper.py +7 -2
  287. agno/tools/newspaper4k.py +8 -3
  288. agno/tools/openai.py +57 -26
  289. agno/tools/openbb.py +12 -11
  290. agno/tools/opencv.py +62 -46
  291. agno/tools/openweather.py +14 -12
  292. agno/tools/pandas.py +11 -3
  293. agno/tools/postgres.py +4 -12
  294. agno/tools/pubmed.py +4 -1
  295. agno/tools/python.py +9 -22
  296. agno/tools/reasoning.py +35 -27
  297. agno/tools/reddit.py +11 -26
  298. agno/tools/replicate.py +54 -41
  299. agno/tools/resend.py +4 -1
  300. agno/tools/scrapegraph.py +15 -14
  301. agno/tools/searxng.py +10 -23
  302. agno/tools/serpapi.py +6 -3
  303. agno/tools/serper.py +13 -4
  304. agno/tools/shell.py +9 -2
  305. agno/tools/slack.py +12 -11
  306. agno/tools/sleep.py +3 -2
  307. agno/tools/spider.py +24 -4
  308. agno/tools/sql.py +7 -6
  309. agno/tools/tavily.py +6 -4
  310. agno/tools/telegram.py +12 -4
  311. agno/tools/todoist.py +11 -31
  312. agno/tools/toolkit.py +1 -1
  313. agno/tools/trafilatura.py +22 -6
  314. agno/tools/trello.py +9 -22
  315. agno/tools/twilio.py +10 -3
  316. agno/tools/user_control_flow.py +6 -1
  317. agno/tools/valyu.py +34 -5
  318. agno/tools/visualization.py +19 -28
  319. agno/tools/webbrowser.py +4 -3
  320. agno/tools/webex.py +11 -7
  321. agno/tools/website.py +15 -46
  322. agno/tools/webtools.py +12 -4
  323. agno/tools/whatsapp.py +5 -9
  324. agno/tools/wikipedia.py +20 -13
  325. agno/tools/x.py +14 -13
  326. agno/tools/yfinance.py +13 -40
  327. agno/tools/youtube.py +26 -20
  328. agno/tools/zendesk.py +7 -2
  329. agno/tools/zep.py +10 -7
  330. agno/tools/zoom.py +10 -9
  331. agno/utils/common.py +1 -19
  332. agno/utils/events.py +95 -118
  333. agno/utils/knowledge.py +29 -0
  334. agno/utils/log.py +2 -2
  335. agno/utils/mcp.py +11 -5
  336. agno/utils/media.py +39 -0
  337. agno/utils/message.py +12 -1
  338. agno/utils/models/claude.py +6 -4
  339. agno/utils/models/mistral.py +8 -7
  340. agno/utils/models/schema_utils.py +3 -3
  341. agno/utils/pprint.py +33 -32
  342. agno/utils/print_response/agent.py +779 -0
  343. agno/utils/print_response/team.py +1565 -0
  344. agno/utils/print_response/workflow.py +1451 -0
  345. agno/utils/prompts.py +14 -14
  346. agno/utils/reasoning.py +87 -0
  347. agno/utils/response.py +42 -42
  348. agno/utils/string.py +8 -22
  349. agno/utils/team.py +50 -0
  350. agno/utils/timer.py +2 -2
  351. agno/vectordb/base.py +33 -21
  352. agno/vectordb/cassandra/cassandra.py +287 -23
  353. agno/vectordb/chroma/chromadb.py +482 -59
  354. agno/vectordb/clickhouse/clickhousedb.py +270 -63
  355. agno/vectordb/couchbase/couchbase.py +309 -29
  356. agno/vectordb/lancedb/lance_db.py +360 -21
  357. agno/vectordb/langchaindb/__init__.py +5 -0
  358. agno/vectordb/langchaindb/langchaindb.py +145 -0
  359. agno/vectordb/lightrag/__init__.py +5 -0
  360. agno/vectordb/lightrag/lightrag.py +374 -0
  361. agno/vectordb/llamaindex/llamaindexdb.py +127 -0
  362. agno/vectordb/milvus/milvus.py +242 -32
  363. agno/vectordb/mongodb/mongodb.py +200 -24
  364. agno/vectordb/pgvector/pgvector.py +319 -37
  365. agno/vectordb/pineconedb/pineconedb.py +221 -27
  366. agno/vectordb/qdrant/qdrant.py +334 -14
  367. agno/vectordb/singlestore/singlestore.py +286 -29
  368. agno/vectordb/surrealdb/surrealdb.py +187 -7
  369. agno/vectordb/upstashdb/upstashdb.py +342 -26
  370. agno/vectordb/weaviate/weaviate.py +227 -165
  371. agno/workflow/__init__.py +17 -13
  372. agno/workflow/{v2/condition.py → condition.py} +135 -32
  373. agno/workflow/{v2/loop.py → loop.py} +115 -28
  374. agno/workflow/{v2/parallel.py → parallel.py} +138 -108
  375. agno/workflow/{v2/router.py → router.py} +133 -32
  376. agno/workflow/{v2/step.py → step.py} +200 -42
  377. agno/workflow/{v2/steps.py → steps.py} +147 -66
  378. agno/workflow/types.py +482 -0
  379. agno/workflow/workflow.py +2394 -696
  380. agno-2.0.0a1.dist-info/METADATA +355 -0
  381. agno-2.0.0a1.dist-info/RECORD +514 -0
  382. agno/agent/metrics.py +0 -107
  383. agno/api/app.py +0 -35
  384. agno/api/playground.py +0 -92
  385. agno/api/schemas/app.py +0 -12
  386. agno/api/schemas/playground.py +0 -22
  387. agno/api/schemas/user.py +0 -35
  388. agno/api/schemas/workspace.py +0 -46
  389. agno/api/user.py +0 -160
  390. agno/api/workflows.py +0 -33
  391. agno/api/workspace.py +0 -175
  392. agno/app/agui/__init__.py +0 -3
  393. agno/app/agui/app.py +0 -17
  394. agno/app/agui/sync_router.py +0 -120
  395. agno/app/base.py +0 -186
  396. agno/app/discord/__init__.py +0 -3
  397. agno/app/fastapi/__init__.py +0 -3
  398. agno/app/fastapi/app.py +0 -107
  399. agno/app/fastapi/async_router.py +0 -457
  400. agno/app/fastapi/sync_router.py +0 -448
  401. agno/app/playground/app.py +0 -228
  402. agno/app/playground/async_router.py +0 -1050
  403. agno/app/playground/deploy.py +0 -249
  404. agno/app/playground/operator.py +0 -183
  405. agno/app/playground/schemas.py +0 -220
  406. agno/app/playground/serve.py +0 -55
  407. agno/app/playground/sync_router.py +0 -1042
  408. agno/app/playground/utils.py +0 -46
  409. agno/app/settings.py +0 -15
  410. agno/app/slack/__init__.py +0 -3
  411. agno/app/slack/app.py +0 -19
  412. agno/app/slack/sync_router.py +0 -92
  413. agno/app/utils.py +0 -54
  414. agno/app/whatsapp/__init__.py +0 -3
  415. agno/app/whatsapp/app.py +0 -15
  416. agno/app/whatsapp/sync_router.py +0 -197
  417. agno/cli/auth_server.py +0 -249
  418. agno/cli/config.py +0 -274
  419. agno/cli/console.py +0 -88
  420. agno/cli/credentials.py +0 -23
  421. agno/cli/entrypoint.py +0 -571
  422. agno/cli/operator.py +0 -357
  423. agno/cli/settings.py +0 -96
  424. agno/cli/ws/ws_cli.py +0 -817
  425. agno/constants.py +0 -13
  426. agno/document/__init__.py +0 -5
  427. agno/document/chunking/semantic.py +0 -45
  428. agno/document/chunking/strategy.py +0 -31
  429. agno/document/reader/__init__.py +0 -5
  430. agno/document/reader/base.py +0 -47
  431. agno/document/reader/docx_reader.py +0 -60
  432. agno/document/reader/gcs/pdf_reader.py +0 -44
  433. agno/document/reader/s3/pdf_reader.py +0 -59
  434. agno/document/reader/s3/text_reader.py +0 -63
  435. agno/document/reader/url_reader.py +0 -59
  436. agno/document/reader/youtube_reader.py +0 -58
  437. agno/embedder/__init__.py +0 -5
  438. agno/embedder/langdb.py +0 -80
  439. agno/embedder/mistral.py +0 -82
  440. agno/embedder/openai.py +0 -78
  441. agno/file/__init__.py +0 -5
  442. agno/file/file.py +0 -16
  443. agno/file/local/csv.py +0 -32
  444. agno/file/local/txt.py +0 -19
  445. agno/infra/app.py +0 -240
  446. agno/infra/base.py +0 -144
  447. agno/infra/context.py +0 -20
  448. agno/infra/db_app.py +0 -52
  449. agno/infra/resource.py +0 -205
  450. agno/infra/resources.py +0 -55
  451. agno/knowledge/agent.py +0 -702
  452. agno/knowledge/arxiv.py +0 -33
  453. agno/knowledge/combined.py +0 -36
  454. agno/knowledge/csv.py +0 -144
  455. agno/knowledge/csv_url.py +0 -124
  456. agno/knowledge/document.py +0 -223
  457. agno/knowledge/docx.py +0 -137
  458. agno/knowledge/firecrawl.py +0 -34
  459. agno/knowledge/gcs/__init__.py +0 -0
  460. agno/knowledge/gcs/base.py +0 -39
  461. agno/knowledge/gcs/pdf.py +0 -125
  462. agno/knowledge/json.py +0 -137
  463. agno/knowledge/langchain.py +0 -71
  464. agno/knowledge/light_rag.py +0 -273
  465. agno/knowledge/llamaindex.py +0 -66
  466. agno/knowledge/markdown.py +0 -154
  467. agno/knowledge/pdf.py +0 -164
  468. agno/knowledge/pdf_bytes.py +0 -42
  469. agno/knowledge/pdf_url.py +0 -148
  470. agno/knowledge/s3/__init__.py +0 -0
  471. agno/knowledge/s3/base.py +0 -64
  472. agno/knowledge/s3/pdf.py +0 -33
  473. agno/knowledge/s3/text.py +0 -34
  474. agno/knowledge/text.py +0 -141
  475. agno/knowledge/url.py +0 -46
  476. agno/knowledge/website.py +0 -179
  477. agno/knowledge/wikipedia.py +0 -32
  478. agno/knowledge/youtube.py +0 -35
  479. agno/memory/agent.py +0 -423
  480. agno/memory/classifier.py +0 -104
  481. agno/memory/db/__init__.py +0 -5
  482. agno/memory/db/base.py +0 -42
  483. agno/memory/db/mongodb.py +0 -189
  484. agno/memory/db/postgres.py +0 -203
  485. agno/memory/db/sqlite.py +0 -193
  486. agno/memory/memory.py +0 -22
  487. agno/memory/row.py +0 -36
  488. agno/memory/summarizer.py +0 -201
  489. agno/memory/summary.py +0 -19
  490. agno/memory/team.py +0 -415
  491. agno/memory/v2/__init__.py +0 -2
  492. agno/memory/v2/db/__init__.py +0 -1
  493. agno/memory/v2/db/base.py +0 -42
  494. agno/memory/v2/db/firestore.py +0 -339
  495. agno/memory/v2/db/mongodb.py +0 -196
  496. agno/memory/v2/db/postgres.py +0 -214
  497. agno/memory/v2/db/redis.py +0 -187
  498. agno/memory/v2/db/schema.py +0 -54
  499. agno/memory/v2/db/sqlite.py +0 -209
  500. agno/memory/v2/manager.py +0 -437
  501. agno/memory/v2/memory.py +0 -1097
  502. agno/memory/v2/schema.py +0 -55
  503. agno/memory/v2/summarizer.py +0 -215
  504. agno/memory/workflow.py +0 -38
  505. agno/models/ollama/tools.py +0 -430
  506. agno/models/qwen/__init__.py +0 -5
  507. agno/playground/__init__.py +0 -10
  508. agno/playground/deploy.py +0 -3
  509. agno/playground/playground.py +0 -3
  510. agno/playground/serve.py +0 -3
  511. agno/playground/settings.py +0 -3
  512. agno/reranker/__init__.py +0 -0
  513. agno/run/v2/__init__.py +0 -0
  514. agno/run/v2/workflow.py +0 -567
  515. agno/storage/__init__.py +0 -0
  516. agno/storage/agent/__init__.py +0 -0
  517. agno/storage/agent/dynamodb.py +0 -1
  518. agno/storage/agent/json.py +0 -1
  519. agno/storage/agent/mongodb.py +0 -1
  520. agno/storage/agent/postgres.py +0 -1
  521. agno/storage/agent/singlestore.py +0 -1
  522. agno/storage/agent/sqlite.py +0 -1
  523. agno/storage/agent/yaml.py +0 -1
  524. agno/storage/base.py +0 -60
  525. agno/storage/dynamodb.py +0 -673
  526. agno/storage/firestore.py +0 -297
  527. agno/storage/gcs_json.py +0 -261
  528. agno/storage/in_memory.py +0 -234
  529. agno/storage/json.py +0 -237
  530. agno/storage/mongodb.py +0 -328
  531. agno/storage/mysql.py +0 -685
  532. agno/storage/postgres.py +0 -682
  533. agno/storage/redis.py +0 -336
  534. agno/storage/session/__init__.py +0 -16
  535. agno/storage/session/agent.py +0 -64
  536. agno/storage/session/team.py +0 -63
  537. agno/storage/session/v2/__init__.py +0 -5
  538. agno/storage/session/workflow.py +0 -61
  539. agno/storage/singlestore.py +0 -606
  540. agno/storage/sqlite.py +0 -646
  541. agno/storage/workflow/__init__.py +0 -0
  542. agno/storage/workflow/mongodb.py +0 -1
  543. agno/storage/workflow/postgres.py +0 -1
  544. agno/storage/workflow/sqlite.py +0 -1
  545. agno/storage/yaml.py +0 -241
  546. agno/tools/thinking.py +0 -73
  547. agno/utils/defaults.py +0 -57
  548. agno/utils/filesystem.py +0 -39
  549. agno/utils/git.py +0 -52
  550. agno/utils/json_io.py +0 -30
  551. agno/utils/load_env.py +0 -19
  552. agno/utils/py_io.py +0 -19
  553. agno/utils/pyproject.py +0 -18
  554. agno/utils/resource_filter.py +0 -31
  555. agno/workflow/v2/__init__.py +0 -21
  556. agno/workflow/v2/types.py +0 -357
  557. agno/workflow/v2/workflow.py +0 -3312
  558. agno/workspace/__init__.py +0 -0
  559. agno/workspace/config.py +0 -325
  560. agno/workspace/enums.py +0 -6
  561. agno/workspace/helpers.py +0 -52
  562. agno/workspace/operator.py +0 -757
  563. agno/workspace/settings.py +0 -158
  564. agno-1.8.1.dist-info/METADATA +0 -982
  565. agno-1.8.1.dist-info/RECORD +0 -566
  566. agno-1.8.1.dist-info/entry_points.txt +0 -3
  567. /agno/{app → db/migrations}/__init__.py +0 -0
  568. /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
  569. /agno/{cli → integrations}/__init__.py +0 -0
  570. /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
  571. /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
  572. /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
  573. /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
  574. /agno/{app → os/interfaces}/slack/security.py +0 -0
  575. /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
  576. /agno/{file/local → utils/print_response}/__init__.py +0 -0
  577. /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
  578. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
  579. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
  580. {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
agno/memory/team.py DELETED
@@ -1,415 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from dataclasses import dataclass, field
4
- from typing import Any, Dict, List, Optional, Tuple
5
-
6
- from pydantic import ConfigDict
7
-
8
- from agno.media import AudioArtifact, ImageArtifact, VideoArtifact
9
- from agno.memory.agent import AgentRun, MemoryRetrieval
10
- from agno.memory.classifier import MemoryClassifier
11
- from agno.memory.db import MemoryDb
12
- from agno.memory.manager import MemoryManager
13
- from agno.memory.memory import Memory
14
- from agno.models.message import Message
15
- from agno.run.response import RunResponse
16
- from agno.run.team import TeamRunResponse
17
- from agno.utils.log import log_debug, log_info, log_warning
18
-
19
-
20
- @dataclass
21
- class TeamRun:
22
- message: Optional[Message] = None
23
- member_runs: Optional[List[AgentRun]] = None
24
- response: Optional[TeamRunResponse] = None
25
-
26
- def to_dict(self) -> Dict[str, Any]:
27
- message = self.message.to_dict() if self.message else None
28
- member_responses = [run.to_dict() for run in self.member_runs] if self.member_runs else None
29
- response = self.response.to_dict() if self.response else None
30
- return {
31
- "message": message,
32
- "member_responses": member_responses,
33
- "response": response,
34
- }
35
-
36
- @classmethod
37
- def from_dict(cls, data: Dict[str, Any]) -> "TeamRun":
38
- message = Message.model_validate(data.get("message")) if data.get("message") else None
39
- member_runs = (
40
- [AgentRun.model_validate(run) for run in data.get("member_runs", [])] if data.get("member_runs") else None
41
- )
42
- response = TeamRunResponse.from_dict(data.get("response", {})) if data.get("response") else None
43
- return cls(message=message, member_runs=member_runs, response=response)
44
-
45
-
46
- @dataclass
47
- class TeamMemberInteraction:
48
- member_name: str
49
- task: str
50
- response: RunResponse
51
-
52
-
53
- @dataclass
54
- class TeamContext:
55
- # List of team member interaction, represented as a request and a response
56
- member_interactions: List[TeamMemberInteraction] = field(default_factory=list)
57
- text: Optional[str] = None
58
-
59
-
60
- @dataclass
61
- class TeamMemory:
62
- # Runs between the user and agent
63
- runs: List[TeamRun] = field(default_factory=list)
64
- # List of messages sent to the model
65
- messages: List[Message] = field(default_factory=list)
66
- # If True, update the system message when it changes
67
- update_system_message_on_change: bool = True
68
-
69
- team_context: Optional[TeamContext] = None
70
-
71
- # Create and store personalized memories for this user
72
- create_user_memories: bool = False
73
- # Update memories for the user after each run
74
- update_user_memories_after_run: bool = True
75
-
76
- # MemoryDb to store personalized memories
77
- db: Optional[MemoryDb] = None
78
- # User ID for the personalized memories
79
- user_id: Optional[str] = None
80
- retrieval: MemoryRetrieval = MemoryRetrieval.last_n
81
- memories: Optional[List[Memory]] = None
82
- classifier: Optional[MemoryClassifier] = None
83
- manager: Optional[MemoryManager] = None
84
-
85
- num_memories: Optional[int] = None
86
-
87
- # True when memory is being updated
88
- updating_memory: bool = False
89
-
90
- model_config = ConfigDict(arbitrary_types_allowed=True)
91
-
92
- def to_dict(self) -> Dict[str, Any]:
93
- _memory_dict = {}
94
- for key, value in self.__dict__.items():
95
- if value is not None and key in [
96
- "update_system_message_on_change",
97
- "create_user_memories",
98
- "update_user_memories_after_run",
99
- "user_id",
100
- "num_memories",
101
- ]:
102
- _memory_dict[key] = value
103
-
104
- # Add messages if they exist
105
- if self.messages is not None:
106
- _memory_dict["messages"] = [message.to_dict() for message in self.messages]
107
- # Add memories if they exist
108
- if self.memories is not None:
109
- _memory_dict["memories"] = [memory.to_dict() for memory in self.memories]
110
- # Add runs if they exist
111
- if self.runs is not None:
112
- _memory_dict["runs"] = [run.to_dict() for run in self.runs]
113
- return _memory_dict
114
-
115
- def add_interaction_to_team_context(self, member_name: str, task: str, run_response: RunResponse) -> None:
116
- if self.team_context is None:
117
- self.team_context = TeamContext()
118
- self.team_context.member_interactions.append(
119
- TeamMemberInteraction(
120
- member_name=member_name,
121
- task=task,
122
- response=run_response,
123
- )
124
- )
125
- log_debug(f"Updated team context with member name: {member_name}")
126
-
127
- def set_team_context_text(self, text: str) -> None:
128
- if self.team_context:
129
- self.team_context.text = text
130
- else:
131
- self.team_context = TeamContext(text=text)
132
-
133
- def get_team_context_str(self) -> str:
134
- if self.team_context and self.team_context.text:
135
- return f"<team_context>\n{self.team_context.text}\n</team_context>"
136
- return ""
137
-
138
- def get_team_member_interactions_str(self) -> str:
139
- team_member_interactions_str = ""
140
- if self.team_context and self.team_context.member_interactions:
141
- team_member_interactions_str += "<member_interactions>\n"
142
-
143
- for interaction in self.team_context.member_interactions:
144
- team_member_interactions_str += f"Member: {interaction.member_name}\n"
145
- team_member_interactions_str += f"Task: {interaction.task}\n"
146
- team_member_interactions_str += f"Response: {interaction.response.to_dict().get('content', '')}\n"
147
- team_member_interactions_str += "\n"
148
- team_member_interactions_str += "</member_interactions>\n"
149
- return team_member_interactions_str
150
-
151
- def get_team_context_images(self) -> List[ImageArtifact]:
152
- images = []
153
- if self.team_context and self.team_context.member_interactions:
154
- for interaction in self.team_context.member_interactions:
155
- if interaction.response.images:
156
- images.extend(interaction.response.images)
157
- return images
158
-
159
- def get_team_context_videos(self) -> List[VideoArtifact]:
160
- videos = []
161
- if self.team_context and self.team_context.member_interactions:
162
- for interaction in self.team_context.member_interactions:
163
- if interaction.response.videos:
164
- videos.extend(interaction.response.videos)
165
- return videos
166
-
167
- def get_team_context_audio(self) -> List[AudioArtifact]:
168
- audio = []
169
- if self.team_context and self.team_context.member_interactions:
170
- for interaction in self.team_context.member_interactions:
171
- if interaction.response.audio:
172
- audio.extend(interaction.response.audio)
173
- return audio
174
-
175
- def add_team_run(self, team_run: TeamRun) -> None:
176
- """Adds an TeamRun to the runs list."""
177
- self.runs.append(team_run)
178
- log_debug("Added TeamRun to TeamMemory")
179
-
180
- def add_system_message(self, message: Message, system_message_role: str = "system") -> None:
181
- """Add the system messages to the messages list"""
182
- # If this is the first run in the session, add the system message to the messages list
183
- if len(self.messages) == 0:
184
- if message is not None:
185
- self.messages.append(message)
186
- # If there are messages in the memory, check if the system message is already in the memory
187
- # If it is not, add the system message to the messages list
188
- # If it is, update the system message if content has changed and update_system_message_on_change is True
189
- else:
190
- system_message_index = next((i for i, m in enumerate(self.messages) if m.role == system_message_role), None)
191
- # Update the system message in memory if content has changed
192
- if system_message_index is not None:
193
- if (
194
- self.messages[system_message_index].content != message.content
195
- and self.update_system_message_on_change
196
- ):
197
- log_info("Updating system message in memory with new content")
198
- self.messages[system_message_index] = message
199
- else:
200
- # Add the system message to the messages list
201
- self.messages.insert(0, message)
202
-
203
- def add_messages(self, messages: List[Message]) -> None:
204
- """Add a list of messages to the messages list."""
205
- self.messages.extend(messages)
206
- log_debug(f"Added {len(messages)} Messages to TeamMemory")
207
-
208
- def get_messages(self) -> List[Dict[str, Any]]:
209
- """Returns the messages list as a list of dictionaries."""
210
- return [message.model_dump() for message in self.messages]
211
-
212
- def get_messages_from_last_n_runs(
213
- self, last_n: Optional[int] = None, skip_role: Optional[str] = None
214
- ) -> List[Message]:
215
- """Returns the messages from the last_n runs, excluding previously tagged history messages.
216
-
217
- Args:
218
- last_n: The number of runs to return from the end of the conversation.
219
- skip_role: Skip messages with this role.
220
-
221
- Returns:
222
- A list of Messages from the specified runs, excluding history messages.
223
- """
224
- if not self.runs:
225
- return []
226
-
227
- runs_to_process = self.runs if last_n is None else self.runs[-last_n:]
228
- messages_from_history = []
229
-
230
- for run in runs_to_process:
231
- if not (run.response and run.response.messages):
232
- continue
233
-
234
- for message in run.response.messages:
235
- # Skip messages with specified role
236
- if skip_role and message.role == skip_role:
237
- continue
238
- # Skip messages that were tagged as history in previous runs
239
- if hasattr(message, "from_history") and message.from_history:
240
- continue
241
-
242
- messages_from_history.append(message)
243
-
244
- log_debug(f"Getting messages from previous runs: {len(messages_from_history)}")
245
- return messages_from_history
246
-
247
- def get_all_messages(self) -> List[Tuple[Message, Message]]:
248
- """Returns a list of tuples of (user message, assistant response)."""
249
-
250
- assistant_role = ["assistant", "model", "CHATBOT"]
251
-
252
- runs_as_message_pairs: List[Tuple[Message, Message]] = []
253
- for run in self.runs:
254
- if run.response and run.response.messages:
255
- user_message_from_run = None
256
- assistant_message_from_run = None
257
-
258
- # Start from the beginning to look for the user message
259
- for message in run.response.messages:
260
- if message.role == "user":
261
- user_message_from_run = message
262
- break
263
-
264
- # Start from the end to look for the assistant response
265
- for message in run.response.messages[::-1]:
266
- if message.role in assistant_role:
267
- assistant_message_from_run = message
268
- break
269
-
270
- if user_message_from_run and assistant_message_from_run:
271
- runs_as_message_pairs.append((user_message_from_run, assistant_message_from_run))
272
- return runs_as_message_pairs
273
-
274
- def load_user_memories(self) -> None:
275
- """Load memories from memory db for this user."""
276
-
277
- if self.db is None:
278
- return
279
-
280
- try:
281
- if self.retrieval in (MemoryRetrieval.last_n, MemoryRetrieval.first_n):
282
- memory_rows = self.db.read_memories(
283
- user_id=self.user_id,
284
- limit=self.num_memories,
285
- sort="asc" if self.retrieval == MemoryRetrieval.first_n else "desc",
286
- )
287
- else:
288
- raise NotImplementedError("Semantic retrieval not yet supported.")
289
- except Exception as e:
290
- log_debug(f"Error reading memory: {e}")
291
- return
292
-
293
- # Clear the existing memories
294
- self.memories = []
295
-
296
- # No memories to load
297
- if memory_rows is None or len(memory_rows) == 0:
298
- return
299
-
300
- for row in memory_rows:
301
- try:
302
- self.memories.append(Memory.model_validate(row.memory))
303
- except Exception as e:
304
- log_warning(f"Error loading memory: {e}")
305
- continue
306
-
307
- def should_update_memory(self, input: str) -> bool:
308
- """Determines if a message should be added to the memory db."""
309
- from agno.memory.classifier import MemoryClassifier
310
-
311
- if self.classifier is None:
312
- self.classifier = MemoryClassifier()
313
-
314
- self.classifier.existing_memories = self.memories
315
- classifier_response = self.classifier.run(input)
316
- if classifier_response and classifier_response.lower() == "yes":
317
- return True
318
- return False
319
-
320
- async def ashould_update_memory(self, input: str) -> bool:
321
- """Determines if a message should be added to the memory db."""
322
- from agno.memory.classifier import MemoryClassifier
323
-
324
- if self.classifier is None:
325
- self.classifier = MemoryClassifier()
326
-
327
- self.classifier.existing_memories = self.memories
328
- classifier_response = await self.classifier.arun(input)
329
- if classifier_response and classifier_response.lower() == "yes":
330
- return True
331
- return False
332
-
333
- def update_memory(self, input: str, force: bool = False) -> Optional[str]:
334
- """Creates a memory from a message and adds it to the memory db."""
335
-
336
- if input is None or not isinstance(input, str):
337
- return "Invalid message content"
338
-
339
- if self.db is None:
340
- log_warning("MemoryDb not provided.")
341
- return "Please provide a db to store memories"
342
-
343
- self.updating_memory = True
344
-
345
- # Check if this user message should be added to long term memory
346
- should_update_memory = force or self.should_update_memory(input=input)
347
- log_debug(f"Update memory: {should_update_memory}")
348
-
349
- if not should_update_memory:
350
- log_debug("Memory update not required")
351
- return "Memory update not required"
352
-
353
- if self.manager is None:
354
- self.manager = MemoryManager(user_id=self.user_id, db=self.db)
355
-
356
- else:
357
- self.manager.db = self.db
358
- self.manager.user_id = self.user_id
359
-
360
- response = self.manager.run(input)
361
- self.load_user_memories()
362
- self.updating_memory = False
363
- return response
364
-
365
- async def aupdate_memory(self, input: str, force: bool = False) -> Optional[str]:
366
- """Creates a memory from a message and adds it to the memory db."""
367
- if input is None or not isinstance(input, str):
368
- return "Invalid message content"
369
-
370
- if self.db is None:
371
- log_warning("MemoryDb not provided.")
372
- return "Please provide a db to store memories"
373
-
374
- self.updating_memory = True
375
-
376
- # Check if this user message should be added to long term memory
377
- should_update_memory = force or await self.ashould_update_memory(input=input)
378
- log_debug(f"Async update memory: {should_update_memory}")
379
-
380
- if not should_update_memory:
381
- log_debug("Memory update not required")
382
- return "Memory update not required"
383
-
384
- if self.manager is None:
385
- self.manager = MemoryManager(user_id=self.user_id, db=self.db)
386
-
387
- else:
388
- self.manager.db = self.db
389
- self.manager.user_id = self.user_id
390
-
391
- response = await self.manager.arun(input)
392
- self.load_user_memories()
393
- self.updating_memory = False
394
- return response
395
-
396
- def deep_copy(self) -> "TeamMemory":
397
- from copy import deepcopy
398
-
399
- # Create a shallow copy of the object
400
- copied_obj = self.__class__(**self.to_dict())
401
-
402
- # Manually deepcopy fields that are known to be safe
403
- for field_name, field_value in self.__dict__.items():
404
- if field_name not in ["db", "classifier", "manager"]:
405
- try:
406
- setattr(copied_obj, field_name, deepcopy(field_value))
407
- except Exception as e:
408
- log_warning(f"Failed to deepcopy field: {field_name} - {e}")
409
- setattr(copied_obj, field_name, field_value)
410
-
411
- copied_obj.db = self.db
412
- copied_obj.classifier = self.classifier
413
- copied_obj.manager = self.manager
414
-
415
- return copied_obj
@@ -1,2 +0,0 @@
1
- from agno.memory.v2.memory import Memory, MemoryManager, MemoryRow, SessionSummarizer
2
- from agno.memory.v2.schema import SessionSummary, UserMemory
@@ -1 +0,0 @@
1
- from agno.memory.db.base import MemoryDb
agno/memory/v2/db/base.py DELETED
@@ -1,42 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from typing import List, Optional
3
-
4
- from agno.memory.v2.db.schema import MemoryRow
5
-
6
-
7
- class MemoryDb(ABC):
8
- """Base class for the Memory Database."""
9
-
10
- @abstractmethod
11
- def create(self) -> None:
12
- raise NotImplementedError
13
-
14
- @abstractmethod
15
- def memory_exists(self, memory: MemoryRow) -> bool:
16
- raise NotImplementedError
17
-
18
- @abstractmethod
19
- def read_memories(
20
- self, user_id: Optional[str] = None, limit: Optional[int] = None, sort: Optional[str] = None
21
- ) -> List[MemoryRow]:
22
- raise NotImplementedError
23
-
24
- @abstractmethod
25
- def upsert_memory(self, memory: MemoryRow) -> Optional[MemoryRow]:
26
- raise NotImplementedError
27
-
28
- @abstractmethod
29
- def delete_memory(self, memory_id: str) -> None:
30
- raise NotImplementedError
31
-
32
- @abstractmethod
33
- def drop_table(self) -> None:
34
- raise NotImplementedError
35
-
36
- @abstractmethod
37
- def table_exists(self) -> bool:
38
- raise NotImplementedError
39
-
40
- @abstractmethod
41
- def clear(self) -> bool:
42
- raise NotImplementedError