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/eval/reliability.py
CHANGED
|
@@ -1,14 +1,18 @@
|
|
|
1
|
-
from dataclasses import asdict, dataclass
|
|
1
|
+
from dataclasses import asdict, dataclass, field
|
|
2
2
|
from os import getenv
|
|
3
|
-
from
|
|
4
|
-
from typing import TYPE_CHECKING, List, Optional
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
|
5
4
|
from uuid import uuid4
|
|
6
5
|
|
|
6
|
+
from agno.db.base import AsyncBaseDb, BaseDb
|
|
7
|
+
from agno.run.team import TeamRunOutput
|
|
8
|
+
|
|
7
9
|
if TYPE_CHECKING:
|
|
8
10
|
from rich.console import Console
|
|
9
11
|
|
|
10
|
-
from agno.
|
|
11
|
-
from agno.
|
|
12
|
+
from agno.agent import RunOutput
|
|
13
|
+
from agno.db.schemas.evals import EvalType
|
|
14
|
+
from agno.eval.utils import async_log_eval, log_eval_run, store_result_in_file
|
|
15
|
+
from agno.utils.log import logger
|
|
12
16
|
|
|
13
17
|
|
|
14
18
|
@dataclass
|
|
@@ -40,52 +44,50 @@ class ReliabilityEval:
|
|
|
40
44
|
|
|
41
45
|
# Evaluation name
|
|
42
46
|
name: Optional[str] = None
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
eval_id: Optional[str] = None
|
|
47
|
+
# Evaluation UUID
|
|
48
|
+
eval_id: str = field(default_factory=lambda: str(uuid4()))
|
|
46
49
|
|
|
47
50
|
# Agent response
|
|
48
|
-
agent_response: Optional[
|
|
49
|
-
|
|
51
|
+
agent_response: Optional[RunOutput] = None
|
|
52
|
+
# Team response
|
|
53
|
+
team_response: Optional[TeamRunOutput] = None
|
|
50
54
|
# Expected tool calls
|
|
51
55
|
expected_tool_calls: Optional[List[str]] = None
|
|
52
|
-
|
|
53
56
|
# Result of the evaluation
|
|
54
57
|
result: Optional[ReliabilityResult] = None
|
|
55
58
|
|
|
56
|
-
# Print summary of results
|
|
57
|
-
print_summary: bool = False
|
|
58
59
|
# Print detailed results
|
|
59
60
|
print_results: bool = False
|
|
60
|
-
#
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def
|
|
73
|
-
if self.
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
61
|
+
# If set, results will be saved in the given file path
|
|
62
|
+
file_path_to_save_results: Optional[str] = None
|
|
63
|
+
# Enable debug logs
|
|
64
|
+
debug_mode: bool = getenv("AGNO_DEBUG", "false").lower() == "true"
|
|
65
|
+
# The database to store Evaluation results
|
|
66
|
+
db: Optional[Union[BaseDb, AsyncBaseDb]] = None
|
|
67
|
+
|
|
68
|
+
# Telemetry settings
|
|
69
|
+
# telemetry=True logs minimal telemetry for analytics
|
|
70
|
+
# This helps us improve our Evals and provide better support
|
|
71
|
+
telemetry: bool = True
|
|
72
|
+
|
|
73
|
+
def run(self, *, print_results: bool = False) -> Optional[ReliabilityResult]:
|
|
74
|
+
if isinstance(self.db, AsyncBaseDb):
|
|
75
|
+
raise ValueError("run() is not supported with an async DB. Please use arun() instead.")
|
|
76
|
+
|
|
77
|
+
if self.agent_response is None and self.team_response is None:
|
|
78
|
+
raise ValueError("You need to provide 'agent_response' or 'team_response' to run the evaluation.")
|
|
79
|
+
|
|
80
|
+
if self.agent_response is not None and self.team_response is not None:
|
|
81
|
+
raise ValueError(
|
|
82
|
+
"You need to provide only one of 'agent_response' or 'team_response' to run the evaluation."
|
|
83
|
+
)
|
|
84
|
+
|
|
81
85
|
from rich.console import Console
|
|
82
86
|
from rich.live import Live
|
|
83
87
|
from rich.status import Status
|
|
84
88
|
|
|
85
|
-
self.
|
|
86
|
-
|
|
87
|
-
self.print_results = print_results
|
|
88
|
-
self.print_summary = print_summary
|
|
89
|
+
# Generate unique run_id for this execution (don't modify self.eval_id due to concurrency)
|
|
90
|
+
run_id = str(uuid4())
|
|
89
91
|
|
|
90
92
|
# Add a spinner while running the evaluations
|
|
91
93
|
console = Console()
|
|
@@ -95,20 +97,34 @@ class ReliabilityEval:
|
|
|
95
97
|
|
|
96
98
|
actual_tool_calls = None
|
|
97
99
|
if self.agent_response is not None:
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
messages = self.agent_response.messages
|
|
101
|
+
elif self.team_response is not None:
|
|
102
|
+
messages = self.team_response.messages or []
|
|
103
|
+
for member_response in self.team_response.member_responses:
|
|
104
|
+
if member_response.messages is not None:
|
|
105
|
+
messages += member_response.messages
|
|
106
|
+
|
|
107
|
+
for message in reversed(messages): # type: ignore
|
|
108
|
+
if message.tool_calls:
|
|
109
|
+
if actual_tool_calls is None:
|
|
110
|
+
actual_tool_calls = message.tool_calls
|
|
111
|
+
else:
|
|
112
|
+
actual_tool_calls.append(message.tool_calls[0]) # type: ignore
|
|
104
113
|
|
|
105
114
|
failed_tool_calls = []
|
|
106
115
|
passed_tool_calls = []
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
116
|
+
if not actual_tool_calls:
|
|
117
|
+
failed_tool_calls = self.expected_tool_calls or []
|
|
118
|
+
else:
|
|
119
|
+
for tool_call in actual_tool_calls: # type: ignore
|
|
120
|
+
tool_name = tool_call.get("function", {}).get("name")
|
|
121
|
+
if not tool_name:
|
|
122
|
+
continue
|
|
123
|
+
else:
|
|
124
|
+
if self.expected_tool_calls is not None and tool_name not in self.expected_tool_calls:
|
|
125
|
+
failed_tool_calls.append(tool_call.get("function", {}).get("name"))
|
|
126
|
+
else:
|
|
127
|
+
passed_tool_calls.append(tool_call.get("function", {}).get("name"))
|
|
112
128
|
|
|
113
129
|
self.result = ReliabilityResult(
|
|
114
130
|
eval_status="PASSED" if len(failed_tool_calls) == 0 else "FAILED",
|
|
@@ -116,21 +132,184 @@ class ReliabilityEval:
|
|
|
116
132
|
passed_tool_calls=passed_tool_calls,
|
|
117
133
|
)
|
|
118
134
|
|
|
119
|
-
#
|
|
120
|
-
if self.
|
|
121
|
-
|
|
122
|
-
|
|
135
|
+
# Save result to file if requested
|
|
136
|
+
if self.file_path_to_save_results is not None and self.result is not None:
|
|
137
|
+
store_result_in_file(
|
|
138
|
+
file_path=self.file_path_to_save_results,
|
|
139
|
+
name=self.name,
|
|
140
|
+
eval_id=self.eval_id,
|
|
141
|
+
result=self.result,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Print results if requested
|
|
145
|
+
if self.print_results or print_results:
|
|
146
|
+
self.result.print_eval(console)
|
|
147
|
+
|
|
148
|
+
# Log results to the Agno platform if requested
|
|
149
|
+
if self.db:
|
|
150
|
+
if self.agent_response is not None:
|
|
151
|
+
agent_id = self.agent_response.agent_id
|
|
152
|
+
team_id = None
|
|
153
|
+
model_id = self.agent_response.model
|
|
154
|
+
model_provider = self.agent_response.model_provider
|
|
155
|
+
elif self.team_response is not None:
|
|
156
|
+
agent_id = None
|
|
157
|
+
team_id = self.team_response.team_id
|
|
158
|
+
model_id = self.team_response.model
|
|
159
|
+
model_provider = self.team_response.model_provider
|
|
160
|
+
|
|
161
|
+
eval_input = {
|
|
162
|
+
"expected_tool_calls": self.expected_tool_calls,
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
log_eval_run(
|
|
166
|
+
db=self.db,
|
|
167
|
+
run_id=self.eval_id, # type: ignore
|
|
168
|
+
run_data=asdict(self.result),
|
|
169
|
+
eval_type=EvalType.RELIABILITY,
|
|
170
|
+
name=self.name if self.name is not None else None,
|
|
171
|
+
agent_id=agent_id,
|
|
172
|
+
team_id=team_id,
|
|
173
|
+
model_id=model_id,
|
|
174
|
+
model_provider=model_provider,
|
|
175
|
+
eval_input=eval_input,
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
if self.telemetry:
|
|
179
|
+
from agno.api.evals import EvalRunCreate, create_eval_run_telemetry
|
|
180
|
+
|
|
181
|
+
create_eval_run_telemetry(
|
|
182
|
+
eval_run=EvalRunCreate(
|
|
183
|
+
run_id=self.eval_id,
|
|
184
|
+
eval_type=EvalType.RELIABILITY,
|
|
185
|
+
data=self._get_telemetry_data(),
|
|
186
|
+
),
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
logger.debug(f"*********** Evaluation End: {run_id} ***********")
|
|
190
|
+
return self.result
|
|
191
|
+
|
|
192
|
+
async def arun(self, *, print_results: bool = False) -> Optional[ReliabilityResult]:
|
|
193
|
+
if self.agent_response is None and self.team_response is None:
|
|
194
|
+
raise ValueError("You need to provide 'agent_response' or 'team_response' to run the evaluation.")
|
|
195
|
+
|
|
196
|
+
if self.agent_response is not None and self.team_response is not None:
|
|
197
|
+
raise ValueError(
|
|
198
|
+
"You need to provide only one of 'agent_response' or 'team_response' to run the evaluation."
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
from rich.console import Console
|
|
202
|
+
from rich.live import Live
|
|
203
|
+
from rich.status import Status
|
|
204
|
+
|
|
205
|
+
# Generate unique run_id for this execution (don't modify self.eval_id due to concurrency)
|
|
206
|
+
run_id = str(uuid4())
|
|
207
|
+
|
|
208
|
+
# Add a spinner while running the evaluations
|
|
209
|
+
console = Console()
|
|
210
|
+
with Live(console=console, transient=True) as live_log:
|
|
211
|
+
status = Status("Running evaluation...", spinner="dots", speed=1.0, refresh_per_second=10)
|
|
212
|
+
live_log.update(status)
|
|
213
|
+
|
|
214
|
+
actual_tool_calls = None
|
|
215
|
+
if self.agent_response is not None:
|
|
216
|
+
messages = self.agent_response.messages
|
|
217
|
+
elif self.team_response is not None:
|
|
218
|
+
messages = self.team_response.messages or []
|
|
219
|
+
for member_response in self.team_response.member_responses:
|
|
220
|
+
if member_response.messages is not None:
|
|
221
|
+
messages += member_response.messages
|
|
222
|
+
|
|
223
|
+
for message in reversed(messages): # type: ignore
|
|
224
|
+
if message.tool_calls:
|
|
225
|
+
if actual_tool_calls is None:
|
|
226
|
+
actual_tool_calls = message.tool_calls
|
|
227
|
+
else:
|
|
228
|
+
actual_tool_calls.append(message.tool_calls[0]) # type: ignore
|
|
229
|
+
|
|
230
|
+
failed_tool_calls = []
|
|
231
|
+
passed_tool_calls = []
|
|
232
|
+
if not actual_tool_calls:
|
|
233
|
+
failed_tool_calls = self.expected_tool_calls or []
|
|
234
|
+
else:
|
|
235
|
+
for tool_call in actual_tool_calls: # type: ignore
|
|
236
|
+
tool_name = tool_call.get("function", {}).get("name")
|
|
237
|
+
if not tool_name:
|
|
238
|
+
continue
|
|
239
|
+
else:
|
|
240
|
+
if self.expected_tool_calls is not None and tool_name not in self.expected_tool_calls:
|
|
241
|
+
failed_tool_calls.append(tool_call.get("function", {}).get("name"))
|
|
242
|
+
else:
|
|
243
|
+
passed_tool_calls.append(tool_call.get("function", {}).get("name"))
|
|
244
|
+
|
|
245
|
+
self.result = ReliabilityResult(
|
|
246
|
+
eval_status="PASSED" if len(failed_tool_calls) == 0 else "FAILED",
|
|
247
|
+
failed_tool_calls=failed_tool_calls,
|
|
248
|
+
passed_tool_calls=passed_tool_calls,
|
|
249
|
+
)
|
|
123
250
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
251
|
+
# Save result to file if requested
|
|
252
|
+
if self.file_path_to_save_results is not None and self.result is not None:
|
|
253
|
+
store_result_in_file(
|
|
254
|
+
file_path=self.file_path_to_save_results,
|
|
255
|
+
name=self.name,
|
|
256
|
+
eval_id=run_id,
|
|
257
|
+
result=self.result,
|
|
258
|
+
)
|
|
130
259
|
|
|
131
|
-
#
|
|
132
|
-
if self.
|
|
260
|
+
# Print results if requested
|
|
261
|
+
if self.print_results or print_results:
|
|
133
262
|
self.result.print_eval(console)
|
|
134
263
|
|
|
135
|
-
|
|
264
|
+
# Log results to the Agno platform if requested
|
|
265
|
+
if self.db:
|
|
266
|
+
if self.agent_response is not None:
|
|
267
|
+
agent_id = self.agent_response.agent_id
|
|
268
|
+
team_id = None
|
|
269
|
+
model_id = self.agent_response.model
|
|
270
|
+
model_provider = self.agent_response.model_provider
|
|
271
|
+
elif self.team_response is not None:
|
|
272
|
+
agent_id = None
|
|
273
|
+
team_id = self.team_response.team_id
|
|
274
|
+
model_id = self.team_response.model
|
|
275
|
+
model_provider = self.team_response.model_provider
|
|
276
|
+
|
|
277
|
+
eval_input = {
|
|
278
|
+
"expected_tool_calls": self.expected_tool_calls,
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
await async_log_eval(
|
|
282
|
+
db=self.db,
|
|
283
|
+
run_id=self.eval_id, # type: ignore
|
|
284
|
+
run_data=asdict(self.result),
|
|
285
|
+
eval_type=EvalType.RELIABILITY,
|
|
286
|
+
name=self.name if self.name is not None else None,
|
|
287
|
+
agent_id=agent_id,
|
|
288
|
+
team_id=team_id,
|
|
289
|
+
model_id=model_id,
|
|
290
|
+
model_provider=model_provider,
|
|
291
|
+
eval_input=eval_input,
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
if self.telemetry:
|
|
295
|
+
from agno.api.evals import EvalRunCreate, async_create_eval_run_telemetry
|
|
296
|
+
|
|
297
|
+
await async_create_eval_run_telemetry(
|
|
298
|
+
eval_run=EvalRunCreate(
|
|
299
|
+
run_id=self.eval_id,
|
|
300
|
+
eval_type=EvalType.RELIABILITY,
|
|
301
|
+
data=self._get_telemetry_data(),
|
|
302
|
+
),
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
logger.debug(f"*********** Evaluation End: {run_id} ***********")
|
|
136
306
|
return self.result
|
|
307
|
+
|
|
308
|
+
def _get_telemetry_data(self) -> Dict[str, Any]:
|
|
309
|
+
"""Get the telemetry data for the evaluation"""
|
|
310
|
+
return {
|
|
311
|
+
"team_id": self.team_response.team_id if self.team_response else None,
|
|
312
|
+
"agent_id": self.agent_response.agent_id if self.agent_response else None,
|
|
313
|
+
"model_id": self.agent_response.model if self.agent_response else None,
|
|
314
|
+
"model_provider": self.agent_response.model_provider if self.agent_response else None,
|
|
315
|
+
}
|
agno/eval/utils.py
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from dataclasses import asdict
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import TYPE_CHECKING, Optional, Union
|
|
4
|
+
|
|
5
|
+
from agno.db.base import AsyncBaseDb, BaseDb
|
|
6
|
+
from agno.db.schemas.evals import EvalRunRecord, EvalType
|
|
7
|
+
from agno.utils.log import log_debug, logger
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from agno.eval.accuracy import AccuracyResult
|
|
11
|
+
from agno.eval.agent_as_judge import AgentAsJudgeResult
|
|
12
|
+
from agno.eval.performance import PerformanceResult
|
|
13
|
+
from agno.eval.reliability import ReliabilityResult
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def log_eval_run(
|
|
17
|
+
db: BaseDb,
|
|
18
|
+
run_id: str,
|
|
19
|
+
run_data: dict,
|
|
20
|
+
eval_type: EvalType,
|
|
21
|
+
eval_input: dict,
|
|
22
|
+
agent_id: Optional[str] = None,
|
|
23
|
+
model_id: Optional[str] = None,
|
|
24
|
+
model_provider: Optional[str] = None,
|
|
25
|
+
name: Optional[str] = None,
|
|
26
|
+
evaluated_component_name: Optional[str] = None,
|
|
27
|
+
team_id: Optional[str] = None,
|
|
28
|
+
workflow_id: Optional[str] = None,
|
|
29
|
+
) -> None:
|
|
30
|
+
"""Call the API to create an evaluation run."""
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
db.create_eval_run(
|
|
34
|
+
EvalRunRecord(
|
|
35
|
+
run_id=run_id,
|
|
36
|
+
eval_type=eval_type,
|
|
37
|
+
eval_data=run_data,
|
|
38
|
+
eval_input=eval_input,
|
|
39
|
+
agent_id=agent_id,
|
|
40
|
+
model_id=model_id,
|
|
41
|
+
model_provider=model_provider,
|
|
42
|
+
name=name,
|
|
43
|
+
evaluated_component_name=evaluated_component_name,
|
|
44
|
+
team_id=team_id,
|
|
45
|
+
workflow_id=workflow_id,
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
except Exception as e:
|
|
49
|
+
log_debug(f"Could not create agent event: {e}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async def async_log_eval(
|
|
53
|
+
db: Union[BaseDb, AsyncBaseDb],
|
|
54
|
+
run_id: str,
|
|
55
|
+
run_data: dict,
|
|
56
|
+
eval_type: EvalType,
|
|
57
|
+
eval_input: dict,
|
|
58
|
+
agent_id: Optional[str] = None,
|
|
59
|
+
model_id: Optional[str] = None,
|
|
60
|
+
model_provider: Optional[str] = None,
|
|
61
|
+
name: Optional[str] = None,
|
|
62
|
+
evaluated_component_name: Optional[str] = None,
|
|
63
|
+
team_id: Optional[str] = None,
|
|
64
|
+
workflow_id: Optional[str] = None,
|
|
65
|
+
) -> None:
|
|
66
|
+
"""Call the API to create an evaluation run."""
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
if isinstance(db, AsyncBaseDb):
|
|
70
|
+
await db.create_eval_run(
|
|
71
|
+
EvalRunRecord(
|
|
72
|
+
run_id=run_id,
|
|
73
|
+
eval_type=eval_type,
|
|
74
|
+
eval_data=run_data,
|
|
75
|
+
eval_input=eval_input,
|
|
76
|
+
agent_id=agent_id,
|
|
77
|
+
model_id=model_id,
|
|
78
|
+
model_provider=model_provider,
|
|
79
|
+
name=name,
|
|
80
|
+
evaluated_component_name=evaluated_component_name,
|
|
81
|
+
team_id=team_id,
|
|
82
|
+
workflow_id=workflow_id,
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
else:
|
|
86
|
+
db.create_eval_run(
|
|
87
|
+
EvalRunRecord(
|
|
88
|
+
run_id=run_id,
|
|
89
|
+
eval_type=eval_type,
|
|
90
|
+
eval_data=run_data,
|
|
91
|
+
eval_input=eval_input,
|
|
92
|
+
agent_id=agent_id,
|
|
93
|
+
model_id=model_id,
|
|
94
|
+
model_provider=model_provider,
|
|
95
|
+
name=name,
|
|
96
|
+
evaluated_component_name=evaluated_component_name,
|
|
97
|
+
team_id=team_id,
|
|
98
|
+
workflow_id=workflow_id,
|
|
99
|
+
)
|
|
100
|
+
)
|
|
101
|
+
except Exception as e:
|
|
102
|
+
log_debug(f"Could not create agent event: {e}")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def store_result_in_file(
|
|
106
|
+
file_path: str,
|
|
107
|
+
result: Union["AccuracyResult", "AgentAsJudgeResult", "PerformanceResult", "ReliabilityResult"],
|
|
108
|
+
eval_id: Optional[str] = None,
|
|
109
|
+
name: Optional[str] = None,
|
|
110
|
+
):
|
|
111
|
+
"""Store the given result in the given file path"""
|
|
112
|
+
try:
|
|
113
|
+
import json
|
|
114
|
+
|
|
115
|
+
fn_path = Path(file_path.format(name=name, eval_id=eval_id))
|
|
116
|
+
if not fn_path.parent.exists():
|
|
117
|
+
fn_path.parent.mkdir(parents=True, exist_ok=True)
|
|
118
|
+
fn_path.write_text(json.dumps(asdict(result), indent=4))
|
|
119
|
+
except Exception as e:
|
|
120
|
+
logger.warning(f"Failed to save result to file: {e}")
|
agno/exceptions.py
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
from
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Any, Dict, List, Optional, Union
|
|
2
4
|
|
|
3
5
|
from agno.models.message import Message
|
|
4
6
|
|
|
@@ -17,11 +19,25 @@ class AgentRunException(Exception):
|
|
|
17
19
|
self.agent_message = agent_message
|
|
18
20
|
self.messages = messages
|
|
19
21
|
self.stop_execution = stop_execution
|
|
22
|
+
self.type = "agent_run_error"
|
|
23
|
+
self.error_id = "agent_run_error"
|
|
20
24
|
|
|
21
25
|
|
|
22
26
|
class RetryAgentRun(AgentRunException):
|
|
23
27
|
"""Exception raised when a tool call should be retried."""
|
|
24
28
|
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
exc,
|
|
32
|
+
user_message: Optional[Union[str, Message]] = None,
|
|
33
|
+
agent_message: Optional[Union[str, Message]] = None,
|
|
34
|
+
messages: Optional[List[Union[dict, Message]]] = None,
|
|
35
|
+
):
|
|
36
|
+
super().__init__(
|
|
37
|
+
exc, user_message=user_message, agent_message=agent_message, messages=messages, stop_execution=False
|
|
38
|
+
)
|
|
39
|
+
self.error_id = "retry_agent_run_error"
|
|
40
|
+
|
|
25
41
|
|
|
26
42
|
class StopAgentRun(AgentRunException):
|
|
27
43
|
"""Exception raised when an agent should stop executing entirely."""
|
|
@@ -36,3 +52,129 @@ class StopAgentRun(AgentRunException):
|
|
|
36
52
|
super().__init__(
|
|
37
53
|
exc, user_message=user_message, agent_message=agent_message, messages=messages, stop_execution=True
|
|
38
54
|
)
|
|
55
|
+
self.error_id = "stop_agent_run_error"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
class RunCancelledException(Exception):
|
|
59
|
+
"""Exception raised when a run is cancelled."""
|
|
60
|
+
|
|
61
|
+
def __init__(self, message: str = "Operation cancelled by user"):
|
|
62
|
+
super().__init__(message)
|
|
63
|
+
self.type = "run_cancelled_error"
|
|
64
|
+
self.error_id = "run_cancelled_error"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class AgnoError(Exception):
|
|
68
|
+
"""Exception raised when an internal error occurs."""
|
|
69
|
+
|
|
70
|
+
def __init__(self, message: str, status_code: int = 500):
|
|
71
|
+
super().__init__(message)
|
|
72
|
+
self.message = message
|
|
73
|
+
self.status_code = status_code
|
|
74
|
+
self.type = "agno_error"
|
|
75
|
+
self.error_id = "agno_error"
|
|
76
|
+
|
|
77
|
+
def __str__(self) -> str:
|
|
78
|
+
return str(self.message)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ModelAuthenticationError(AgnoError):
|
|
82
|
+
"""Raised when model authentication fails."""
|
|
83
|
+
|
|
84
|
+
def __init__(self, message: str, status_code: int = 401, model_name: Optional[str] = None):
|
|
85
|
+
super().__init__(message, status_code)
|
|
86
|
+
self.model_name = model_name
|
|
87
|
+
|
|
88
|
+
self.type = "model_authentication_error"
|
|
89
|
+
self.error_id = "model_authentication_error"
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class ModelProviderError(AgnoError):
|
|
93
|
+
"""Exception raised when a model provider returns an error."""
|
|
94
|
+
|
|
95
|
+
def __init__(
|
|
96
|
+
self, message: str, status_code: int = 502, model_name: Optional[str] = None, model_id: Optional[str] = None
|
|
97
|
+
):
|
|
98
|
+
super().__init__(message, status_code)
|
|
99
|
+
self.model_name = model_name
|
|
100
|
+
self.model_id = model_id
|
|
101
|
+
|
|
102
|
+
self.type = "model_provider_error"
|
|
103
|
+
self.error_id = "model_provider_error"
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class ModelRateLimitError(ModelProviderError):
|
|
107
|
+
"""Exception raised when a model provider returns a rate limit error."""
|
|
108
|
+
|
|
109
|
+
def __init__(
|
|
110
|
+
self, message: str, status_code: int = 429, model_name: Optional[str] = None, model_id: Optional[str] = None
|
|
111
|
+
):
|
|
112
|
+
super().__init__(message, status_code, model_name, model_id)
|
|
113
|
+
self.error_id = "model_rate_limit_error"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class EvalError(Exception):
|
|
117
|
+
"""Exception raised when an evaluation fails."""
|
|
118
|
+
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class CheckTrigger(Enum):
|
|
123
|
+
"""Enum for guardrail triggers."""
|
|
124
|
+
|
|
125
|
+
OFF_TOPIC = "off_topic"
|
|
126
|
+
INPUT_NOT_ALLOWED = "input_not_allowed"
|
|
127
|
+
OUTPUT_NOT_ALLOWED = "output_not_allowed"
|
|
128
|
+
VALIDATION_FAILED = "validation_failed"
|
|
129
|
+
|
|
130
|
+
PROMPT_INJECTION = "prompt_injection"
|
|
131
|
+
PII_DETECTED = "pii_detected"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class InputCheckError(Exception):
|
|
135
|
+
"""Exception raised when an input check fails."""
|
|
136
|
+
|
|
137
|
+
def __init__(
|
|
138
|
+
self,
|
|
139
|
+
message: str,
|
|
140
|
+
check_trigger: CheckTrigger = CheckTrigger.INPUT_NOT_ALLOWED,
|
|
141
|
+
additional_data: Optional[Dict[str, Any]] = None,
|
|
142
|
+
):
|
|
143
|
+
super().__init__(message)
|
|
144
|
+
self.type = "input_check_error"
|
|
145
|
+
if isinstance(check_trigger, CheckTrigger):
|
|
146
|
+
self.error_id = check_trigger.value
|
|
147
|
+
else:
|
|
148
|
+
self.error_id = str(check_trigger)
|
|
149
|
+
|
|
150
|
+
self.message = message
|
|
151
|
+
self.check_trigger = check_trigger
|
|
152
|
+
self.additional_data = additional_data
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class OutputCheckError(Exception):
|
|
156
|
+
"""Exception raised when an output check fails."""
|
|
157
|
+
|
|
158
|
+
def __init__(
|
|
159
|
+
self,
|
|
160
|
+
message: str,
|
|
161
|
+
check_trigger: CheckTrigger = CheckTrigger.OUTPUT_NOT_ALLOWED,
|
|
162
|
+
additional_data: Optional[Dict[str, Any]] = None,
|
|
163
|
+
):
|
|
164
|
+
super().__init__(message)
|
|
165
|
+
self.type = "output_check_error"
|
|
166
|
+
if isinstance(check_trigger, CheckTrigger):
|
|
167
|
+
self.error_id = check_trigger.value
|
|
168
|
+
else:
|
|
169
|
+
self.error_id = str(check_trigger)
|
|
170
|
+
|
|
171
|
+
self.message = message
|
|
172
|
+
self.check_trigger = check_trigger
|
|
173
|
+
self.additional_data = additional_data
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@dataclass
|
|
177
|
+
class RetryableModelProviderError(Exception):
|
|
178
|
+
original_error: Optional[str] = None
|
|
179
|
+
# Guidance message to retry a model invocation after an error
|
|
180
|
+
retry_guidance_message: Optional[str] = None
|