agno 2.2.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 (575) hide show
  1. agno/__init__.py +8 -0
  2. agno/agent/__init__.py +51 -0
  3. agno/agent/agent.py +10405 -0
  4. agno/api/__init__.py +0 -0
  5. agno/api/agent.py +28 -0
  6. agno/api/api.py +40 -0
  7. agno/api/evals.py +22 -0
  8. agno/api/os.py +17 -0
  9. agno/api/routes.py +13 -0
  10. agno/api/schemas/__init__.py +9 -0
  11. agno/api/schemas/agent.py +16 -0
  12. agno/api/schemas/evals.py +16 -0
  13. agno/api/schemas/os.py +14 -0
  14. agno/api/schemas/response.py +6 -0
  15. agno/api/schemas/team.py +16 -0
  16. agno/api/schemas/utils.py +21 -0
  17. agno/api/schemas/workflows.py +16 -0
  18. agno/api/settings.py +53 -0
  19. agno/api/team.py +30 -0
  20. agno/api/workflow.py +28 -0
  21. agno/cloud/aws/base.py +214 -0
  22. agno/cloud/aws/s3/__init__.py +2 -0
  23. agno/cloud/aws/s3/api_client.py +43 -0
  24. agno/cloud/aws/s3/bucket.py +195 -0
  25. agno/cloud/aws/s3/object.py +57 -0
  26. agno/culture/__init__.py +3 -0
  27. agno/culture/manager.py +956 -0
  28. agno/db/__init__.py +24 -0
  29. agno/db/async_postgres/__init__.py +3 -0
  30. agno/db/base.py +598 -0
  31. agno/db/dynamo/__init__.py +3 -0
  32. agno/db/dynamo/dynamo.py +2042 -0
  33. agno/db/dynamo/schemas.py +314 -0
  34. agno/db/dynamo/utils.py +743 -0
  35. agno/db/firestore/__init__.py +3 -0
  36. agno/db/firestore/firestore.py +1795 -0
  37. agno/db/firestore/schemas.py +140 -0
  38. agno/db/firestore/utils.py +376 -0
  39. agno/db/gcs_json/__init__.py +3 -0
  40. agno/db/gcs_json/gcs_json_db.py +1335 -0
  41. agno/db/gcs_json/utils.py +228 -0
  42. agno/db/in_memory/__init__.py +3 -0
  43. agno/db/in_memory/in_memory_db.py +1160 -0
  44. agno/db/in_memory/utils.py +230 -0
  45. agno/db/json/__init__.py +3 -0
  46. agno/db/json/json_db.py +1328 -0
  47. agno/db/json/utils.py +230 -0
  48. agno/db/migrations/__init__.py +0 -0
  49. agno/db/migrations/v1_to_v2.py +635 -0
  50. agno/db/mongo/__init__.py +17 -0
  51. agno/db/mongo/async_mongo.py +2026 -0
  52. agno/db/mongo/mongo.py +1982 -0
  53. agno/db/mongo/schemas.py +87 -0
  54. agno/db/mongo/utils.py +259 -0
  55. agno/db/mysql/__init__.py +3 -0
  56. agno/db/mysql/mysql.py +2308 -0
  57. agno/db/mysql/schemas.py +138 -0
  58. agno/db/mysql/utils.py +355 -0
  59. agno/db/postgres/__init__.py +4 -0
  60. agno/db/postgres/async_postgres.py +1927 -0
  61. agno/db/postgres/postgres.py +2260 -0
  62. agno/db/postgres/schemas.py +139 -0
  63. agno/db/postgres/utils.py +442 -0
  64. agno/db/redis/__init__.py +3 -0
  65. agno/db/redis/redis.py +1660 -0
  66. agno/db/redis/schemas.py +123 -0
  67. agno/db/redis/utils.py +346 -0
  68. agno/db/schemas/__init__.py +4 -0
  69. agno/db/schemas/culture.py +120 -0
  70. agno/db/schemas/evals.py +33 -0
  71. agno/db/schemas/knowledge.py +40 -0
  72. agno/db/schemas/memory.py +46 -0
  73. agno/db/schemas/metrics.py +0 -0
  74. agno/db/singlestore/__init__.py +3 -0
  75. agno/db/singlestore/schemas.py +130 -0
  76. agno/db/singlestore/singlestore.py +2272 -0
  77. agno/db/singlestore/utils.py +384 -0
  78. agno/db/sqlite/__init__.py +4 -0
  79. agno/db/sqlite/async_sqlite.py +2293 -0
  80. agno/db/sqlite/schemas.py +133 -0
  81. agno/db/sqlite/sqlite.py +2288 -0
  82. agno/db/sqlite/utils.py +431 -0
  83. agno/db/surrealdb/__init__.py +3 -0
  84. agno/db/surrealdb/metrics.py +292 -0
  85. agno/db/surrealdb/models.py +309 -0
  86. agno/db/surrealdb/queries.py +71 -0
  87. agno/db/surrealdb/surrealdb.py +1353 -0
  88. agno/db/surrealdb/utils.py +147 -0
  89. agno/db/utils.py +116 -0
  90. agno/debug.py +18 -0
  91. agno/eval/__init__.py +14 -0
  92. agno/eval/accuracy.py +834 -0
  93. agno/eval/performance.py +773 -0
  94. agno/eval/reliability.py +306 -0
  95. agno/eval/utils.py +119 -0
  96. agno/exceptions.py +161 -0
  97. agno/filters.py +354 -0
  98. agno/guardrails/__init__.py +6 -0
  99. agno/guardrails/base.py +19 -0
  100. agno/guardrails/openai.py +144 -0
  101. agno/guardrails/pii.py +94 -0
  102. agno/guardrails/prompt_injection.py +52 -0
  103. agno/integrations/__init__.py +0 -0
  104. agno/integrations/discord/__init__.py +3 -0
  105. agno/integrations/discord/client.py +203 -0
  106. agno/knowledge/__init__.py +5 -0
  107. agno/knowledge/chunking/__init__.py +0 -0
  108. agno/knowledge/chunking/agentic.py +79 -0
  109. agno/knowledge/chunking/document.py +91 -0
  110. agno/knowledge/chunking/fixed.py +57 -0
  111. agno/knowledge/chunking/markdown.py +151 -0
  112. agno/knowledge/chunking/recursive.py +63 -0
  113. agno/knowledge/chunking/row.py +39 -0
  114. agno/knowledge/chunking/semantic.py +86 -0
  115. agno/knowledge/chunking/strategy.py +165 -0
  116. agno/knowledge/content.py +74 -0
  117. agno/knowledge/document/__init__.py +5 -0
  118. agno/knowledge/document/base.py +58 -0
  119. agno/knowledge/embedder/__init__.py +5 -0
  120. agno/knowledge/embedder/aws_bedrock.py +343 -0
  121. agno/knowledge/embedder/azure_openai.py +210 -0
  122. agno/knowledge/embedder/base.py +23 -0
  123. agno/knowledge/embedder/cohere.py +323 -0
  124. agno/knowledge/embedder/fastembed.py +62 -0
  125. agno/knowledge/embedder/fireworks.py +13 -0
  126. agno/knowledge/embedder/google.py +258 -0
  127. agno/knowledge/embedder/huggingface.py +94 -0
  128. agno/knowledge/embedder/jina.py +182 -0
  129. agno/knowledge/embedder/langdb.py +22 -0
  130. agno/knowledge/embedder/mistral.py +206 -0
  131. agno/knowledge/embedder/nebius.py +13 -0
  132. agno/knowledge/embedder/ollama.py +154 -0
  133. agno/knowledge/embedder/openai.py +195 -0
  134. agno/knowledge/embedder/sentence_transformer.py +63 -0
  135. agno/knowledge/embedder/together.py +13 -0
  136. agno/knowledge/embedder/vllm.py +262 -0
  137. agno/knowledge/embedder/voyageai.py +165 -0
  138. agno/knowledge/knowledge.py +1988 -0
  139. agno/knowledge/reader/__init__.py +7 -0
  140. agno/knowledge/reader/arxiv_reader.py +81 -0
  141. agno/knowledge/reader/base.py +95 -0
  142. agno/knowledge/reader/csv_reader.py +166 -0
  143. agno/knowledge/reader/docx_reader.py +82 -0
  144. agno/knowledge/reader/field_labeled_csv_reader.py +292 -0
  145. agno/knowledge/reader/firecrawl_reader.py +201 -0
  146. agno/knowledge/reader/json_reader.py +87 -0
  147. agno/knowledge/reader/markdown_reader.py +137 -0
  148. agno/knowledge/reader/pdf_reader.py +431 -0
  149. agno/knowledge/reader/pptx_reader.py +101 -0
  150. agno/knowledge/reader/reader_factory.py +313 -0
  151. agno/knowledge/reader/s3_reader.py +89 -0
  152. agno/knowledge/reader/tavily_reader.py +194 -0
  153. agno/knowledge/reader/text_reader.py +115 -0
  154. agno/knowledge/reader/web_search_reader.py +372 -0
  155. agno/knowledge/reader/website_reader.py +455 -0
  156. agno/knowledge/reader/wikipedia_reader.py +59 -0
  157. agno/knowledge/reader/youtube_reader.py +78 -0
  158. agno/knowledge/remote_content/__init__.py +0 -0
  159. agno/knowledge/remote_content/remote_content.py +88 -0
  160. agno/knowledge/reranker/__init__.py +3 -0
  161. agno/knowledge/reranker/base.py +14 -0
  162. agno/knowledge/reranker/cohere.py +64 -0
  163. agno/knowledge/reranker/infinity.py +195 -0
  164. agno/knowledge/reranker/sentence_transformer.py +54 -0
  165. agno/knowledge/types.py +39 -0
  166. agno/knowledge/utils.py +189 -0
  167. agno/media.py +462 -0
  168. agno/memory/__init__.py +3 -0
  169. agno/memory/manager.py +1327 -0
  170. agno/models/__init__.py +0 -0
  171. agno/models/aimlapi/__init__.py +5 -0
  172. agno/models/aimlapi/aimlapi.py +45 -0
  173. agno/models/anthropic/__init__.py +5 -0
  174. agno/models/anthropic/claude.py +757 -0
  175. agno/models/aws/__init__.py +15 -0
  176. agno/models/aws/bedrock.py +701 -0
  177. agno/models/aws/claude.py +378 -0
  178. agno/models/azure/__init__.py +18 -0
  179. agno/models/azure/ai_foundry.py +485 -0
  180. agno/models/azure/openai_chat.py +131 -0
  181. agno/models/base.py +2175 -0
  182. agno/models/cerebras/__init__.py +12 -0
  183. agno/models/cerebras/cerebras.py +501 -0
  184. agno/models/cerebras/cerebras_openai.py +112 -0
  185. agno/models/cohere/__init__.py +5 -0
  186. agno/models/cohere/chat.py +389 -0
  187. agno/models/cometapi/__init__.py +5 -0
  188. agno/models/cometapi/cometapi.py +57 -0
  189. agno/models/dashscope/__init__.py +5 -0
  190. agno/models/dashscope/dashscope.py +91 -0
  191. agno/models/deepinfra/__init__.py +5 -0
  192. agno/models/deepinfra/deepinfra.py +28 -0
  193. agno/models/deepseek/__init__.py +5 -0
  194. agno/models/deepseek/deepseek.py +61 -0
  195. agno/models/defaults.py +1 -0
  196. agno/models/fireworks/__init__.py +5 -0
  197. agno/models/fireworks/fireworks.py +26 -0
  198. agno/models/google/__init__.py +5 -0
  199. agno/models/google/gemini.py +1085 -0
  200. agno/models/groq/__init__.py +5 -0
  201. agno/models/groq/groq.py +556 -0
  202. agno/models/huggingface/__init__.py +5 -0
  203. agno/models/huggingface/huggingface.py +491 -0
  204. agno/models/ibm/__init__.py +5 -0
  205. agno/models/ibm/watsonx.py +422 -0
  206. agno/models/internlm/__init__.py +3 -0
  207. agno/models/internlm/internlm.py +26 -0
  208. agno/models/langdb/__init__.py +1 -0
  209. agno/models/langdb/langdb.py +48 -0
  210. agno/models/litellm/__init__.py +14 -0
  211. agno/models/litellm/chat.py +468 -0
  212. agno/models/litellm/litellm_openai.py +25 -0
  213. agno/models/llama_cpp/__init__.py +5 -0
  214. agno/models/llama_cpp/llama_cpp.py +22 -0
  215. agno/models/lmstudio/__init__.py +5 -0
  216. agno/models/lmstudio/lmstudio.py +25 -0
  217. agno/models/message.py +434 -0
  218. agno/models/meta/__init__.py +12 -0
  219. agno/models/meta/llama.py +475 -0
  220. agno/models/meta/llama_openai.py +78 -0
  221. agno/models/metrics.py +120 -0
  222. agno/models/mistral/__init__.py +5 -0
  223. agno/models/mistral/mistral.py +432 -0
  224. agno/models/nebius/__init__.py +3 -0
  225. agno/models/nebius/nebius.py +54 -0
  226. agno/models/nexus/__init__.py +3 -0
  227. agno/models/nexus/nexus.py +22 -0
  228. agno/models/nvidia/__init__.py +5 -0
  229. agno/models/nvidia/nvidia.py +28 -0
  230. agno/models/ollama/__init__.py +5 -0
  231. agno/models/ollama/chat.py +441 -0
  232. agno/models/openai/__init__.py +9 -0
  233. agno/models/openai/chat.py +883 -0
  234. agno/models/openai/like.py +27 -0
  235. agno/models/openai/responses.py +1050 -0
  236. agno/models/openrouter/__init__.py +5 -0
  237. agno/models/openrouter/openrouter.py +66 -0
  238. agno/models/perplexity/__init__.py +5 -0
  239. agno/models/perplexity/perplexity.py +187 -0
  240. agno/models/portkey/__init__.py +3 -0
  241. agno/models/portkey/portkey.py +81 -0
  242. agno/models/requesty/__init__.py +5 -0
  243. agno/models/requesty/requesty.py +52 -0
  244. agno/models/response.py +199 -0
  245. agno/models/sambanova/__init__.py +5 -0
  246. agno/models/sambanova/sambanova.py +28 -0
  247. agno/models/siliconflow/__init__.py +5 -0
  248. agno/models/siliconflow/siliconflow.py +25 -0
  249. agno/models/together/__init__.py +5 -0
  250. agno/models/together/together.py +25 -0
  251. agno/models/utils.py +266 -0
  252. agno/models/vercel/__init__.py +3 -0
  253. agno/models/vercel/v0.py +26 -0
  254. agno/models/vertexai/__init__.py +0 -0
  255. agno/models/vertexai/claude.py +70 -0
  256. agno/models/vllm/__init__.py +3 -0
  257. agno/models/vllm/vllm.py +78 -0
  258. agno/models/xai/__init__.py +3 -0
  259. agno/models/xai/xai.py +113 -0
  260. agno/os/__init__.py +3 -0
  261. agno/os/app.py +876 -0
  262. agno/os/auth.py +57 -0
  263. agno/os/config.py +104 -0
  264. agno/os/interfaces/__init__.py +1 -0
  265. agno/os/interfaces/a2a/__init__.py +3 -0
  266. agno/os/interfaces/a2a/a2a.py +42 -0
  267. agno/os/interfaces/a2a/router.py +250 -0
  268. agno/os/interfaces/a2a/utils.py +924 -0
  269. agno/os/interfaces/agui/__init__.py +3 -0
  270. agno/os/interfaces/agui/agui.py +47 -0
  271. agno/os/interfaces/agui/router.py +144 -0
  272. agno/os/interfaces/agui/utils.py +534 -0
  273. agno/os/interfaces/base.py +25 -0
  274. agno/os/interfaces/slack/__init__.py +3 -0
  275. agno/os/interfaces/slack/router.py +148 -0
  276. agno/os/interfaces/slack/security.py +30 -0
  277. agno/os/interfaces/slack/slack.py +47 -0
  278. agno/os/interfaces/whatsapp/__init__.py +3 -0
  279. agno/os/interfaces/whatsapp/router.py +211 -0
  280. agno/os/interfaces/whatsapp/security.py +53 -0
  281. agno/os/interfaces/whatsapp/whatsapp.py +36 -0
  282. agno/os/mcp.py +292 -0
  283. agno/os/middleware/__init__.py +7 -0
  284. agno/os/middleware/jwt.py +233 -0
  285. agno/os/router.py +1763 -0
  286. agno/os/routers/__init__.py +3 -0
  287. agno/os/routers/evals/__init__.py +3 -0
  288. agno/os/routers/evals/evals.py +430 -0
  289. agno/os/routers/evals/schemas.py +142 -0
  290. agno/os/routers/evals/utils.py +162 -0
  291. agno/os/routers/health.py +31 -0
  292. agno/os/routers/home.py +52 -0
  293. agno/os/routers/knowledge/__init__.py +3 -0
  294. agno/os/routers/knowledge/knowledge.py +997 -0
  295. agno/os/routers/knowledge/schemas.py +178 -0
  296. agno/os/routers/memory/__init__.py +3 -0
  297. agno/os/routers/memory/memory.py +515 -0
  298. agno/os/routers/memory/schemas.py +62 -0
  299. agno/os/routers/metrics/__init__.py +3 -0
  300. agno/os/routers/metrics/metrics.py +190 -0
  301. agno/os/routers/metrics/schemas.py +47 -0
  302. agno/os/routers/session/__init__.py +3 -0
  303. agno/os/routers/session/session.py +997 -0
  304. agno/os/schema.py +1055 -0
  305. agno/os/settings.py +43 -0
  306. agno/os/utils.py +630 -0
  307. agno/py.typed +0 -0
  308. agno/reasoning/__init__.py +0 -0
  309. agno/reasoning/anthropic.py +80 -0
  310. agno/reasoning/azure_ai_foundry.py +67 -0
  311. agno/reasoning/deepseek.py +63 -0
  312. agno/reasoning/default.py +97 -0
  313. agno/reasoning/gemini.py +73 -0
  314. agno/reasoning/groq.py +71 -0
  315. agno/reasoning/helpers.py +63 -0
  316. agno/reasoning/ollama.py +67 -0
  317. agno/reasoning/openai.py +86 -0
  318. agno/reasoning/step.py +31 -0
  319. agno/reasoning/vertexai.py +76 -0
  320. agno/run/__init__.py +6 -0
  321. agno/run/agent.py +787 -0
  322. agno/run/base.py +229 -0
  323. agno/run/cancel.py +81 -0
  324. agno/run/messages.py +32 -0
  325. agno/run/team.py +753 -0
  326. agno/run/workflow.py +708 -0
  327. agno/session/__init__.py +10 -0
  328. agno/session/agent.py +295 -0
  329. agno/session/summary.py +265 -0
  330. agno/session/team.py +392 -0
  331. agno/session/workflow.py +205 -0
  332. agno/team/__init__.py +37 -0
  333. agno/team/team.py +8793 -0
  334. agno/tools/__init__.py +10 -0
  335. agno/tools/agentql.py +120 -0
  336. agno/tools/airflow.py +69 -0
  337. agno/tools/api.py +122 -0
  338. agno/tools/apify.py +314 -0
  339. agno/tools/arxiv.py +127 -0
  340. agno/tools/aws_lambda.py +53 -0
  341. agno/tools/aws_ses.py +66 -0
  342. agno/tools/baidusearch.py +89 -0
  343. agno/tools/bitbucket.py +292 -0
  344. agno/tools/brandfetch.py +213 -0
  345. agno/tools/bravesearch.py +106 -0
  346. agno/tools/brightdata.py +367 -0
  347. agno/tools/browserbase.py +209 -0
  348. agno/tools/calcom.py +255 -0
  349. agno/tools/calculator.py +151 -0
  350. agno/tools/cartesia.py +187 -0
  351. agno/tools/clickup.py +244 -0
  352. agno/tools/confluence.py +240 -0
  353. agno/tools/crawl4ai.py +158 -0
  354. agno/tools/csv_toolkit.py +185 -0
  355. agno/tools/dalle.py +110 -0
  356. agno/tools/daytona.py +475 -0
  357. agno/tools/decorator.py +262 -0
  358. agno/tools/desi_vocal.py +108 -0
  359. agno/tools/discord.py +161 -0
  360. agno/tools/docker.py +716 -0
  361. agno/tools/duckdb.py +379 -0
  362. agno/tools/duckduckgo.py +91 -0
  363. agno/tools/e2b.py +703 -0
  364. agno/tools/eleven_labs.py +196 -0
  365. agno/tools/email.py +67 -0
  366. agno/tools/evm.py +129 -0
  367. agno/tools/exa.py +396 -0
  368. agno/tools/fal.py +127 -0
  369. agno/tools/file.py +240 -0
  370. agno/tools/file_generation.py +350 -0
  371. agno/tools/financial_datasets.py +288 -0
  372. agno/tools/firecrawl.py +143 -0
  373. agno/tools/function.py +1187 -0
  374. agno/tools/giphy.py +93 -0
  375. agno/tools/github.py +1760 -0
  376. agno/tools/gmail.py +922 -0
  377. agno/tools/google_bigquery.py +117 -0
  378. agno/tools/google_drive.py +270 -0
  379. agno/tools/google_maps.py +253 -0
  380. agno/tools/googlecalendar.py +674 -0
  381. agno/tools/googlesearch.py +98 -0
  382. agno/tools/googlesheets.py +377 -0
  383. agno/tools/hackernews.py +77 -0
  384. agno/tools/jina.py +101 -0
  385. agno/tools/jira.py +170 -0
  386. agno/tools/knowledge.py +218 -0
  387. agno/tools/linear.py +426 -0
  388. agno/tools/linkup.py +58 -0
  389. agno/tools/local_file_system.py +90 -0
  390. agno/tools/lumalab.py +183 -0
  391. agno/tools/mcp/__init__.py +10 -0
  392. agno/tools/mcp/mcp.py +331 -0
  393. agno/tools/mcp/multi_mcp.py +347 -0
  394. agno/tools/mcp/params.py +24 -0
  395. agno/tools/mcp_toolbox.py +284 -0
  396. agno/tools/mem0.py +193 -0
  397. agno/tools/memori.py +339 -0
  398. agno/tools/memory.py +419 -0
  399. agno/tools/mlx_transcribe.py +139 -0
  400. agno/tools/models/__init__.py +0 -0
  401. agno/tools/models/azure_openai.py +190 -0
  402. agno/tools/models/gemini.py +203 -0
  403. agno/tools/models/groq.py +158 -0
  404. agno/tools/models/morph.py +186 -0
  405. agno/tools/models/nebius.py +124 -0
  406. agno/tools/models_labs.py +195 -0
  407. agno/tools/moviepy_video.py +349 -0
  408. agno/tools/neo4j.py +134 -0
  409. agno/tools/newspaper.py +46 -0
  410. agno/tools/newspaper4k.py +93 -0
  411. agno/tools/notion.py +204 -0
  412. agno/tools/openai.py +202 -0
  413. agno/tools/openbb.py +160 -0
  414. agno/tools/opencv.py +321 -0
  415. agno/tools/openweather.py +233 -0
  416. agno/tools/oxylabs.py +385 -0
  417. agno/tools/pandas.py +102 -0
  418. agno/tools/parallel.py +314 -0
  419. agno/tools/postgres.py +257 -0
  420. agno/tools/pubmed.py +188 -0
  421. agno/tools/python.py +205 -0
  422. agno/tools/reasoning.py +283 -0
  423. agno/tools/reddit.py +467 -0
  424. agno/tools/replicate.py +117 -0
  425. agno/tools/resend.py +62 -0
  426. agno/tools/scrapegraph.py +222 -0
  427. agno/tools/searxng.py +152 -0
  428. agno/tools/serpapi.py +116 -0
  429. agno/tools/serper.py +255 -0
  430. agno/tools/shell.py +53 -0
  431. agno/tools/slack.py +136 -0
  432. agno/tools/sleep.py +20 -0
  433. agno/tools/spider.py +116 -0
  434. agno/tools/sql.py +154 -0
  435. agno/tools/streamlit/__init__.py +0 -0
  436. agno/tools/streamlit/components.py +113 -0
  437. agno/tools/tavily.py +254 -0
  438. agno/tools/telegram.py +48 -0
  439. agno/tools/todoist.py +218 -0
  440. agno/tools/tool_registry.py +1 -0
  441. agno/tools/toolkit.py +146 -0
  442. agno/tools/trafilatura.py +388 -0
  443. agno/tools/trello.py +274 -0
  444. agno/tools/twilio.py +186 -0
  445. agno/tools/user_control_flow.py +78 -0
  446. agno/tools/valyu.py +228 -0
  447. agno/tools/visualization.py +467 -0
  448. agno/tools/webbrowser.py +28 -0
  449. agno/tools/webex.py +76 -0
  450. agno/tools/website.py +54 -0
  451. agno/tools/webtools.py +45 -0
  452. agno/tools/whatsapp.py +286 -0
  453. agno/tools/wikipedia.py +63 -0
  454. agno/tools/workflow.py +278 -0
  455. agno/tools/x.py +335 -0
  456. agno/tools/yfinance.py +257 -0
  457. agno/tools/youtube.py +184 -0
  458. agno/tools/zendesk.py +82 -0
  459. agno/tools/zep.py +454 -0
  460. agno/tools/zoom.py +382 -0
  461. agno/utils/__init__.py +0 -0
  462. agno/utils/agent.py +820 -0
  463. agno/utils/audio.py +49 -0
  464. agno/utils/certs.py +27 -0
  465. agno/utils/code_execution.py +11 -0
  466. agno/utils/common.py +132 -0
  467. agno/utils/dttm.py +13 -0
  468. agno/utils/enum.py +22 -0
  469. agno/utils/env.py +11 -0
  470. agno/utils/events.py +696 -0
  471. agno/utils/format_str.py +16 -0
  472. agno/utils/functions.py +166 -0
  473. agno/utils/gemini.py +426 -0
  474. agno/utils/hooks.py +57 -0
  475. agno/utils/http.py +74 -0
  476. agno/utils/json_schema.py +234 -0
  477. agno/utils/knowledge.py +36 -0
  478. agno/utils/location.py +19 -0
  479. agno/utils/log.py +255 -0
  480. agno/utils/mcp.py +214 -0
  481. agno/utils/media.py +352 -0
  482. agno/utils/merge_dict.py +41 -0
  483. agno/utils/message.py +118 -0
  484. agno/utils/models/__init__.py +0 -0
  485. agno/utils/models/ai_foundry.py +43 -0
  486. agno/utils/models/claude.py +358 -0
  487. agno/utils/models/cohere.py +87 -0
  488. agno/utils/models/llama.py +78 -0
  489. agno/utils/models/mistral.py +98 -0
  490. agno/utils/models/openai_responses.py +140 -0
  491. agno/utils/models/schema_utils.py +153 -0
  492. agno/utils/models/watsonx.py +41 -0
  493. agno/utils/openai.py +257 -0
  494. agno/utils/pickle.py +32 -0
  495. agno/utils/pprint.py +178 -0
  496. agno/utils/print_response/__init__.py +0 -0
  497. agno/utils/print_response/agent.py +842 -0
  498. agno/utils/print_response/team.py +1724 -0
  499. agno/utils/print_response/workflow.py +1668 -0
  500. agno/utils/prompts.py +111 -0
  501. agno/utils/reasoning.py +108 -0
  502. agno/utils/response.py +163 -0
  503. agno/utils/response_iterator.py +17 -0
  504. agno/utils/safe_formatter.py +24 -0
  505. agno/utils/serialize.py +32 -0
  506. agno/utils/shell.py +22 -0
  507. agno/utils/streamlit.py +487 -0
  508. agno/utils/string.py +231 -0
  509. agno/utils/team.py +139 -0
  510. agno/utils/timer.py +41 -0
  511. agno/utils/tools.py +102 -0
  512. agno/utils/web.py +23 -0
  513. agno/utils/whatsapp.py +305 -0
  514. agno/utils/yaml_io.py +25 -0
  515. agno/vectordb/__init__.py +3 -0
  516. agno/vectordb/base.py +127 -0
  517. agno/vectordb/cassandra/__init__.py +5 -0
  518. agno/vectordb/cassandra/cassandra.py +501 -0
  519. agno/vectordb/cassandra/extra_param_mixin.py +11 -0
  520. agno/vectordb/cassandra/index.py +13 -0
  521. agno/vectordb/chroma/__init__.py +5 -0
  522. agno/vectordb/chroma/chromadb.py +929 -0
  523. agno/vectordb/clickhouse/__init__.py +9 -0
  524. agno/vectordb/clickhouse/clickhousedb.py +835 -0
  525. agno/vectordb/clickhouse/index.py +9 -0
  526. agno/vectordb/couchbase/__init__.py +3 -0
  527. agno/vectordb/couchbase/couchbase.py +1442 -0
  528. agno/vectordb/distance.py +7 -0
  529. agno/vectordb/lancedb/__init__.py +6 -0
  530. agno/vectordb/lancedb/lance_db.py +995 -0
  531. agno/vectordb/langchaindb/__init__.py +5 -0
  532. agno/vectordb/langchaindb/langchaindb.py +163 -0
  533. agno/vectordb/lightrag/__init__.py +5 -0
  534. agno/vectordb/lightrag/lightrag.py +388 -0
  535. agno/vectordb/llamaindex/__init__.py +3 -0
  536. agno/vectordb/llamaindex/llamaindexdb.py +166 -0
  537. agno/vectordb/milvus/__init__.py +4 -0
  538. agno/vectordb/milvus/milvus.py +1182 -0
  539. agno/vectordb/mongodb/__init__.py +9 -0
  540. agno/vectordb/mongodb/mongodb.py +1417 -0
  541. agno/vectordb/pgvector/__init__.py +12 -0
  542. agno/vectordb/pgvector/index.py +23 -0
  543. agno/vectordb/pgvector/pgvector.py +1462 -0
  544. agno/vectordb/pineconedb/__init__.py +5 -0
  545. agno/vectordb/pineconedb/pineconedb.py +747 -0
  546. agno/vectordb/qdrant/__init__.py +5 -0
  547. agno/vectordb/qdrant/qdrant.py +1134 -0
  548. agno/vectordb/redis/__init__.py +9 -0
  549. agno/vectordb/redis/redisdb.py +694 -0
  550. agno/vectordb/search.py +7 -0
  551. agno/vectordb/singlestore/__init__.py +10 -0
  552. agno/vectordb/singlestore/index.py +41 -0
  553. agno/vectordb/singlestore/singlestore.py +763 -0
  554. agno/vectordb/surrealdb/__init__.py +3 -0
  555. agno/vectordb/surrealdb/surrealdb.py +699 -0
  556. agno/vectordb/upstashdb/__init__.py +5 -0
  557. agno/vectordb/upstashdb/upstashdb.py +718 -0
  558. agno/vectordb/weaviate/__init__.py +8 -0
  559. agno/vectordb/weaviate/index.py +15 -0
  560. agno/vectordb/weaviate/weaviate.py +1005 -0
  561. agno/workflow/__init__.py +23 -0
  562. agno/workflow/agent.py +299 -0
  563. agno/workflow/condition.py +738 -0
  564. agno/workflow/loop.py +735 -0
  565. agno/workflow/parallel.py +824 -0
  566. agno/workflow/router.py +702 -0
  567. agno/workflow/step.py +1432 -0
  568. agno/workflow/steps.py +592 -0
  569. agno/workflow/types.py +520 -0
  570. agno/workflow/workflow.py +4321 -0
  571. agno-2.2.13.dist-info/METADATA +614 -0
  572. agno-2.2.13.dist-info/RECORD +575 -0
  573. agno-2.2.13.dist-info/WHEEL +5 -0
  574. agno-2.2.13.dist-info/licenses/LICENSE +201 -0
  575. agno-2.2.13.dist-info/top_level.txt +1 -0
agno/tools/linear.py ADDED
@@ -0,0 +1,426 @@
1
+ from os import getenv
2
+ from typing import Any, List, Optional
3
+
4
+ import requests
5
+
6
+ from agno.tools import Toolkit
7
+ from agno.utils.log import log_info, logger
8
+
9
+
10
+ class LinearTools(Toolkit):
11
+ def __init__(
12
+ self,
13
+ api_key: Optional[str] = None,
14
+ **kwargs,
15
+ ):
16
+ self.api_key = api_key or getenv("LINEAR_API_KEY")
17
+
18
+ if not self.api_key:
19
+ raise ValueError("Linear API key is required")
20
+
21
+ self.endpoint = "https://api.linear.app/graphql"
22
+ self.headers = {"Authorization": f"{self.api_key}"}
23
+
24
+ tools: List[Any] = [
25
+ self.get_user_details,
26
+ self.get_teams_details,
27
+ self.get_issue_details,
28
+ self.create_issue,
29
+ self.update_issue,
30
+ self.get_user_assigned_issues,
31
+ self.get_workflow_issues,
32
+ self.get_high_priority_issues,
33
+ ]
34
+
35
+ super().__init__(name="linear_tools", tools=tools, **kwargs)
36
+
37
+ def _execute_query(self, query, variables=None):
38
+ """Helper method to execute GraphQL queries with optional variables."""
39
+
40
+ try:
41
+ response = requests.post(self.endpoint, json={"query": query, "variables": variables}, headers=self.headers)
42
+ response.raise_for_status()
43
+
44
+ data = response.json()
45
+
46
+ if "errors" in data:
47
+ logger.error(f"GraphQL Error: {data['errors']}")
48
+ raise Exception(f"GraphQL Error: {data['errors']}")
49
+
50
+ log_info("GraphQL query executed successfully.")
51
+ return data.get("data")
52
+
53
+ except requests.exceptions.RequestException as e:
54
+ logger.error(f"Request error: {e}")
55
+ raise
56
+
57
+ except Exception as e:
58
+ logger.error(f"Unexpected error: {e}")
59
+ raise
60
+
61
+ def get_user_details(self) -> Optional[str]:
62
+ """
63
+ Fetch authenticated user details.
64
+ It will return the user's unique ID, name, and email address from the viewer object in the GraphQL response.
65
+
66
+ Returns:
67
+ str or None: A string containing user details like user id, name, and email.
68
+
69
+ Raises:
70
+ Exception: If an error occurs during the query execution or data retrieval.
71
+ """
72
+
73
+ query = """
74
+ query Me {
75
+ viewer {
76
+ id
77
+ name
78
+ email
79
+ }
80
+ }
81
+ """
82
+
83
+ try:
84
+ response = self._execute_query(query)
85
+
86
+ if response.get("viewer"):
87
+ user = response["viewer"]
88
+ log_info(
89
+ f"Retrieved authenticated user details with name: {user['name']}, ID: {user['id']}, Email: {user['email']}"
90
+ )
91
+ return str(user)
92
+ else:
93
+ logger.error("Failed to retrieve the current user details")
94
+ return None
95
+
96
+ except Exception as e:
97
+ logger.error(f"Error fetching authenticated user details: {e}")
98
+ raise
99
+
100
+ def get_teams_details(self) -> Optional[str]:
101
+ """
102
+ Fetch the list of authenticated teams.
103
+ It will return the unique ID and team name for each team, from the viewer object in the GraphQL response.
104
+
105
+ Returns:
106
+ str or None: A dictionary containing team details like team name, id.
107
+
108
+ Raises:
109
+ Exception: If an error occurs during the query execution or data retrieval.
110
+ """
111
+
112
+ query = """
113
+ query Teams {
114
+ teams {
115
+ nodes {
116
+ id
117
+ name
118
+ }
119
+ }
120
+ }
121
+ """
122
+
123
+ try:
124
+ response = self._execute_query(query)
125
+
126
+ if response.get("teams"):
127
+ teams = response["teams"]["nodes"]
128
+ log_info(f"Retrieved authenticated team details: {teams}")
129
+ return str(teams)
130
+ else:
131
+ logger.error("Failed to retrieve the current user details")
132
+ return None
133
+
134
+ except Exception as e:
135
+ logger.error(f"Error fetching authenticated user details: {e}")
136
+ raise
137
+
138
+ def get_issue_details(self, issue_id: str) -> Optional[str]:
139
+ """
140
+ Retrieve details of a specific issue by issue ID.
141
+
142
+ Args:
143
+ issue_id (str): The unique identifier of the issue to retrieve.
144
+
145
+ Returns:
146
+ str or None: A string containing issue details like issue id, issue title, and issue description.
147
+ Returns `None` if the issue is not found.
148
+
149
+ Raises:
150
+ Exception: If an error occurs during the query execution or data retrieval.
151
+ """
152
+
153
+ query = """
154
+ query IssueDetails ($issueId: String!){
155
+ issue(id: $issueId) {
156
+ id
157
+ title
158
+ description
159
+ }
160
+ }
161
+ """
162
+ variables = {"issueId": issue_id}
163
+ try:
164
+ response = self._execute_query(query, variables)
165
+
166
+ if response.get("issue"):
167
+ issue = response["issue"]
168
+ log_info(f"Issue '{issue['title']}' retrieved successfully with ID {issue['id']}.")
169
+ return str(issue)
170
+ else:
171
+ logger.error(f"Failed to retrieve issue with ID {issue_id}.")
172
+ return None
173
+
174
+ except Exception as e:
175
+ logger.error(f"Error retrieving issue with ID {issue_id}: {e}")
176
+ raise
177
+
178
+ def create_issue(
179
+ self,
180
+ title: str,
181
+ description: str,
182
+ team_id: str,
183
+ project_id: Optional[str] = None,
184
+ assignee_id: Optional[str] = None,
185
+ ) -> Optional[str]:
186
+ """
187
+ Create a new issue within a specific project and team.
188
+
189
+ Args:
190
+ title (str): The title of the new issue.
191
+ description (str): The description of the new issue.
192
+ team_id (str): The unique identifier of the team in which to create the issue.
193
+ project_id (Optional[str]): The ID of the project (optional).
194
+ assignee_id (Optional[str]): The ID of the assignee (optional).
195
+
196
+ Returns:
197
+ str or None: A string containing the created issue's details like issue id and issue title.
198
+ Returns `None` if the issue creation fails.
199
+
200
+ Raises:
201
+ Exception: If an error occurs during the mutation execution or data retrieval.
202
+ """
203
+
204
+ query = """
205
+ mutation IssueCreate ($title: String!, $description: String!, $teamId: String!, $projectId: String, $assigneeId: String){
206
+ issueCreate(
207
+ input: { title: $title, description: $description, teamId: $teamId, projectId: $projectId, assigneeId: $assigneeId}
208
+ ) {
209
+ success
210
+ issue {
211
+ id
212
+ title
213
+ url
214
+ }
215
+ }
216
+ }
217
+ """
218
+
219
+ variables = {
220
+ "title": title,
221
+ "description": description,
222
+ "teamId": team_id,
223
+ }
224
+ if project_id is not None:
225
+ variables["projectId"] = project_id
226
+ if assignee_id is not None:
227
+ variables["assigneeId"] = assignee_id
228
+
229
+ try:
230
+ response = self._execute_query(query, variables)
231
+ log_info(f"Response: {response}")
232
+
233
+ if response["issueCreate"]["success"]:
234
+ issue = response["issueCreate"]["issue"]
235
+ log_info(f"Issue '{issue['title']}' created successfully with ID {issue['id']}")
236
+ return str(issue)
237
+ else:
238
+ logger.error("Issue creation failed.")
239
+ return None
240
+
241
+ except Exception as e:
242
+ logger.error(f"Error creating issue '{title}' for team ID {team_id}: {e}")
243
+ raise
244
+
245
+ def update_issue(self, issue_id: str, title: Optional[str]) -> Optional[str]:
246
+ """
247
+ Update the title or state of a specific issue by issue ID.
248
+
249
+ Args:
250
+ issue_id (str): The unique identifier of the issue to update.
251
+ title (str, optional): The new title for the issue. If None, the title remains unchanged.
252
+
253
+ Returns:
254
+ str or None: A string containing the updated issue's details with issue id, issue title, and issue state (which includes `id` and `name`).
255
+ Returns `None` if the update is unsuccessful.
256
+
257
+ Raises:
258
+ Exception: If an error occurs during the mutation execution or data retrieval.
259
+ """
260
+
261
+ query = """
262
+ mutation IssueUpdate ($issueId: String!, $title: String!){
263
+ issueUpdate(
264
+ id: $issueId,
265
+ input: { title: $title}
266
+ ) {
267
+ success
268
+ issue {
269
+ id
270
+ title
271
+ state {
272
+ id
273
+ name
274
+ }
275
+ }
276
+ }
277
+ }
278
+ """
279
+ variables = {"issueId": issue_id, "title": title}
280
+
281
+ try:
282
+ response = self._execute_query(query, variables)
283
+
284
+ if response["issueUpdate"]["success"]:
285
+ issue = response["issueUpdate"]["issue"]
286
+ log_info(f"Issue ID {issue_id} updated successfully.")
287
+ return str(issue)
288
+ else:
289
+ logger.error(f"Failed to update issue ID {issue_id}. Success flag was false.")
290
+ return None
291
+
292
+ except Exception as e:
293
+ logger.error(f"Error updating issue ID {issue_id}: {e}")
294
+ raise
295
+
296
+ def get_user_assigned_issues(self, user_id: str) -> Optional[str]:
297
+ """
298
+ Retrieve issues assigned to a specific user by user ID.
299
+
300
+ Args:
301
+ user_id (str): The unique identifier of the user for whom to retrieve assigned issues.
302
+
303
+ Returns:
304
+ str or None: A string representing the assigned issues to user id,
305
+ where each issue contains issue details (e.g., `id`, `title`).
306
+ Returns None if the user or issues cannot be retrieved.
307
+
308
+ Raises:
309
+ Exception: If an error occurs while querying for the user's assigned issues.
310
+ """
311
+
312
+ query = """
313
+ query UserAssignedIssues($userId: String!) {
314
+ user(id: $userId) {
315
+ id
316
+ name
317
+ assignedIssues {
318
+ nodes {
319
+ id
320
+ title
321
+ }
322
+ }
323
+ }
324
+ }
325
+ """
326
+ variables = {"userId": user_id}
327
+
328
+ try:
329
+ response = self._execute_query(query, variables)
330
+
331
+ if response.get("user"):
332
+ user = response["user"]
333
+ issues = user["assignedIssues"]["nodes"]
334
+ log_info(f"Retrieved {len(issues)} issues assigned to user '{user['name']}' (ID: {user['id']}).")
335
+ return str(issues)
336
+ else:
337
+ logger.error("Failed to retrieve user or issues.")
338
+ return None
339
+
340
+ except Exception as e:
341
+ logger.error(f"Error retrieving issues for user ID {user_id}: {e}")
342
+ raise
343
+
344
+ def get_workflow_issues(self, workflow_id: str) -> Optional[str]:
345
+ """
346
+ Retrieve issues within a specific workflow state by workflow ID.
347
+
348
+ Args:
349
+ workflow_id (str): The unique identifier of the workflow state to retrieve issues from.
350
+
351
+ Returns:
352
+ str or None: A string representing the issues within the specified workflow state,
353
+ where each issue contains details of an issue (e.g., `title`).
354
+ Returns None if no issues are found or if the workflow state cannot be retrieved.
355
+
356
+ Raises:
357
+ Exception: If an error occurs while querying issues for the specified workflow state.
358
+ """
359
+
360
+ query = """
361
+ query WorkflowStateIssues($workflowId: String!) {
362
+ workflowState(id: $workflowId) {
363
+ issues {
364
+ nodes {
365
+ title
366
+ }
367
+ }
368
+ }
369
+ }
370
+ """
371
+ variables = {"workflowId": workflow_id}
372
+ try:
373
+ response = self._execute_query(query, variables)
374
+
375
+ if response.get("workflowState"):
376
+ issues = response["workflowState"]["issues"]["nodes"]
377
+ log_info(f"Retrieved {len(issues)} issues in workflow state ID {workflow_id}.")
378
+ return str(issues)
379
+ else:
380
+ logger.error("Failed to retrieve issues for the specified workflow state.")
381
+ return None
382
+
383
+ except Exception as e:
384
+ logger.error(f"Error retrieving issues for workflow state ID {workflow_id}: {e}")
385
+ raise
386
+
387
+ def get_high_priority_issues(self) -> Optional[str]:
388
+ """
389
+ Retrieve issues with a high priority (priority <= 2).
390
+
391
+ Returns:
392
+ str or None: A str representing high-priority issues, where it
393
+ contains details of an issue (e.g., `id`, `title`, `priority`).
394
+ Returns None if no issues are retrieved.
395
+
396
+ Raises:
397
+ Exception: If an error occurs during the query process.
398
+ """
399
+
400
+ query = """
401
+ query HighPriorityIssues {
402
+ issues(filter: {
403
+ priority: { lte: 2 }
404
+ }) {
405
+ nodes {
406
+ id
407
+ title
408
+ priority
409
+ }
410
+ }
411
+ }
412
+ """
413
+ try:
414
+ response = self._execute_query(query)
415
+
416
+ if response.get("issues"):
417
+ high_priority_issues = response["issues"]["nodes"]
418
+ log_info(f"Retrieved {len(high_priority_issues)} high-priority issues.")
419
+ return str(high_priority_issues)
420
+ else:
421
+ logger.error("Failed to retrieve high-priority issues.")
422
+ return None
423
+
424
+ except Exception as e:
425
+ logger.error(f"Error retrieving high-priority issues: {e}")
426
+ raise
agno/tools/linkup.py ADDED
@@ -0,0 +1,58 @@
1
+ from os import getenv
2
+ from typing import Any, List, Literal, Optional
3
+
4
+ from agno.tools import Toolkit
5
+ from agno.utils.log import logger
6
+
7
+ try:
8
+ from linkup import LinkupClient
9
+ except ImportError:
10
+ raise ImportError("`linkup-sdk` not installed. Please install using `pip install linkup-sdk`")
11
+
12
+
13
+ class LinkupTools(Toolkit):
14
+ def __init__(
15
+ self,
16
+ api_key: Optional[str] = None,
17
+ depth: Literal["standard", "deep"] = "standard",
18
+ output_type: Literal["sourcedAnswer", "searchResults"] = "searchResults",
19
+ enable_web_search_with_linkup: bool = True,
20
+ all: bool = False,
21
+ **kwargs,
22
+ ):
23
+ self.api_key = api_key or getenv("LINKUP_API_KEY")
24
+ if not self.api_key:
25
+ logger.error("LINKUP_API_KEY not set. Please set the LINKUP_API_KEY environment variable.")
26
+
27
+ self.linkup = LinkupClient(api_key=api_key)
28
+ self.depth = depth
29
+ self.output_type = output_type
30
+
31
+ tools: List[Any] = []
32
+ if all or enable_web_search_with_linkup:
33
+ tools.append(self.web_search_with_linkup)
34
+
35
+ super().__init__(name="linkup_tools", tools=tools, **kwargs)
36
+
37
+ def web_search_with_linkup(self, query: str, depth: Optional[str] = None, output_type: Optional[str] = None) -> str:
38
+ """
39
+ Use this function to search the web for a given query.
40
+ This function uses the Linkup API to provide realtime online information about the query.
41
+
42
+ Args:
43
+ query (str): Query to search for.
44
+ depth (str): (deep|standard) Depth of the search. Defaults to 'standard'.
45
+ output_type (str): (sourcedAnswer|searchResults) Type of output. Defaults to 'searchResults'.
46
+
47
+ Returns:
48
+ str: string of results related to the query.
49
+ """
50
+ try:
51
+ response = self.linkup.search(
52
+ query=query,
53
+ depth=depth or self.depth, # type: ignore
54
+ output_type=output_type or self.output_type, # type: ignore
55
+ )
56
+ return response
57
+ except Exception as e:
58
+ return f"Error: {str(e)}"
@@ -0,0 +1,90 @@
1
+ from pathlib import Path
2
+ from typing import Optional
3
+ from uuid import uuid4
4
+
5
+ from agno.tools import Toolkit
6
+ from agno.utils.log import log_debug, logger
7
+
8
+
9
+ class LocalFileSystemTools(Toolkit):
10
+ def __init__(
11
+ self,
12
+ target_directory: Optional[str] = None,
13
+ default_extension: str = "txt",
14
+ enable_write_file: bool = True,
15
+ all: bool = False,
16
+ **kwargs,
17
+ ):
18
+ """
19
+ Initialize the WriteToLocal toolkit.
20
+ Args:
21
+ target_directory (Optional[str]): Default directory to write files to. Creates if doesn't exist.
22
+ default_extension (str): Default file extension to use if none specified.
23
+ """
24
+
25
+ self.target_directory = target_directory or str(Path.cwd())
26
+ self.default_extension = default_extension.lstrip(".")
27
+
28
+ target_path = Path(self.target_directory)
29
+ target_path.mkdir(parents=True, exist_ok=True)
30
+
31
+ tools = []
32
+ if all or enable_write_file:
33
+ tools.append(self.write_file)
34
+
35
+ super().__init__(name="write_to_local", tools=tools, **kwargs)
36
+
37
+ def write_file(
38
+ self,
39
+ content: str,
40
+ filename: Optional[str] = None,
41
+ directory: Optional[str] = None,
42
+ extension: Optional[str] = None,
43
+ ) -> str:
44
+ """
45
+ Write content to a local file.
46
+ Args:
47
+ content (str): Content to write to the file
48
+ filename (Optional[str]): Name of the file. Defaults to UUID if not provided
49
+ directory (Optional[str]): Directory to write file to. Uses target_directory if not provided
50
+ extension (Optional[str]): File extension. Uses default_extension if not provided
51
+ Returns:
52
+ str: Path to the created file or error message
53
+ """
54
+ try:
55
+ filename = filename or str(uuid4())
56
+ directory = directory or self.target_directory
57
+ if filename and "." in filename:
58
+ path_obj = Path(filename)
59
+ filename = path_obj.stem
60
+ extension = extension or path_obj.suffix.lstrip(".")
61
+
62
+ log_debug(f"Writing file to local system: {filename}")
63
+
64
+ extension = (extension or self.default_extension).lstrip(".")
65
+
66
+ # Create directory if it doesn't exist
67
+ dir_path = Path(directory)
68
+ dir_path.mkdir(parents=True, exist_ok=True)
69
+
70
+ # Construct full filename with extension
71
+ full_filename = f"{filename}.{extension}"
72
+ file_path = dir_path / full_filename
73
+
74
+ file_path.write_text(content)
75
+
76
+ return f"Successfully wrote file to: {file_path}"
77
+
78
+ except Exception as e:
79
+ error_msg = f"Failed to write file: {str(e)}"
80
+ logger.error(error_msg)
81
+ return f"Error: {error_msg}"
82
+
83
+ def read_file(self, filename: str, directory: Optional[str] = None) -> str:
84
+ """
85
+ Read content from a local file.
86
+ """
87
+ file_path = Path(directory or self.target_directory) / filename
88
+ if not file_path.exists():
89
+ return f"File not found: {file_path}"
90
+ return file_path.read_text()