agno 0.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.
- agno/__init__.py +8 -0
- agno/agent/__init__.py +44 -5
- agno/agent/agent.py +10531 -2975
- agno/api/agent.py +14 -53
- agno/api/api.py +7 -46
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -25
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +6 -9
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +10 -10
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +22 -26
- agno/api/workflow.py +28 -0
- agno/cloud/aws/base.py +214 -0
- agno/cloud/aws/s3/__init__.py +2 -0
- agno/cloud/aws/s3/api_client.py +43 -0
- agno/cloud/aws/s3/bucket.py +195 -0
- agno/cloud/aws/s3/object.py +57 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +946 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2781 -0
- agno/db/dynamo/schemas.py +442 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +2379 -0
- agno/db/firestore/schemas.py +181 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1791 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1312 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1777 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +2597 -0
- agno/db/mongo/schemas.py +119 -0
- agno/db/mongo/utils.py +276 -0
- agno/db/mysql/__init__.py +4 -0
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +2923 -0
- agno/db/mysql/schemas.py +186 -0
- agno/db/mysql/utils.py +488 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +2870 -0
- agno/db/postgres/schemas.py +187 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +2141 -0
- agno/db/redis/schemas.py +159 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +34 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +61 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +179 -0
- agno/db/singlestore/singlestore.py +2877 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +181 -0
- agno/db/sqlite/sqlite.py +2908 -0
- agno/db/sqlite/utils.py +429 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +118 -0
- agno/eval/__init__.py +24 -0
- agno/eval/accuracy.py +666 -276
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +779 -0
- agno/eval/reliability.py +241 -62
- agno/eval/utils.py +120 -0
- agno/exceptions.py +143 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -1
- agno/{document → knowledge}/chunking/agentic.py +22 -14
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +7 -6
- agno/knowledge/chunking/markdown.py +151 -0
- agno/{document → knowledge}/chunking/recursive.py +15 -3
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +91 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/{document → knowledge/document}/base.py +12 -2
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/{embedder → knowledge/embedder}/base.py +8 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +3006 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +164 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +88 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +127 -0
- agno/knowledge/reader/web_search_reader.py +325 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +91 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +234 -0
- agno/media.py +439 -95
- agno/memory/__init__.py +16 -3
- agno/memory/manager.py +1474 -123
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +62 -0
- agno/models/anthropic/__init__.py +4 -0
- agno/models/anthropic/claude.py +960 -496
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +686 -451
- agno/models/aws/claude.py +190 -183
- agno/models/azure/__init__.py +18 -1
- agno/models/azure/ai_foundry.py +489 -0
- agno/models/azure/openai_chat.py +89 -40
- agno/models/base.py +2477 -550
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +565 -0
- agno/models/cerebras/cerebras_openai.py +131 -0
- agno/models/cohere/__init__.py +4 -0
- agno/models/cohere/chat.py +306 -492
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +74 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +90 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +45 -0
- agno/models/deepseek/__init__.py +4 -0
- agno/models/deepseek/deepseek.py +110 -9
- agno/models/fireworks/__init__.py +4 -0
- agno/models/fireworks/fireworks.py +19 -22
- agno/models/google/__init__.py +3 -7
- agno/models/google/gemini.py +1717 -662
- agno/models/google/utils.py +22 -0
- agno/models/groq/__init__.py +4 -0
- agno/models/groq/groq.py +391 -666
- agno/models/huggingface/__init__.py +4 -0
- agno/models/huggingface/huggingface.py +266 -538
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +432 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +20 -3
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +60 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +503 -0
- agno/models/litellm/litellm_openai.py +42 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +361 -39
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +502 -0
- agno/models/meta/llama_openai.py +79 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +4 -0
- agno/models/mistral/mistral.py +293 -393
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +53 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +4 -0
- agno/models/nvidia/nvidia.py +22 -3
- agno/models/ollama/__init__.py +4 -2
- agno/models/ollama/chat.py +257 -492
- agno/models/openai/__init__.py +7 -0
- agno/models/openai/chat.py +725 -770
- agno/models/openai/like.py +16 -2
- agno/models/openai/responses.py +1121 -0
- agno/models/openrouter/__init__.py +4 -0
- agno/models/openrouter/openrouter.py +62 -5
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +203 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +82 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +69 -0
- agno/models/response.py +177 -7
- agno/models/sambanova/__init__.py +4 -0
- agno/models/sambanova/sambanova.py +23 -4
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +42 -0
- agno/models/together/__init__.py +4 -0
- agno/models/together/together.py +21 -164
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +43 -0
- agno/models/vertexai/__init__.py +0 -1
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +83 -0
- agno/models/xai/__init__.py +2 -0
- agno/models/xai/xai.py +111 -7
- agno/os/__init__.py +3 -0
- agno/os/app.py +1027 -0
- agno/os/auth.py +244 -0
- agno/os/config.py +126 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +249 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +147 -0
- agno/os/interfaces/agui/utils.py +574 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +210 -0
- agno/os/interfaces/whatsapp/security.py +55 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +293 -0
- agno/os/middleware/__init__.py +9 -0
- agno/os/middleware/jwt.py +797 -0
- agno/os/router.py +258 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +450 -0
- agno/os/routers/evals/schemas.py +174 -0
- agno/os/routers/evals/utils.py +231 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +1008 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +661 -0
- agno/os/routers/memory/schemas.py +88 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +534 -0
- agno/os/scopes.py +469 -0
- agno/{playground → os}/settings.py +7 -15
- agno/os/utils.py +973 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +24 -1
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +2 -1
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +822 -0
- agno/run/base.py +247 -0
- agno/run/cancel.py +81 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +767 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +260 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +342 -0
- agno/session/workflow.py +501 -0
- agno/table.py +10 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +9536 -0
- agno/tools/__init__.py +7 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +22 -12
- agno/tools/api.py +122 -0
- agno/tools/apify.py +276 -83
- agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
- agno/tools/aws_lambda.py +28 -7
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +11 -4
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +32 -23
- agno/tools/calculator.py +24 -37
- agno/tools/cartesia.py +187 -0
- agno/tools/{clickup_tool.py → clickup.py} +17 -28
- agno/tools/confluence.py +91 -26
- agno/tools/crawl4ai.py +139 -43
- agno/tools/csv_toolkit.py +28 -22
- agno/tools/dalle.py +36 -22
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +169 -14
- agno/tools/desi_vocal.py +23 -11
- agno/tools/discord.py +32 -29
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +76 -81
- agno/tools/duckduckgo.py +43 -40
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +65 -54
- agno/tools/email.py +13 -5
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +324 -42
- agno/tools/fal.py +39 -35
- agno/tools/file.py +196 -30
- agno/tools/file_generation.py +356 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +108 -33
- agno/tools/function.py +960 -122
- agno/tools/giphy.py +34 -12
- agno/tools/github.py +1294 -97
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +271 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +607 -107
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +20 -12
- agno/tools/jina.py +24 -14
- agno/tools/jira.py +48 -19
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +82 -43
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +15 -7
- agno/tools/lumalab.py +41 -26
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +193 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +11 -9
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +163 -82
- agno/tools/moviepy_video.py +18 -13
- agno/tools/nano_banana.py +151 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +15 -4
- agno/tools/newspaper4k.py +19 -6
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +181 -17
- agno/tools/openbb.py +27 -20
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +25 -15
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +238 -185
- agno/tools/pubmed.py +125 -13
- agno/tools/python.py +48 -35
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +207 -29
- agno/tools/redshift.py +406 -0
- agno/tools/replicate.py +69 -26
- agno/tools/resend.py +11 -6
- agno/tools/scrapegraph.py +179 -19
- agno/tools/searxng.py +23 -31
- agno/tools/serpapi.py +15 -10
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +23 -12
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +56 -14
- agno/tools/sleep.py +8 -6
- agno/tools/spider.py +35 -11
- agno/tools/spotify.py +919 -0
- agno/tools/sql.py +34 -19
- agno/tools/tavily.py +158 -8
- agno/tools/telegram.py +18 -8
- agno/tools/todoist.py +218 -0
- agno/tools/toolkit.py +134 -9
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +25 -28
- agno/tools/twilio.py +18 -9
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +23 -19
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +28 -19
- agno/tools/workflow.py +285 -0
- agno/tools/{twitter.py → x.py} +142 -46
- agno/tools/yfinance.py +41 -39
- agno/tools/youtube.py +34 -17
- agno/tools/zendesk.py +15 -5
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +86 -37
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/audio.py +37 -1
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +103 -20
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +700 -0
- agno/utils/functions.py +107 -37
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +171 -0
- agno/utils/http.py +185 -0
- agno/utils/json_schema.py +159 -37
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +221 -8
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +335 -14
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +77 -2
- agno/utils/models/ai_foundry.py +50 -0
- agno/utils/models/claude.py +373 -0
- agno/utils/models/cohere.py +94 -0
- agno/utils/models/llama.py +85 -0
- agno/utils/models/mistral.py +100 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +1 -1
- agno/utils/pprint.py +124 -8
- agno/utils/print_response/agent.py +930 -0
- agno/utils/print_response/team.py +1914 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +4 -4
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +204 -51
- agno/utils/team.py +139 -0
- agno/utils/timer.py +9 -2
- agno/utils/tokens.py +657 -0
- agno/utils/tools.py +19 -1
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +3 -3
- agno/vectordb/__init__.py +2 -0
- agno/vectordb/base.py +87 -9
- agno/vectordb/cassandra/__init__.py +5 -1
- agno/vectordb/cassandra/cassandra.py +383 -27
- agno/vectordb/chroma/__init__.py +4 -0
- agno/vectordb/chroma/chromadb.py +748 -83
- agno/vectordb/clickhouse/__init__.py +7 -1
- agno/vectordb/clickhouse/clickhousedb.py +554 -53
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1446 -0
- agno/vectordb/lancedb/__init__.py +5 -0
- agno/vectordb/lancedb/lance_db.py +730 -98
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +3 -0
- agno/vectordb/milvus/milvus.py +966 -78
- agno/vectordb/mongodb/__init__.py +9 -1
- agno/vectordb/mongodb/mongodb.py +1175 -172
- agno/vectordb/pgvector/__init__.py +8 -0
- agno/vectordb/pgvector/pgvector.py +599 -115
- agno/vectordb/pineconedb/__init__.py +5 -1
- agno/vectordb/pineconedb/pineconedb.py +406 -43
- agno/vectordb/qdrant/__init__.py +4 -0
- agno/vectordb/qdrant/qdrant.py +914 -61
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/__init__.py +8 -1
- agno/vectordb/singlestore/singlestore.py +771 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +663 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1009 -0
- agno/workflow/__init__.py +23 -1
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +759 -0
- agno/workflow/loop.py +756 -0
- agno/workflow/parallel.py +853 -0
- agno/workflow/router.py +723 -0
- agno/workflow/step.py +1564 -0
- agno/workflow/steps.py +613 -0
- agno/workflow/types.py +556 -0
- agno/workflow/workflow.py +4327 -514
- agno-2.3.13.dist-info/METADATA +639 -0
- agno-2.3.13.dist-info/RECORD +613 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
- agno-2.3.13.dist-info/licenses/LICENSE +201 -0
- agno/api/playground.py +0 -91
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -22
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workspace.py +0 -151
- agno/cli/auth_server.py +0 -118
- agno/cli/config.py +0 -275
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -355
- agno/cli/settings.py +0 -85
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -1
- agno/document/chunking/semantic.py +0 -47
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -1
- agno/document/reader/arxiv_reader.py +0 -41
- agno/document/reader/base.py +0 -22
- agno/document/reader/csv_reader.py +0 -84
- agno/document/reader/docx_reader.py +0 -46
- agno/document/reader/firecrawl_reader.py +0 -99
- agno/document/reader/json_reader.py +0 -43
- agno/document/reader/pdf_reader.py +0 -219
- agno/document/reader/s3/pdf_reader.py +0 -46
- agno/document/reader/s3/text_reader.py +0 -51
- agno/document/reader/text_reader.py +0 -41
- agno/document/reader/website_reader.py +0 -175
- agno/document/reader/youtube_reader.py +0 -50
- agno/embedder/__init__.py +0 -1
- agno/embedder/azure_openai.py +0 -86
- agno/embedder/cohere.py +0 -72
- agno/embedder/fastembed.py +0 -37
- agno/embedder/google.py +0 -73
- agno/embedder/huggingface.py +0 -54
- agno/embedder/mistral.py +0 -80
- agno/embedder/ollama.py +0 -57
- agno/embedder/openai.py +0 -74
- agno/embedder/sentence_transformer.py +0 -38
- agno/embedder/voyageai.py +0 -64
- agno/eval/perf.py +0 -201
- agno/file/__init__.py +0 -1
- agno/file/file.py +0 -16
- agno/file/local/csv.py +0 -32
- agno/file/local/txt.py +0 -19
- agno/infra/app.py +0 -240
- agno/infra/base.py +0 -144
- agno/infra/context.py +0 -20
- agno/infra/db_app.py +0 -52
- agno/infra/resource.py +0 -205
- agno/infra/resources.py +0 -55
- agno/knowledge/agent.py +0 -230
- agno/knowledge/arxiv.py +0 -22
- agno/knowledge/combined.py +0 -22
- agno/knowledge/csv.py +0 -28
- agno/knowledge/csv_url.py +0 -19
- agno/knowledge/document.py +0 -20
- agno/knowledge/docx.py +0 -30
- agno/knowledge/json.py +0 -28
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/pdf.py +0 -28
- agno/knowledge/pdf_url.py +0 -26
- agno/knowledge/s3/base.py +0 -60
- agno/knowledge/s3/pdf.py +0 -21
- agno/knowledge/s3/text.py +0 -23
- agno/knowledge/text.py +0 -30
- agno/knowledge/website.py +0 -88
- agno/knowledge/wikipedia.py +0 -31
- agno/knowledge/youtube.py +0 -22
- agno/memory/agent.py +0 -392
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -1
- agno/memory/db/base.py +0 -42
- agno/memory/db/mongodb.py +0 -189
- agno/memory/db/postgres.py +0 -203
- agno/memory/db/sqlite.py +0 -193
- agno/memory/memory.py +0 -15
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -192
- agno/memory/summary.py +0 -19
- agno/memory/workflow.py +0 -38
- agno/models/google/gemini_openai.py +0 -26
- agno/models/ollama/hermes.py +0 -221
- agno/models/ollama/tools.py +0 -362
- agno/models/vertexai/gemini.py +0 -595
- agno/playground/__init__.py +0 -3
- agno/playground/async_router.py +0 -421
- agno/playground/deploy.py +0 -249
- agno/playground/operator.py +0 -92
- agno/playground/playground.py +0 -91
- agno/playground/schemas.py +0 -76
- agno/playground/serve.py +0 -55
- agno/playground/sync_router.py +0 -405
- agno/reasoning/agent.py +0 -68
- agno/run/response.py +0 -112
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/base.py +0 -38
- agno/storage/agent/dynamodb.py +0 -350
- agno/storage/agent/json.py +0 -92
- agno/storage/agent/mongodb.py +0 -228
- agno/storage/agent/postgres.py +0 -367
- agno/storage/agent/session.py +0 -79
- agno/storage/agent/singlestore.py +0 -303
- agno/storage/agent/sqlite.py +0 -357
- agno/storage/agent/yaml.py +0 -93
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/base.py +0 -40
- agno/storage/workflow/mongodb.py +0 -233
- agno/storage/workflow/postgres.py +0 -366
- agno/storage/workflow/session.py +0 -60
- agno/storage/workflow/sqlite.py +0 -359
- agno/tools/googlesearch.py +0 -88
- agno/utils/defaults.py +0 -57
- agno/utils/filesystem.py +0 -39
- agno/utils/git.py +0 -52
- agno/utils/json_io.py +0 -30
- agno/utils/load_env.py +0 -19
- agno/utils/py_io.py +0 -19
- agno/utils/pyproject.py +0 -18
- agno/utils/resource_filter.py +0 -31
- agno/vectordb/singlestore/s2vectordb.py +0 -390
- agno/vectordb/singlestore/s2vectordb2.py +0 -355
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -48
- agno/workspace/operator.py +0 -758
- agno/workspace/settings.py +0 -63
- agno-0.1.2.dist-info/LICENSE +0 -375
- agno-0.1.2.dist-info/METADATA +0 -502
- agno-0.1.2.dist-info/RECORD +0 -352
- agno-0.1.2.dist-info/entry_points.txt +0 -3
- /agno/{cli → db/migrations}/__init__.py +0 -0
- /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
- /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
- /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
- /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
- /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
- /agno/{reranker → utils/models}/__init__.py +0 -0
- /agno/{storage → utils/print_response}/__init__.py +0 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/tools/exa.py
CHANGED
|
@@ -1,24 +1,64 @@
|
|
|
1
1
|
import json
|
|
2
|
+
from concurrent.futures import ThreadPoolExecutor, TimeoutError
|
|
2
3
|
from os import getenv
|
|
3
|
-
from typing import Any, Dict, List, Optional
|
|
4
|
+
from typing import Any, Dict, List, Literal, Optional
|
|
4
5
|
|
|
5
6
|
from agno.tools import Toolkit
|
|
6
|
-
from agno.utils.log import logger
|
|
7
|
+
from agno.utils.log import log_debug, log_info, logger
|
|
7
8
|
|
|
8
9
|
try:
|
|
9
10
|
from exa_py import Exa
|
|
11
|
+
from exa_py.api import SearchResponse
|
|
10
12
|
except ImportError:
|
|
11
13
|
raise ImportError("`exa_py` not installed. Please install using `pip install exa_py`")
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
class ExaTools(Toolkit):
|
|
17
|
+
"""
|
|
18
|
+
ExaTools is a toolkit for interfacing with the Exa web search engine, providing
|
|
19
|
+
functionalities to perform categorized searches and retrieve structured results.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
enable_search (bool): Enable search functionality. Default is True.
|
|
23
|
+
enable_get_contents (bool): Enable get contents functionality. Default is True.
|
|
24
|
+
enable_find_similar (bool): Enable find similar functionality. Default is True.
|
|
25
|
+
enable_answer (bool): Enable answer generation. Default is True.
|
|
26
|
+
enable_research (bool): Enable research tool functionality. Default is False.
|
|
27
|
+
all (bool): Enable all tools. Overrides individual flags when True. Default is False.
|
|
28
|
+
text (bool): Retrieve text content from results. Default is True.
|
|
29
|
+
text_length_limit (int): Max length of text content per result. Default is 1000.
|
|
30
|
+
highlights (bool): Include highlighted snippets. Deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.
|
|
31
|
+
api_key (Optional[str]): Exa API key. Retrieved from `EXA_API_KEY` env variable if not provided.
|
|
32
|
+
num_results (Optional[int]): Default number of search results. Overrides individual searches if set.
|
|
33
|
+
start_crawl_date (Optional[str]): Include results crawled on/after this date (`YYYY-MM-DD`).
|
|
34
|
+
end_crawl_date (Optional[str]): Include results crawled on/before this date (`YYYY-MM-DD`).
|
|
35
|
+
start_published_date (Optional[str]): Include results published on/after this date (`YYYY-MM-DD`).
|
|
36
|
+
end_published_date (Optional[str]): Include results published on/before this date (`YYYY-MM-DD`).
|
|
37
|
+
use_autoprompt (Optional[bool]): Enable autoprompt features in queries. Deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.
|
|
38
|
+
type (Optional[str]): Specify content type (e.g., article, blog, video).
|
|
39
|
+
category (Optional[str]): Filter results by category. Options are "company", "research paper", "news", "pdf", "github", "tweet", "personal site", "linkedin profile", "financial report".
|
|
40
|
+
include_domains (Optional[List[str]]): Restrict results to these domains.
|
|
41
|
+
exclude_domains (Optional[List[str]]): Exclude results from these domains.
|
|
42
|
+
show_results (bool): Log search results for debugging. Default is False.
|
|
43
|
+
model (Optional[str]): The search model to use. Options are 'exa' or 'exa-pro'.
|
|
44
|
+
timeout (int): Maximum time in seconds to wait for API responses. Default is 30 seconds.
|
|
45
|
+
"""
|
|
46
|
+
|
|
15
47
|
def __init__(
|
|
16
48
|
self,
|
|
49
|
+
enable_search: bool = True,
|
|
50
|
+
enable_get_contents: bool = True,
|
|
51
|
+
enable_find_similar: bool = True,
|
|
52
|
+
enable_answer: bool = True,
|
|
53
|
+
enable_research: bool = False,
|
|
54
|
+
all: bool = False,
|
|
17
55
|
text: bool = True,
|
|
18
56
|
text_length_limit: int = 1000,
|
|
19
|
-
highlights: bool =
|
|
57
|
+
highlights: Optional[bool] = None, # Deprecated
|
|
58
|
+
summary: bool = False,
|
|
20
59
|
api_key: Optional[str] = None,
|
|
21
60
|
num_results: Optional[int] = None,
|
|
61
|
+
livecrawl: str = "always",
|
|
22
62
|
start_crawl_date: Optional[str] = None,
|
|
23
63
|
end_crawl_date: Optional[str] = None,
|
|
24
64
|
start_published_date: Optional[str] = None,
|
|
@@ -27,88 +67,330 @@ class ExaTools(Toolkit):
|
|
|
27
67
|
type: Optional[str] = None,
|
|
28
68
|
category: Optional[str] = None,
|
|
29
69
|
include_domains: Optional[List[str]] = None,
|
|
70
|
+
exclude_domains: Optional[List[str]] = None,
|
|
30
71
|
show_results: bool = False,
|
|
72
|
+
model: Optional[str] = None,
|
|
73
|
+
timeout: int = 30,
|
|
74
|
+
research_model: Literal["exa-research", "exa-research-pro"] = "exa-research",
|
|
75
|
+
**kwargs,
|
|
31
76
|
):
|
|
32
|
-
super().__init__(name="exa")
|
|
33
|
-
|
|
34
77
|
self.api_key = api_key or getenv("EXA_API_KEY")
|
|
35
78
|
if not self.api_key:
|
|
36
79
|
logger.error("EXA_API_KEY not set. Please set the EXA_API_KEY environment variable.")
|
|
37
80
|
|
|
81
|
+
self.exa = Exa(self.api_key)
|
|
38
82
|
self.show_results = show_results
|
|
83
|
+
self.timeout = timeout
|
|
39
84
|
|
|
40
85
|
self.text: bool = text
|
|
41
86
|
self.text_length_limit: int = text_length_limit
|
|
42
|
-
|
|
87
|
+
|
|
88
|
+
if highlights:
|
|
89
|
+
import warnings
|
|
90
|
+
|
|
91
|
+
warnings.warn(
|
|
92
|
+
"The 'highlights' parameter is deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.",
|
|
93
|
+
DeprecationWarning,
|
|
94
|
+
stacklevel=2,
|
|
95
|
+
)
|
|
96
|
+
if use_autoprompt:
|
|
97
|
+
import warnings
|
|
98
|
+
|
|
99
|
+
warnings.warn(
|
|
100
|
+
"The 'use_autoprompt' parameter is deprecated since it was removed in the Exa API. It will be removed from Agno in a future release.",
|
|
101
|
+
DeprecationWarning,
|
|
102
|
+
stacklevel=2,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
self.summary: bool = summary
|
|
43
106
|
self.num_results: Optional[int] = num_results
|
|
107
|
+
self.livecrawl: str = livecrawl
|
|
44
108
|
self.start_crawl_date: Optional[str] = start_crawl_date
|
|
45
109
|
self.end_crawl_date: Optional[str] = end_crawl_date
|
|
46
110
|
self.start_published_date: Optional[str] = start_published_date
|
|
47
111
|
self.end_published_date: Optional[str] = end_published_date
|
|
48
|
-
self.use_autoprompt: Optional[bool] = use_autoprompt
|
|
49
112
|
self.type: Optional[str] = type
|
|
50
|
-
self.include_domains: Optional[List[str]] = include_domains
|
|
51
113
|
self.category: Optional[str] = category
|
|
114
|
+
self.include_domains: Optional[List[str]] = include_domains
|
|
115
|
+
self.exclude_domains: Optional[List[str]] = exclude_domains
|
|
116
|
+
self.model: Optional[str] = model
|
|
117
|
+
self.research_model: Literal["exa-research", "exa-research-pro"] = research_model
|
|
118
|
+
|
|
119
|
+
tools: List[Any] = []
|
|
120
|
+
if all or enable_search:
|
|
121
|
+
tools.append(self.search_exa)
|
|
122
|
+
if all or enable_get_contents:
|
|
123
|
+
tools.append(self.get_contents)
|
|
124
|
+
if all or enable_find_similar:
|
|
125
|
+
tools.append(self.find_similar)
|
|
126
|
+
if all or enable_answer:
|
|
127
|
+
tools.append(self.exa_answer)
|
|
128
|
+
if all or enable_research:
|
|
129
|
+
tools.append(self.research)
|
|
130
|
+
|
|
131
|
+
super().__init__(name="exa", tools=tools, **kwargs)
|
|
132
|
+
|
|
133
|
+
def _execute_with_timeout(self, func, *args, **kwargs):
|
|
134
|
+
"""Execute a function with a timeout using a temporary ThreadPoolExecutor."""
|
|
135
|
+
with ThreadPoolExecutor(max_workers=1) as executor:
|
|
136
|
+
future = executor.submit(func, *args, **kwargs)
|
|
137
|
+
try:
|
|
138
|
+
return future.result(timeout=self.timeout)
|
|
139
|
+
except TimeoutError:
|
|
140
|
+
raise TimeoutError(f"Operation timed out after {self.timeout} seconds")
|
|
141
|
+
except Exception as e:
|
|
142
|
+
raise e
|
|
52
143
|
|
|
53
|
-
|
|
144
|
+
def _parse_results(self, exa_results: SearchResponse) -> str:
|
|
145
|
+
exa_results_parsed = []
|
|
146
|
+
for result in exa_results.results:
|
|
147
|
+
result_dict = {"url": result.url}
|
|
148
|
+
if result.title:
|
|
149
|
+
result_dict["title"] = result.title
|
|
150
|
+
if result.author and result.author != "":
|
|
151
|
+
result_dict["author"] = result.author
|
|
152
|
+
if result.published_date:
|
|
153
|
+
result_dict["published_date"] = result.published_date
|
|
154
|
+
if result.text:
|
|
155
|
+
_text = result.text
|
|
156
|
+
if self.text_length_limit:
|
|
157
|
+
_text = _text[: self.text_length_limit]
|
|
158
|
+
result_dict["text"] = _text
|
|
159
|
+
exa_results_parsed.append(result_dict)
|
|
160
|
+
return json.dumps(exa_results_parsed, indent=4, ensure_ascii=False)
|
|
54
161
|
|
|
55
|
-
def search_exa(self, query: str, num_results: int = 5) -> str:
|
|
162
|
+
def search_exa(self, query: str, num_results: int = 5, category: Optional[str] = None) -> str:
|
|
56
163
|
"""Use this function to search Exa (a web search engine) for a query.
|
|
57
164
|
|
|
58
165
|
Args:
|
|
59
166
|
query (str): The query to search for.
|
|
60
167
|
num_results (int): Number of results to return. Defaults to 5.
|
|
168
|
+
category (Optional[str]): The category to filter search results.
|
|
169
|
+
Options are "company", "research paper", "news", "pdf", "github",
|
|
170
|
+
"tweet", "personal site", "linkedin profile", "financial report".
|
|
61
171
|
|
|
62
172
|
Returns:
|
|
63
173
|
str: The search results in JSON format.
|
|
64
174
|
"""
|
|
65
|
-
if not self.api_key:
|
|
66
|
-
return "Please set the EXA_API_KEY"
|
|
67
|
-
|
|
68
175
|
try:
|
|
69
|
-
|
|
70
|
-
|
|
176
|
+
if self.show_results:
|
|
177
|
+
log_info(f"Searching exa for: {query}")
|
|
71
178
|
search_kwargs: Dict[str, Any] = {
|
|
72
179
|
"text": self.text,
|
|
73
|
-
"
|
|
180
|
+
"summary": self.summary,
|
|
74
181
|
"num_results": self.num_results or num_results,
|
|
75
182
|
"start_crawl_date": self.start_crawl_date,
|
|
76
183
|
"end_crawl_date": self.end_crawl_date,
|
|
77
184
|
"start_published_date": self.start_published_date,
|
|
78
185
|
"end_published_date": self.end_published_date,
|
|
79
|
-
"use_autoprompt": self.use_autoprompt,
|
|
80
186
|
"type": self.type,
|
|
81
|
-
"category": self.category,
|
|
187
|
+
"category": self.category or category, # Prefer a user-set category
|
|
82
188
|
"include_domains": self.include_domains,
|
|
189
|
+
"exclude_domains": self.exclude_domains,
|
|
83
190
|
}
|
|
84
191
|
# Clean up the kwargs
|
|
85
192
|
search_kwargs = {k: v for k, v in search_kwargs.items() if v is not None}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if result.author and result.author != "":
|
|
93
|
-
result_dict["author"] = result.author
|
|
94
|
-
if result.published_date:
|
|
95
|
-
result_dict["published_date"] = result.published_date
|
|
96
|
-
if result.text:
|
|
97
|
-
_text = result.text
|
|
98
|
-
if self.text_length_limit:
|
|
99
|
-
_text = _text[: self.text_length_limit]
|
|
100
|
-
result_dict["text"] = _text
|
|
101
|
-
if self.highlights:
|
|
102
|
-
try:
|
|
103
|
-
if result.highlights: # type: ignore
|
|
104
|
-
result_dict["highlights"] = result.highlights # type: ignore
|
|
105
|
-
except Exception as e:
|
|
106
|
-
logger.debug(f"Failed to get highlights {e}")
|
|
107
|
-
exa_results_parsed.append(result_dict)
|
|
108
|
-
parsed_results = json.dumps(exa_results_parsed, indent=4)
|
|
193
|
+
|
|
194
|
+
# Execute search with timeout
|
|
195
|
+
exa_results = self._execute_with_timeout(self.exa.search_and_contents, query, **search_kwargs)
|
|
196
|
+
|
|
197
|
+
parsed_results = self._parse_results(exa_results)
|
|
198
|
+
# Extract search results
|
|
109
199
|
if self.show_results:
|
|
110
|
-
|
|
200
|
+
log_info(parsed_results)
|
|
111
201
|
return parsed_results
|
|
202
|
+
except TimeoutError as e:
|
|
203
|
+
logger.error(f"Search timed out after {self.timeout} seconds")
|
|
204
|
+
return f"Error: {str(e)}"
|
|
112
205
|
except Exception as e:
|
|
113
206
|
logger.error(f"Failed to search exa {e}")
|
|
114
207
|
return f"Error: {e}"
|
|
208
|
+
|
|
209
|
+
def get_contents(self, urls: list[str]) -> str:
|
|
210
|
+
"""
|
|
211
|
+
Retrieve detailed content from specific URLs using the Exa API.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
urls (list(str)): A list of URLs from which to fetch content.
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
str: The search results in JSON format.
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
query_kwargs: Dict[str, Any] = {
|
|
221
|
+
"text": self.text,
|
|
222
|
+
"summary": self.summary,
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
try:
|
|
226
|
+
if self.show_results:
|
|
227
|
+
log_info(f"Fetching contents for URLs: {urls}")
|
|
228
|
+
|
|
229
|
+
# Execute get_contents with timeout
|
|
230
|
+
exa_results = self._execute_with_timeout(self.exa.get_contents, urls=urls, **query_kwargs)
|
|
231
|
+
|
|
232
|
+
parsed_results = self._parse_results(exa_results)
|
|
233
|
+
if self.show_results:
|
|
234
|
+
log_info(parsed_results)
|
|
235
|
+
|
|
236
|
+
return parsed_results
|
|
237
|
+
except TimeoutError as e:
|
|
238
|
+
logger.error(f"Get contents timed out after {self.timeout} seconds")
|
|
239
|
+
return f"Error: {str(e)}"
|
|
240
|
+
except Exception as e:
|
|
241
|
+
logger.error(f"Failed to get contents from Exa: {e}")
|
|
242
|
+
return f"Error: {e}"
|
|
243
|
+
|
|
244
|
+
def find_similar(self, url: str, num_results: int = 5) -> str:
|
|
245
|
+
"""
|
|
246
|
+
Find similar links to a given URL using the Exa API.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
url (str): The URL for which to find similar links.
|
|
250
|
+
num_results (int, optional): The number of similar links to return. Defaults to 5.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
str: The search results in JSON format.
|
|
254
|
+
"""
|
|
255
|
+
|
|
256
|
+
query_kwargs: Dict[str, Any] = {
|
|
257
|
+
"text": self.text,
|
|
258
|
+
"summary": self.summary,
|
|
259
|
+
"include_domains": self.include_domains,
|
|
260
|
+
"exclude_domains": self.exclude_domains,
|
|
261
|
+
"start_crawl_date": self.start_crawl_date,
|
|
262
|
+
"end_crawl_date": self.end_crawl_date,
|
|
263
|
+
"start_published_date": self.start_published_date,
|
|
264
|
+
"end_published_date": self.end_published_date,
|
|
265
|
+
"num_results": self.num_results or num_results,
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
try:
|
|
269
|
+
if self.show_results:
|
|
270
|
+
log_info(f"Finding similar links to: {url}")
|
|
271
|
+
|
|
272
|
+
# Execute find_similar with timeout
|
|
273
|
+
exa_results = self._execute_with_timeout(self.exa.find_similar_and_contents, url=url, **query_kwargs)
|
|
274
|
+
|
|
275
|
+
parsed_results = self._parse_results(exa_results)
|
|
276
|
+
if self.show_results:
|
|
277
|
+
log_info(parsed_results)
|
|
278
|
+
|
|
279
|
+
return parsed_results
|
|
280
|
+
except TimeoutError as e:
|
|
281
|
+
logger.error(f"Find similar timed out after {self.timeout} seconds")
|
|
282
|
+
return f"Error: {str(e)}"
|
|
283
|
+
except Exception as e:
|
|
284
|
+
logger.error(f"Failed to get similar links from Exa: {e}")
|
|
285
|
+
return f"Error: {e}"
|
|
286
|
+
|
|
287
|
+
def exa_answer(self, query: str, text: bool = False) -> str:
|
|
288
|
+
"""
|
|
289
|
+
Get an LLM answer to a question informed by Exa search results.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
query (str): The question or query to answer.
|
|
293
|
+
text (bool): Include full text from citation. Default is False.
|
|
294
|
+
Returns:
|
|
295
|
+
str: The answer results in JSON format with both generated answer and sources.
|
|
296
|
+
"""
|
|
297
|
+
|
|
298
|
+
if self.model and self.model not in ["exa", "exa-pro"]:
|
|
299
|
+
raise ValueError("Model must be either 'exa' or 'exa-pro'")
|
|
300
|
+
try:
|
|
301
|
+
if self.show_results:
|
|
302
|
+
log_info(f"Generating answer for query: {query}")
|
|
303
|
+
answer_kwargs: Dict[str, Any] = {
|
|
304
|
+
"model": self.model,
|
|
305
|
+
"text": text,
|
|
306
|
+
}
|
|
307
|
+
answer_kwargs = {k: v for k, v in answer_kwargs.items() if v is not None}
|
|
308
|
+
|
|
309
|
+
# Execute answer with timeout
|
|
310
|
+
answer = self._execute_with_timeout(self.exa.answer, query=query, **answer_kwargs)
|
|
311
|
+
|
|
312
|
+
result = {
|
|
313
|
+
"answer": answer.answer, # type: ignore
|
|
314
|
+
"citations": [
|
|
315
|
+
{
|
|
316
|
+
"id": citation.id,
|
|
317
|
+
"url": citation.url,
|
|
318
|
+
"title": citation.title,
|
|
319
|
+
"published_date": citation.published_date,
|
|
320
|
+
"author": citation.author,
|
|
321
|
+
"text": citation.text if text else None,
|
|
322
|
+
}
|
|
323
|
+
for citation in answer.citations # type: ignore
|
|
324
|
+
],
|
|
325
|
+
}
|
|
326
|
+
if self.show_results:
|
|
327
|
+
log_info(json.dumps(result))
|
|
328
|
+
|
|
329
|
+
return json.dumps(result, indent=4)
|
|
330
|
+
|
|
331
|
+
except TimeoutError as e:
|
|
332
|
+
logger.error(f"Answer generation timed out after {self.timeout} seconds")
|
|
333
|
+
return f"Error: {str(e)}"
|
|
334
|
+
except Exception as e:
|
|
335
|
+
logger.error(f"Failed to get answer from Exa: {e}")
|
|
336
|
+
return f"Error: {e}"
|
|
337
|
+
|
|
338
|
+
def research(
|
|
339
|
+
self,
|
|
340
|
+
instructions: str,
|
|
341
|
+
output_schema: Optional[Dict[str, Any]] = None,
|
|
342
|
+
) -> str:
|
|
343
|
+
"""
|
|
344
|
+
Perform deep research on a topic.
|
|
345
|
+
|
|
346
|
+
Args:
|
|
347
|
+
instructions (str): Research instructions.
|
|
348
|
+
output_schema (Optional[Dict[str, Any]]): JSON schema for structured output. If not provided, the API will auto-infer an appropriate schema.
|
|
349
|
+
Returns:
|
|
350
|
+
str: JSON formatted research results including data and citations.
|
|
351
|
+
"""
|
|
352
|
+
try:
|
|
353
|
+
log_debug(f"Creating research task with instructions: {instructions}")
|
|
354
|
+
log_debug(f"Output schema: {output_schema}")
|
|
355
|
+
|
|
356
|
+
task_kwargs: Dict[str, Any] = {
|
|
357
|
+
"instructions": instructions,
|
|
358
|
+
"model": self.research_model,
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if output_schema is not None:
|
|
362
|
+
task_kwargs["output_schema"] = output_schema
|
|
363
|
+
else:
|
|
364
|
+
task_kwargs["output_infer_schema"] = True
|
|
365
|
+
|
|
366
|
+
task_result = self._execute_with_timeout(self.exa.research.create_task, **task_kwargs) # type: ignore
|
|
367
|
+
task_id = task_result.id
|
|
368
|
+
|
|
369
|
+
if self.show_results:
|
|
370
|
+
log_info(f"Research task created with ID: {task_id}")
|
|
371
|
+
|
|
372
|
+
# Step 2: Poll until complete (using default polling settings)
|
|
373
|
+
task = self.exa.research.poll_task(task_id) # type: ignore
|
|
374
|
+
|
|
375
|
+
# Step 3: Format and return results
|
|
376
|
+
result: Dict[str, Any] = {"data": task.data, "citations": {}}
|
|
377
|
+
|
|
378
|
+
# Process citations by field
|
|
379
|
+
for field, sources in task.citations.items():
|
|
380
|
+
result["citations"][field] = [
|
|
381
|
+
{"url": source.url, "title": source.title, "id": source.id} for source in sources
|
|
382
|
+
]
|
|
383
|
+
|
|
384
|
+
if self.show_results:
|
|
385
|
+
log_info("Research completed successfully")
|
|
386
|
+
|
|
387
|
+
return json.dumps(result, indent=4)
|
|
388
|
+
|
|
389
|
+
except TimeoutError:
|
|
390
|
+
error_msg = "Research task timed out"
|
|
391
|
+
logger.error(error_msg)
|
|
392
|
+
return json.dumps({"error": error_msg}, indent=4)
|
|
393
|
+
except Exception as e:
|
|
394
|
+
error_msg = f"Research failed: {str(e)}"
|
|
395
|
+
logger.error(error_msg)
|
|
396
|
+
return json.dumps({"error": error_msg}, indent=4)
|
agno/tools/fal.py
CHANGED
|
@@ -3,13 +3,15 @@ pip install fal-client
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
from os import getenv
|
|
6
|
-
from typing import Optional
|
|
6
|
+
from typing import Optional, Union
|
|
7
7
|
from uuid import uuid4
|
|
8
8
|
|
|
9
9
|
from agno.agent import Agent
|
|
10
|
-
from agno.media import
|
|
10
|
+
from agno.media import Image, Video
|
|
11
|
+
from agno.team.team import Team
|
|
11
12
|
from agno.tools import Toolkit
|
|
12
|
-
from agno.
|
|
13
|
+
from agno.tools.function import ToolResult
|
|
14
|
+
from agno.utils.log import log_info, logger
|
|
13
15
|
|
|
14
16
|
try:
|
|
15
17
|
import fal_client # type: ignore
|
|
@@ -22,32 +24,41 @@ class FalTools(Toolkit):
|
|
|
22
24
|
self,
|
|
23
25
|
api_key: Optional[str] = None,
|
|
24
26
|
model: str = "fal-ai/hunyuan-video",
|
|
27
|
+
enable_generate_media: bool = True,
|
|
28
|
+
enable_image_to_image: bool = False,
|
|
29
|
+
all: bool = False,
|
|
30
|
+
**kwargs,
|
|
25
31
|
):
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
self.api_key = api_key or getenv("FAL_KEY")
|
|
32
|
+
self.api_key = api_key or getenv("FAL_API_KEY")
|
|
29
33
|
if not self.api_key:
|
|
30
|
-
logger.error("
|
|
34
|
+
logger.error("FAL_API_KEY not set. Please set the FAL_API_KEY environment variable.")
|
|
31
35
|
self.model = model
|
|
32
36
|
self.seen_logs: set[str] = set()
|
|
33
|
-
|
|
37
|
+
|
|
38
|
+
tools = []
|
|
39
|
+
if all or enable_generate_media:
|
|
40
|
+
tools.append(self.generate_media)
|
|
41
|
+
if all or enable_image_to_image:
|
|
42
|
+
tools.append(self.image_to_image)
|
|
43
|
+
|
|
44
|
+
super().__init__(name="fal-tools", tools=tools, **kwargs)
|
|
34
45
|
|
|
35
46
|
def on_queue_update(self, update):
|
|
36
47
|
if isinstance(update, fal_client.InProgress) and update.logs:
|
|
37
48
|
for log in update.logs:
|
|
38
49
|
message = log["message"]
|
|
39
50
|
if message not in self.seen_logs:
|
|
40
|
-
|
|
51
|
+
log_info(message)
|
|
41
52
|
self.seen_logs.add(message)
|
|
42
53
|
|
|
43
|
-
def generate_media(self, agent: Agent, prompt: str) ->
|
|
54
|
+
def generate_media(self, agent: Union[Agent, Team], prompt: str) -> ToolResult:
|
|
44
55
|
"""
|
|
45
56
|
Use this function to run a model with a given prompt.
|
|
46
57
|
|
|
47
58
|
Args:
|
|
48
59
|
prompt (str): A text description of the task.
|
|
49
60
|
Returns:
|
|
50
|
-
|
|
61
|
+
ToolResult: Contains the generated media and success message.
|
|
51
62
|
"""
|
|
52
63
|
try:
|
|
53
64
|
result = fal_client.subscribe(
|
|
@@ -61,32 +72,27 @@ class FalTools(Toolkit):
|
|
|
61
72
|
|
|
62
73
|
if "image" in result:
|
|
63
74
|
url = result.get("image", {}).get("url", "")
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
url=url,
|
|
68
|
-
)
|
|
75
|
+
image_artifact = Image(
|
|
76
|
+
id=media_id,
|
|
77
|
+
url=url,
|
|
69
78
|
)
|
|
70
|
-
|
|
79
|
+
return ToolResult(content=f"Image generated successfully at {url}", images=[image_artifact])
|
|
71
80
|
elif "video" in result:
|
|
72
81
|
url = result.get("video", {}).get("url", "")
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
url=url,
|
|
77
|
-
)
|
|
82
|
+
video_artifact = Video(
|
|
83
|
+
id=media_id,
|
|
84
|
+
url=url,
|
|
78
85
|
)
|
|
79
|
-
|
|
86
|
+
return ToolResult(content=f"Video generated successfully at {url}", videos=[video_artifact])
|
|
80
87
|
else:
|
|
81
88
|
logger.error(f"Unsupported type in result: {result}")
|
|
82
|
-
return f"Unsupported type in result: {result}"
|
|
89
|
+
return ToolResult(content=f"Unsupported type in result: {result}")
|
|
83
90
|
|
|
84
|
-
return f"{media_type.capitalize()} generated successfully at {url}"
|
|
85
91
|
except Exception as e:
|
|
86
92
|
logger.error(f"Failed to run model: {e}")
|
|
87
|
-
return f"Error: {e}"
|
|
93
|
+
return ToolResult(content=f"Error: {e}")
|
|
88
94
|
|
|
89
|
-
def image_to_image(self, agent: Agent, prompt: str, image_url: Optional[str] = None) ->
|
|
95
|
+
def image_to_image(self, agent: Union[Agent, Team], prompt: str, image_url: Optional[str] = None) -> ToolResult:
|
|
90
96
|
"""
|
|
91
97
|
Use this function to transform an input image based on a text prompt using the Fal AI image-to-image model.
|
|
92
98
|
The model takes an existing image and generates a new version modified according to your prompt.
|
|
@@ -97,7 +103,7 @@ class FalTools(Toolkit):
|
|
|
97
103
|
image_url (str): The URL of the image to use for the generation.
|
|
98
104
|
|
|
99
105
|
Returns:
|
|
100
|
-
|
|
106
|
+
ToolResult: Contains the generated image and success message.
|
|
101
107
|
"""
|
|
102
108
|
|
|
103
109
|
try:
|
|
@@ -109,15 +115,13 @@ class FalTools(Toolkit):
|
|
|
109
115
|
)
|
|
110
116
|
url = result.get("images", [{}])[0].get("url", "")
|
|
111
117
|
media_id = str(uuid4())
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
url=url,
|
|
116
|
-
)
|
|
118
|
+
image_artifact = Image(
|
|
119
|
+
id=media_id,
|
|
120
|
+
url=url,
|
|
117
121
|
)
|
|
118
122
|
|
|
119
|
-
return f"Image generated successfully at {url}"
|
|
123
|
+
return ToolResult(content=f"Image generated successfully at {url}", images=[image_artifact])
|
|
120
124
|
|
|
121
125
|
except Exception as e:
|
|
122
126
|
logger.error(f"Failed to generate image: {e}")
|
|
123
|
-
return f"Error: {e}"
|
|
127
|
+
return ToolResult(content=f"Error: {e}")
|