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/db/redis/schemas.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Table schemas and related utils used by the RedisDb class"""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
SESSION_SCHEMA = {
|
|
6
|
+
"session_id": {"type": "string", "primary_key": True},
|
|
7
|
+
"session_type": {"type": "string"},
|
|
8
|
+
"agent_id": {"type": "string"},
|
|
9
|
+
"team_id": {"type": "string"},
|
|
10
|
+
"workflow_id": {"type": "string"},
|
|
11
|
+
"user_id": {"type": "string"},
|
|
12
|
+
"session_data": {"type": "json"},
|
|
13
|
+
"agent_data": {"type": "json"},
|
|
14
|
+
"team_data": {"type": "json"},
|
|
15
|
+
"workflow_data": {"type": "json"},
|
|
16
|
+
"metadata": {"type": "json"},
|
|
17
|
+
"runs": {"type": "json"},
|
|
18
|
+
"summary": {"type": "json"},
|
|
19
|
+
"created_at": {"type": "integer"},
|
|
20
|
+
"updated_at": {"type": "integer"},
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
USER_MEMORY_SCHEMA = {
|
|
24
|
+
"memory_id": {"type": "string", "primary_key": True},
|
|
25
|
+
"memory": {"type": "json"},
|
|
26
|
+
"agent_id": {"type": "string"},
|
|
27
|
+
"team_id": {"type": "string"},
|
|
28
|
+
"user_id": {"type": "string"},
|
|
29
|
+
"topics": {"type": "json"},
|
|
30
|
+
"input": {"type": "string"},
|
|
31
|
+
"feedback": {"type": "string"},
|
|
32
|
+
"created_at": {"type": "integer"},
|
|
33
|
+
"updated_at": {"type": "integer"},
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
METRICS_SCHEMA = {
|
|
37
|
+
"id": {"type": "string", "primary_key": True},
|
|
38
|
+
"agent_runs_count": {"type": "integer", "default": 0},
|
|
39
|
+
"team_runs_count": {"type": "integer", "default": 0},
|
|
40
|
+
"workflow_runs_count": {"type": "integer", "default": 0},
|
|
41
|
+
"agent_sessions_count": {"type": "integer", "default": 0},
|
|
42
|
+
"team_sessions_count": {"type": "integer", "default": 0},
|
|
43
|
+
"workflow_sessions_count": {"type": "integer", "default": 0},
|
|
44
|
+
"users_count": {"type": "integer", "default": 0},
|
|
45
|
+
"token_metrics": {"type": "json", "default": {}},
|
|
46
|
+
"model_metrics": {"type": "json", "default": {}},
|
|
47
|
+
"date": {"type": "date"},
|
|
48
|
+
"aggregation_period": {"type": "string"},
|
|
49
|
+
"created_at": {"type": "integer"},
|
|
50
|
+
"updated_at": {"type": "integer"},
|
|
51
|
+
"completed": {"type": "boolean", "default": False},
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
EVAL_SCHEMA = {
|
|
55
|
+
"run_id": {"type": "string", "primary_key": True},
|
|
56
|
+
"eval_type": {"type": "string"},
|
|
57
|
+
"eval_data": {"type": "json"},
|
|
58
|
+
"eval_input": {"type": "json"},
|
|
59
|
+
"name": {"type": "string"},
|
|
60
|
+
"agent_id": {"type": "string"},
|
|
61
|
+
"team_id": {"type": "string"},
|
|
62
|
+
"workflow_id": {"type": "string"},
|
|
63
|
+
"model_id": {"type": "string"},
|
|
64
|
+
"model_provider": {"type": "string"},
|
|
65
|
+
"evaluated_component_name": {"type": "string"},
|
|
66
|
+
"created_at": {"type": "integer"},
|
|
67
|
+
"updated_at": {"type": "integer"},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
KNOWLEDGE_SCHEMA = {
|
|
71
|
+
"id": {"type": "string", "primary_key": True},
|
|
72
|
+
"name": {"type": "string"},
|
|
73
|
+
"description": {"type": "string"},
|
|
74
|
+
"metadata": {"type": "json"},
|
|
75
|
+
"type": {"type": "string"},
|
|
76
|
+
"size": {"type": "integer"},
|
|
77
|
+
"linked_to": {"type": "string"},
|
|
78
|
+
"access_count": {"type": "integer"},
|
|
79
|
+
"created_at": {"type": "integer"},
|
|
80
|
+
"updated_at": {"type": "integer"},
|
|
81
|
+
"status": {"type": "string"},
|
|
82
|
+
"status_message": {"type": "string"},
|
|
83
|
+
"external_id": {"type": "string"},
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
CULTURAL_KNOWLEDGE_SCHEMA = {
|
|
88
|
+
"id": {"type": "string", "primary_key": True},
|
|
89
|
+
"name": {"type": "string"},
|
|
90
|
+
"summary": {"type": "string"},
|
|
91
|
+
"content": {"type": "json"},
|
|
92
|
+
"metadata": {"type": "json"},
|
|
93
|
+
"input": {"type": "string"},
|
|
94
|
+
"created_at": {"type": "integer"},
|
|
95
|
+
"updated_at": {"type": "integer"},
|
|
96
|
+
"agent_id": {"type": "string"},
|
|
97
|
+
"team_id": {"type": "string"},
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
TRACE_SCHEMA = {
|
|
101
|
+
"trace_id": {"type": "string", "primary_key": True},
|
|
102
|
+
"name": {"type": "string"},
|
|
103
|
+
"status": {"type": "string"},
|
|
104
|
+
"duration_ms": {"type": "integer"},
|
|
105
|
+
"run_id": {"type": "string"},
|
|
106
|
+
"session_id": {"type": "string"},
|
|
107
|
+
"user_id": {"type": "string"},
|
|
108
|
+
"agent_id": {"type": "string"},
|
|
109
|
+
"team_id": {"type": "string"},
|
|
110
|
+
"workflow_id": {"type": "string"},
|
|
111
|
+
"start_time": {"type": "string"},
|
|
112
|
+
"end_time": {"type": "string"},
|
|
113
|
+
"created_at": {"type": "string"},
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
SPAN_SCHEMA = {
|
|
117
|
+
"span_id": {"type": "string", "primary_key": True},
|
|
118
|
+
"trace_id": {"type": "string"},
|
|
119
|
+
"parent_span_id": {"type": "string"},
|
|
120
|
+
"name": {"type": "string"},
|
|
121
|
+
"span_kind": {"type": "string"},
|
|
122
|
+
"status_code": {"type": "string"},
|
|
123
|
+
"status_message": {"type": "string"},
|
|
124
|
+
"start_time": {"type": "string"},
|
|
125
|
+
"end_time": {"type": "string"},
|
|
126
|
+
"attributes": {"type": "json"},
|
|
127
|
+
"created_at": {"type": "string"},
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def get_table_schema_definition(table_type: str) -> dict[str, Any]:
|
|
132
|
+
"""
|
|
133
|
+
Get the expected schema definition for the given table.
|
|
134
|
+
|
|
135
|
+
For Redis, we don't need actual schemas since it's a key-value store,
|
|
136
|
+
but we maintain this for compatibility with the base interface.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
table_type (str): The type of table to get the schema for.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
Dict[str, Any]: Dictionary containing schema information for the table
|
|
143
|
+
"""
|
|
144
|
+
schemas = {
|
|
145
|
+
"sessions": SESSION_SCHEMA,
|
|
146
|
+
"memories": USER_MEMORY_SCHEMA,
|
|
147
|
+
"metrics": METRICS_SCHEMA,
|
|
148
|
+
"evals": EVAL_SCHEMA,
|
|
149
|
+
"knowledge": KNOWLEDGE_SCHEMA,
|
|
150
|
+
"culture": CULTURAL_KNOWLEDGE_SCHEMA,
|
|
151
|
+
"traces": TRACE_SCHEMA,
|
|
152
|
+
"spans": SPAN_SCHEMA,
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
schema = schemas.get(table_type, {})
|
|
156
|
+
if not schema:
|
|
157
|
+
raise ValueError(f"Unknown table type: {table_type}")
|
|
158
|
+
|
|
159
|
+
return schema
|
agno/db/redis/utils.py
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
"""Utility functions for the Redis database class."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
from datetime import date, datetime, timedelta, timezone
|
|
6
|
+
from typing import Any, Dict, List, Optional, Union
|
|
7
|
+
from uuid import UUID
|
|
8
|
+
|
|
9
|
+
from agno.db.schemas.culture import CulturalKnowledge
|
|
10
|
+
from agno.utils.log import log_warning
|
|
11
|
+
|
|
12
|
+
try:
|
|
13
|
+
from redis import Redis, RedisCluster
|
|
14
|
+
except ImportError:
|
|
15
|
+
raise ImportError("`redis` not installed. Please install it using `pip install redis`")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
# -- Serialization and deserialization --
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class CustomEncoder(json.JSONEncoder):
|
|
22
|
+
"""Custom encoder to handle non JSON serializable types."""
|
|
23
|
+
|
|
24
|
+
def default(self, obj):
|
|
25
|
+
if isinstance(obj, UUID):
|
|
26
|
+
return str(obj)
|
|
27
|
+
elif isinstance(obj, (date, datetime)):
|
|
28
|
+
return obj.isoformat()
|
|
29
|
+
|
|
30
|
+
return super().default(obj)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def serialize_data(data: dict) -> str:
|
|
34
|
+
return json.dumps(data, ensure_ascii=False, cls=CustomEncoder)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def deserialize_data(data: str) -> dict:
|
|
38
|
+
return json.loads(data)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
# -- Redis utils --
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def generate_redis_key(prefix: str, table_type: str, key_id: str) -> str:
|
|
45
|
+
"""Generate Redis key with proper namespacing."""
|
|
46
|
+
return f"{prefix}:{table_type}:{key_id}"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def generate_index_key(prefix: str, table_type: str, index_field: str, index_value: str) -> str:
|
|
50
|
+
"""Generate Redis key for index entries."""
|
|
51
|
+
return f"{prefix}:{table_type}:index:{index_field}:{index_value}"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_all_keys_for_table(redis_client: Union[Redis, RedisCluster], prefix: str, table_type: str) -> List[str]:
|
|
55
|
+
"""Get all relevant keys for the given table type.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
redis_client (Redis): The Redis client.
|
|
59
|
+
prefix (str): The prefix for the keys.
|
|
60
|
+
table_type (str): The table type.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
List[str]: A list of all relevant keys for the given table type.
|
|
64
|
+
"""
|
|
65
|
+
pattern = f"{prefix}:{table_type}:*"
|
|
66
|
+
all_keys = redis_client.scan_iter(match=pattern)
|
|
67
|
+
relevant_keys = []
|
|
68
|
+
|
|
69
|
+
for key in all_keys:
|
|
70
|
+
if ":index:" in key: # Skip index keys
|
|
71
|
+
continue
|
|
72
|
+
relevant_keys.append(key)
|
|
73
|
+
|
|
74
|
+
return relevant_keys
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# -- DB util methods --
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def apply_sorting(
|
|
81
|
+
records: List[Dict[str, Any]], sort_by: Optional[str] = None, sort_order: Optional[str] = None
|
|
82
|
+
) -> List[Dict[str, Any]]:
|
|
83
|
+
if sort_by is None:
|
|
84
|
+
return records
|
|
85
|
+
|
|
86
|
+
def get_sort_key(record):
|
|
87
|
+
value = record.get(sort_by, 0)
|
|
88
|
+
if value is None:
|
|
89
|
+
return 0 if isinstance(records[0].get(sort_by, 0), (int, float)) else ""
|
|
90
|
+
return value
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
is_reverse = sort_order == "desc"
|
|
94
|
+
return sorted(records, key=get_sort_key, reverse=is_reverse)
|
|
95
|
+
|
|
96
|
+
except Exception as e:
|
|
97
|
+
log_warning(f"Error sorting Redisrecords: {e}")
|
|
98
|
+
return records
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def apply_pagination(
|
|
102
|
+
records: List[Dict[str, Any]], limit: Optional[int] = None, page: Optional[int] = None
|
|
103
|
+
) -> List[Dict[str, Any]]:
|
|
104
|
+
if limit is None:
|
|
105
|
+
return records
|
|
106
|
+
|
|
107
|
+
if page is not None and page > 0:
|
|
108
|
+
start_idx = (page - 1) * limit
|
|
109
|
+
end_idx = start_idx + limit
|
|
110
|
+
return records[start_idx:end_idx]
|
|
111
|
+
|
|
112
|
+
return records[:limit]
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def apply_filters(records: List[Dict[str, Any]], conditions: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
116
|
+
if not conditions:
|
|
117
|
+
return records
|
|
118
|
+
|
|
119
|
+
filtered_records = []
|
|
120
|
+
for record in records:
|
|
121
|
+
match = True
|
|
122
|
+
for key, value in conditions.items():
|
|
123
|
+
if key not in record or record[key] != value:
|
|
124
|
+
match = False
|
|
125
|
+
break
|
|
126
|
+
if match:
|
|
127
|
+
filtered_records.append(record)
|
|
128
|
+
|
|
129
|
+
return filtered_records
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def create_index_entries(
|
|
133
|
+
redis_client: Union[Redis, RedisCluster],
|
|
134
|
+
prefix: str,
|
|
135
|
+
table_type: str,
|
|
136
|
+
record_id: str,
|
|
137
|
+
record_data: Dict[str, Any],
|
|
138
|
+
index_fields: List[str],
|
|
139
|
+
) -> None:
|
|
140
|
+
for field in index_fields:
|
|
141
|
+
if field in record_data and record_data[field] is not None:
|
|
142
|
+
index_key = generate_index_key(prefix, table_type, field, str(record_data[field]))
|
|
143
|
+
redis_client.sadd(index_key, record_id)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def remove_index_entries(
|
|
147
|
+
redis_client: Union[Redis, RedisCluster],
|
|
148
|
+
prefix: str,
|
|
149
|
+
table_type: str,
|
|
150
|
+
record_id: str,
|
|
151
|
+
record_data: Dict[str, Any],
|
|
152
|
+
index_fields: List[str],
|
|
153
|
+
) -> None:
|
|
154
|
+
for field in index_fields:
|
|
155
|
+
if field in record_data and record_data[field] is not None:
|
|
156
|
+
index_key = generate_index_key(prefix, table_type, field, str(record_data[field]))
|
|
157
|
+
redis_client.srem(index_key, record_id)
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# -- Metrics utils --
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def calculate_date_metrics(date_to_process: date, sessions_data: dict) -> dict:
|
|
164
|
+
"""Calculate metrics for the given date.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
date_to_process (date): The date to calculate metrics for.
|
|
168
|
+
sessions_data (dict): The sessions data.
|
|
169
|
+
|
|
170
|
+
Returns:
|
|
171
|
+
dict: A dictionary with the calculated metrics.
|
|
172
|
+
"""
|
|
173
|
+
metrics = {
|
|
174
|
+
"users_count": 0,
|
|
175
|
+
"agent_sessions_count": 0,
|
|
176
|
+
"team_sessions_count": 0,
|
|
177
|
+
"workflow_sessions_count": 0,
|
|
178
|
+
"agent_runs_count": 0,
|
|
179
|
+
"team_runs_count": 0,
|
|
180
|
+
"workflow_runs_count": 0,
|
|
181
|
+
}
|
|
182
|
+
token_metrics = {
|
|
183
|
+
"input_tokens": 0,
|
|
184
|
+
"output_tokens": 0,
|
|
185
|
+
"total_tokens": 0,
|
|
186
|
+
"audio_total_tokens": 0,
|
|
187
|
+
"audio_input_tokens": 0,
|
|
188
|
+
"audio_output_tokens": 0,
|
|
189
|
+
"cache_read_tokens": 0,
|
|
190
|
+
"cache_write_tokens": 0,
|
|
191
|
+
"reasoning_tokens": 0,
|
|
192
|
+
}
|
|
193
|
+
model_counts: Dict[str, int] = {}
|
|
194
|
+
|
|
195
|
+
session_types = [
|
|
196
|
+
("agent", "agent_sessions_count", "agent_runs_count"),
|
|
197
|
+
("team", "team_sessions_count", "team_runs_count"),
|
|
198
|
+
("workflow", "workflow_sessions_count", "workflow_runs_count"),
|
|
199
|
+
]
|
|
200
|
+
all_user_ids = set()
|
|
201
|
+
|
|
202
|
+
for session_type, sessions_count_key, runs_count_key in session_types:
|
|
203
|
+
sessions = sessions_data.get(session_type, []) or []
|
|
204
|
+
metrics[sessions_count_key] = len(sessions)
|
|
205
|
+
|
|
206
|
+
for session in sessions:
|
|
207
|
+
if session.get("user_id"):
|
|
208
|
+
all_user_ids.add(session["user_id"])
|
|
209
|
+
metrics[runs_count_key] += len(session.get("runs", []))
|
|
210
|
+
if runs := session.get("runs", []):
|
|
211
|
+
for run in runs:
|
|
212
|
+
if model_id := run.get("model"):
|
|
213
|
+
model_provider = run.get("model_provider", "")
|
|
214
|
+
model_counts[f"{model_id}:{model_provider}"] = (
|
|
215
|
+
model_counts.get(f"{model_id}:{model_provider}", 0) + 1
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
session_metrics = session.get("session_data", {}).get("session_metrics", {})
|
|
219
|
+
for field in token_metrics:
|
|
220
|
+
token_metrics[field] += session_metrics.get(field, 0)
|
|
221
|
+
|
|
222
|
+
model_metrics = []
|
|
223
|
+
for model, count in model_counts.items():
|
|
224
|
+
model_id, model_provider = model.rsplit(":", 1)
|
|
225
|
+
model_metrics.append({"model_id": model_id, "model_provider": model_provider, "count": count})
|
|
226
|
+
|
|
227
|
+
metrics["users_count"] = len(all_user_ids)
|
|
228
|
+
current_time = int(time.time())
|
|
229
|
+
|
|
230
|
+
# Create a deterministic ID based on date and aggregation period. This simplifies avoiding duplicates
|
|
231
|
+
metric_id = f"{date_to_process.isoformat()}_daily"
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
"id": metric_id,
|
|
235
|
+
"date": date_to_process,
|
|
236
|
+
"completed": date_to_process < datetime.now(timezone.utc).date(),
|
|
237
|
+
"token_metrics": token_metrics,
|
|
238
|
+
"model_metrics": model_metrics,
|
|
239
|
+
"created_at": current_time,
|
|
240
|
+
"updated_at": current_time,
|
|
241
|
+
"aggregation_period": "daily",
|
|
242
|
+
**metrics,
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def fetch_all_sessions_data(
|
|
247
|
+
sessions: List[Dict[str, Any]], dates_to_process: list[date], start_timestamp: int
|
|
248
|
+
) -> Optional[dict]:
|
|
249
|
+
"""Return all session data for the given dates, for all session types.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
sessions (List[Dict[str, Any]]): The sessions data.
|
|
253
|
+
dates_to_process (list[date]): The dates to process.
|
|
254
|
+
start_timestamp (int): The start timestamp.
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
Optional[dict]: A dictionary with the session data for the given dates, for all session types.
|
|
258
|
+
"""
|
|
259
|
+
if not dates_to_process:
|
|
260
|
+
return None
|
|
261
|
+
|
|
262
|
+
all_sessions_data: Dict[str, Dict[str, List[Dict[str, Any]]]] = {
|
|
263
|
+
date_to_process.isoformat(): {"agent": [], "team": [], "workflow": []} for date_to_process in dates_to_process
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
for session in sessions:
|
|
267
|
+
session_date = (
|
|
268
|
+
datetime.fromtimestamp(session.get("created_at", start_timestamp), tz=timezone.utc).date().isoformat()
|
|
269
|
+
)
|
|
270
|
+
if session_date in all_sessions_data:
|
|
271
|
+
all_sessions_data[session_date][session["session_type"]].append(session)
|
|
272
|
+
|
|
273
|
+
return all_sessions_data
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def get_dates_to_calculate_metrics_for(starting_date: date) -> list[date]:
|
|
277
|
+
"""Return the list of dates to calculate metrics for.
|
|
278
|
+
|
|
279
|
+
Args:
|
|
280
|
+
starting_date (date): The starting date.
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
list[date]: The list of dates to calculate metrics for.
|
|
284
|
+
"""
|
|
285
|
+
today = datetime.now(timezone.utc).date()
|
|
286
|
+
days_diff = (today - starting_date).days + 1
|
|
287
|
+
if days_diff <= 0:
|
|
288
|
+
return []
|
|
289
|
+
return [starting_date + timedelta(days=x) for x in range(days_diff)]
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
# -- Cultural Knowledge util methods --
|
|
293
|
+
def serialize_cultural_knowledge_for_db(cultural_knowledge: CulturalKnowledge) -> Dict[str, Any]:
|
|
294
|
+
"""Serialize a CulturalKnowledge object for database storage.
|
|
295
|
+
|
|
296
|
+
Converts the model's separate content, categories, and notes fields
|
|
297
|
+
into a single dict for the database content column.
|
|
298
|
+
|
|
299
|
+
Args:
|
|
300
|
+
cultural_knowledge (CulturalKnowledge): The cultural knowledge object to serialize.
|
|
301
|
+
|
|
302
|
+
Returns:
|
|
303
|
+
Dict[str, Any]: A dictionary with the content field as a dict containing content, categories, and notes.
|
|
304
|
+
"""
|
|
305
|
+
content_dict: Dict[str, Any] = {}
|
|
306
|
+
if cultural_knowledge.content is not None:
|
|
307
|
+
content_dict["content"] = cultural_knowledge.content
|
|
308
|
+
if cultural_knowledge.categories is not None:
|
|
309
|
+
content_dict["categories"] = cultural_knowledge.categories
|
|
310
|
+
if cultural_knowledge.notes is not None:
|
|
311
|
+
content_dict["notes"] = cultural_knowledge.notes
|
|
312
|
+
|
|
313
|
+
return content_dict if content_dict else {}
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def deserialize_cultural_knowledge_from_db(db_row: Dict[str, Any]) -> CulturalKnowledge:
|
|
317
|
+
"""Deserialize a database row to a CulturalKnowledge object.
|
|
318
|
+
|
|
319
|
+
The database stores content as a dict containing content, categories, and notes.
|
|
320
|
+
This method extracts those fields and converts them back to the model format.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
db_row (Dict[str, Any]): The database row as a dictionary.
|
|
324
|
+
|
|
325
|
+
Returns:
|
|
326
|
+
CulturalKnowledge: The cultural knowledge object.
|
|
327
|
+
"""
|
|
328
|
+
# Extract content, categories, and notes from the content field
|
|
329
|
+
content_json = db_row.get("content", {}) or {}
|
|
330
|
+
|
|
331
|
+
return CulturalKnowledge.from_dict(
|
|
332
|
+
{
|
|
333
|
+
"id": db_row.get("id"),
|
|
334
|
+
"name": db_row.get("name"),
|
|
335
|
+
"summary": db_row.get("summary"),
|
|
336
|
+
"content": content_json.get("content"),
|
|
337
|
+
"categories": content_json.get("categories"),
|
|
338
|
+
"notes": content_json.get("notes"),
|
|
339
|
+
"metadata": db_row.get("metadata"),
|
|
340
|
+
"input": db_row.get("input"),
|
|
341
|
+
"created_at": db_row.get("created_at"),
|
|
342
|
+
"updated_at": db_row.get("updated_at"),
|
|
343
|
+
"agent_id": db_row.get("agent_id"),
|
|
344
|
+
"team_id": db_row.get("team_id"),
|
|
345
|
+
}
|
|
346
|
+
)
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
from typing import Any, Dict, Optional, Union
|
|
4
|
+
|
|
5
|
+
from typing_extensions import List
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class CulturalKnowledge:
|
|
10
|
+
"""Model for Cultural Knowledge
|
|
11
|
+
|
|
12
|
+
Notice: Culture is an experimental feature and is subject to change.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
# The id of the cultural knowledge, auto-generated if not provided
|
|
16
|
+
id: Optional[str] = None
|
|
17
|
+
name: Optional[str] = None
|
|
18
|
+
|
|
19
|
+
content: Optional[str] = None
|
|
20
|
+
categories: Optional[List[str]] = None
|
|
21
|
+
notes: Optional[List[str]] = None
|
|
22
|
+
|
|
23
|
+
summary: Optional[str] = None
|
|
24
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
25
|
+
input: Optional[str] = None
|
|
26
|
+
|
|
27
|
+
created_at: Optional[int] = field(default=None)
|
|
28
|
+
updated_at: Optional[int] = field(default=None)
|
|
29
|
+
|
|
30
|
+
agent_id: Optional[str] = None
|
|
31
|
+
team_id: Optional[str] = None
|
|
32
|
+
|
|
33
|
+
def __post_init__(self):
|
|
34
|
+
if self.name is not None and not self.name.strip():
|
|
35
|
+
raise ValueError("name must be a non-empty string")
|
|
36
|
+
self.created_at = _now_epoch_s() if self.created_at is None else _to_epoch_s(self.created_at)
|
|
37
|
+
self.updated_at = self.created_at if self.updated_at is None else _to_epoch_s(self.updated_at)
|
|
38
|
+
|
|
39
|
+
def bump_updated_at(self) -> None:
|
|
40
|
+
"""Bump updated_at to now (UTC)."""
|
|
41
|
+
self.updated_at = _now_epoch_s()
|
|
42
|
+
|
|
43
|
+
def preview(self) -> Dict[str, Any]:
|
|
44
|
+
"""Return a preview of the cultural knowledge"""
|
|
45
|
+
_preview: Dict[str, Any] = {
|
|
46
|
+
"name": self.name,
|
|
47
|
+
}
|
|
48
|
+
if self.categories is not None:
|
|
49
|
+
_preview["categories"] = self.categories
|
|
50
|
+
if self.summary is not None:
|
|
51
|
+
_preview["summary"] = self.summary[:100] + "..." if len(self.summary) > 100 else self.summary
|
|
52
|
+
if self.content is not None:
|
|
53
|
+
_preview["content"] = self.content[:100] + "..." if len(self.content) > 100 else self.content
|
|
54
|
+
if self.notes is not None:
|
|
55
|
+
_preview["notes"] = [note[:100] + "..." if len(note) > 100 else note for note in self.notes]
|
|
56
|
+
return _preview
|
|
57
|
+
|
|
58
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
59
|
+
_dict = {
|
|
60
|
+
"id": self.id,
|
|
61
|
+
"name": self.name,
|
|
62
|
+
"summary": self.summary,
|
|
63
|
+
"content": self.content,
|
|
64
|
+
"categories": self.categories,
|
|
65
|
+
"metadata": self.metadata,
|
|
66
|
+
"notes": self.notes,
|
|
67
|
+
"input": self.input,
|
|
68
|
+
"created_at": (_epoch_to_rfc3339_z(self.created_at) if self.created_at is not None else None),
|
|
69
|
+
"updated_at": (_epoch_to_rfc3339_z(self.updated_at) if self.updated_at is not None else None),
|
|
70
|
+
"agent_id": self.agent_id,
|
|
71
|
+
"team_id": self.team_id,
|
|
72
|
+
}
|
|
73
|
+
return {k: v for k, v in _dict.items() if v is not None}
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def from_dict(cls, data: Dict[str, Any]) -> "CulturalKnowledge":
|
|
77
|
+
d = dict(data)
|
|
78
|
+
|
|
79
|
+
# Preserve 0 and None explicitly; only process if key exists
|
|
80
|
+
if "created_at" in d and d["created_at"] is not None:
|
|
81
|
+
d["created_at"] = _to_epoch_s(d["created_at"])
|
|
82
|
+
if "updated_at" in d and d["updated_at"] is not None:
|
|
83
|
+
d["updated_at"] = _to_epoch_s(d["updated_at"])
|
|
84
|
+
|
|
85
|
+
return cls(**d)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _now_epoch_s() -> int:
|
|
89
|
+
return int(datetime.now(timezone.utc).timestamp())
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def _to_epoch_s(value: Union[int, float, str, datetime]) -> int:
|
|
93
|
+
"""Normalize various datetime representations to epoch seconds (UTC)."""
|
|
94
|
+
if isinstance(value, (int, float)):
|
|
95
|
+
# assume value is already in seconds
|
|
96
|
+
return int(value)
|
|
97
|
+
|
|
98
|
+
if isinstance(value, datetime):
|
|
99
|
+
dt = value
|
|
100
|
+
if dt.tzinfo is None:
|
|
101
|
+
dt = dt.replace(tzinfo=timezone.utc)
|
|
102
|
+
return int(dt.timestamp())
|
|
103
|
+
|
|
104
|
+
if isinstance(value, str):
|
|
105
|
+
s = value.strip()
|
|
106
|
+
if s.endswith("Z"):
|
|
107
|
+
s = s[:-1] + "+00:00"
|
|
108
|
+
try:
|
|
109
|
+
dt = datetime.fromisoformat(s)
|
|
110
|
+
except ValueError as e:
|
|
111
|
+
raise ValueError(f"Unsupported datetime string: {value!r}") from e
|
|
112
|
+
if dt.tzinfo is None:
|
|
113
|
+
dt = dt.replace(tzinfo=timezone.utc)
|
|
114
|
+
return int(dt.timestamp())
|
|
115
|
+
|
|
116
|
+
raise TypeError(f"Unsupported datetime value: {type(value)}")
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _epoch_to_rfc3339_z(ts: Union[int, float]) -> str:
|
|
120
|
+
return datetime.fromtimestamp(float(ts), tz=timezone.utc).isoformat().replace("+00:00", "Z")
|
agno/db/schemas/evals.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Any, Dict, Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class EvalType(str, Enum):
|
|
8
|
+
ACCURACY = "accuracy"
|
|
9
|
+
AGENT_AS_JUDGE = "agent_as_judge"
|
|
10
|
+
PERFORMANCE = "performance"
|
|
11
|
+
RELIABILITY = "reliability"
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class EvalFilterType(str, Enum):
|
|
15
|
+
AGENT = "agent"
|
|
16
|
+
TEAM = "team"
|
|
17
|
+
WORKFLOW = "workflow"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class EvalRunRecord(BaseModel):
|
|
21
|
+
"""Evaluation run results stored in the database"""
|
|
22
|
+
|
|
23
|
+
agent_id: Optional[str] = None
|
|
24
|
+
model_id: Optional[str] = None
|
|
25
|
+
model_provider: Optional[str] = None
|
|
26
|
+
team_id: Optional[str] = None
|
|
27
|
+
workflow_id: Optional[str] = None
|
|
28
|
+
name: Optional[str] = None
|
|
29
|
+
evaluated_component_name: Optional[str] = None
|
|
30
|
+
|
|
31
|
+
run_id: str
|
|
32
|
+
eval_type: EvalType
|
|
33
|
+
eval_data: Dict[str, Any]
|
|
34
|
+
eval_input: Optional[Dict[str, Any]] = None
|