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/media.py
CHANGED
|
@@ -1,134 +1,478 @@
|
|
|
1
1
|
from pathlib import Path
|
|
2
|
-
from typing import Any, Optional, Union
|
|
2
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
3
|
+
from uuid import uuid4
|
|
3
4
|
|
|
4
|
-
from pydantic import BaseModel, model_validator
|
|
5
|
+
from pydantic import BaseModel, field_validator, model_validator
|
|
5
6
|
|
|
7
|
+
from agno.utils.log import log_error
|
|
6
8
|
|
|
7
|
-
class Media(BaseModel):
|
|
8
|
-
id: str
|
|
9
|
-
original_prompt: Optional[str] = None
|
|
10
|
-
revised_prompt: Optional[str] = None
|
|
11
9
|
|
|
10
|
+
class Image(BaseModel):
|
|
11
|
+
"""Unified Image class for all use cases (input, output, artifacts)"""
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
url: str # Remote location
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
# Core content fields (exactly one required)
|
|
14
|
+
url: Optional[str] = None # Remote location
|
|
15
|
+
filepath: Optional[Union[Path, str]] = None # Local file path
|
|
16
|
+
content: Optional[bytes] = None # Raw image bytes (standardized to bytes)
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
# Metadata fields
|
|
19
|
+
id: Optional[str] = None # For tracking/referencing
|
|
20
|
+
format: Optional[str] = None # E.g. 'png', 'jpeg', 'webp', 'gif'
|
|
21
|
+
mime_type: Optional[str] = None # E.g. 'image/png', 'image/jpeg'
|
|
22
22
|
|
|
23
|
+
# Input-specific fields
|
|
24
|
+
detail: Optional[str] = (
|
|
25
|
+
None # low, medium, high or auto (per OpenAI spec https://platform.openai.com/docs/guides/vision?lang=node#low-or-high-fidelity-image-understanding)
|
|
26
|
+
)
|
|
23
27
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
mime_type: Optional[str] = None
|
|
28
|
+
# Output-specific fields (from tools/LLMs)
|
|
29
|
+
original_prompt: Optional[str] = None # Original generation prompt
|
|
30
|
+
revised_prompt: Optional[str] = None # Revised generation prompt
|
|
31
|
+
alt_text: Optional[str] = None # Alt text description
|
|
29
32
|
|
|
30
33
|
@model_validator(mode="before")
|
|
31
|
-
def
|
|
32
|
-
"""
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
def validate_and_normalize_content(cls, data: Any):
|
|
35
|
+
"""Ensure exactly one content source and normalize to bytes"""
|
|
36
|
+
if isinstance(data, dict):
|
|
37
|
+
url = data.get("url")
|
|
38
|
+
filepath = data.get("filepath")
|
|
39
|
+
content = data.get("content")
|
|
40
|
+
|
|
41
|
+
# Count non-None sources
|
|
42
|
+
sources = [x for x in [url, filepath, content] if x is not None]
|
|
43
|
+
if len(sources) == 0:
|
|
44
|
+
raise ValueError("One of 'url', 'filepath', or 'content' must be provided")
|
|
45
|
+
elif len(sources) > 1:
|
|
46
|
+
raise ValueError("Only one of 'url', 'filepath', or 'content' should be provided")
|
|
47
|
+
|
|
48
|
+
# Auto-generate ID if not provided
|
|
49
|
+
if data.get("id") is None:
|
|
50
|
+
data["id"] = str(uuid4())
|
|
51
|
+
|
|
39
52
|
return data
|
|
40
53
|
|
|
54
|
+
def get_content_bytes(self) -> Optional[bytes]:
|
|
55
|
+
"""Get image content as raw bytes, loading from URL/file if needed"""
|
|
56
|
+
if self.content:
|
|
57
|
+
return self.content
|
|
58
|
+
elif self.url:
|
|
59
|
+
import httpx
|
|
41
60
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
return httpx.get(self.url).content
|
|
62
|
+
elif self.filepath:
|
|
63
|
+
with open(self.filepath, "rb") as f:
|
|
64
|
+
return f.read()
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
def to_base64(self) -> Optional[str]:
|
|
68
|
+
"""Convert content to base64 string for transmission/storage"""
|
|
69
|
+
content_bytes = self.get_content_bytes()
|
|
70
|
+
if content_bytes:
|
|
71
|
+
import base64
|
|
72
|
+
|
|
73
|
+
return base64.b64encode(content_bytes).decode("utf-8")
|
|
74
|
+
return None
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def from_base64(
|
|
78
|
+
cls,
|
|
79
|
+
base64_content: str,
|
|
80
|
+
id: Optional[str] = None,
|
|
81
|
+
mime_type: Optional[str] = None,
|
|
82
|
+
format: Optional[str] = None,
|
|
83
|
+
**kwargs,
|
|
84
|
+
) -> "Image":
|
|
85
|
+
"""Create Image from base64 content"""
|
|
86
|
+
import base64
|
|
87
|
+
|
|
88
|
+
try:
|
|
89
|
+
content_bytes = base64.b64decode(base64_content)
|
|
90
|
+
except Exception:
|
|
91
|
+
content_bytes = base64_content.encode("utf-8")
|
|
92
|
+
|
|
93
|
+
return cls(content=content_bytes, id=id or str(uuid4()), mime_type=mime_type, format=format, **kwargs)
|
|
94
|
+
|
|
95
|
+
def to_dict(self, include_base64_content: bool = True) -> Dict[str, Any]:
|
|
96
|
+
"""Convert to dict, optionally including base64-encoded content"""
|
|
97
|
+
result = {
|
|
98
|
+
"id": self.id,
|
|
99
|
+
"url": self.url,
|
|
100
|
+
"filepath": str(self.filepath) if self.filepath else None,
|
|
101
|
+
"format": self.format,
|
|
102
|
+
"mime_type": self.mime_type,
|
|
103
|
+
"detail": self.detail,
|
|
104
|
+
"original_prompt": self.original_prompt,
|
|
105
|
+
"revised_prompt": self.revised_prompt,
|
|
106
|
+
"alt_text": self.alt_text,
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if include_base64_content and self.content:
|
|
110
|
+
result["content"] = self.to_base64()
|
|
111
|
+
|
|
112
|
+
return {k: v for k, v in result.items() if v is not None}
|
|
45
113
|
|
|
46
|
-
@model_validator(mode="before")
|
|
47
|
-
def validate_exclusive_video(cls, data: Any):
|
|
48
|
-
"""
|
|
49
|
-
Ensure that exactly one of `filepath`, or `content` is provided.
|
|
50
|
-
"""
|
|
51
|
-
# Extract the values from the input data
|
|
52
|
-
filepath = data.get("filepath")
|
|
53
|
-
content = data.get("content")
|
|
54
114
|
|
|
55
|
-
|
|
56
|
-
|
|
115
|
+
class Audio(BaseModel):
|
|
116
|
+
"""Unified Audio class for all use cases (input, output, artifacts)"""
|
|
57
117
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
118
|
+
# Core content fields (exactly one required)
|
|
119
|
+
url: Optional[str] = None
|
|
120
|
+
filepath: Optional[Union[Path, str]] = None
|
|
121
|
+
content: Optional[bytes] = None # Raw audio bytes (standardized to bytes)
|
|
62
122
|
|
|
63
|
-
|
|
123
|
+
# Metadata fields
|
|
124
|
+
id: Optional[str] = None
|
|
125
|
+
format: Optional[str] = None # E.g. 'mp3', 'wav', 'ogg'
|
|
126
|
+
mime_type: Optional[str] = None # E.g. 'audio/mpeg', 'audio/wav'
|
|
64
127
|
|
|
128
|
+
# Audio-specific metadata
|
|
129
|
+
duration: Optional[float] = None # Duration in seconds
|
|
130
|
+
sample_rate: Optional[int] = 24000 # Sample rate in Hz
|
|
131
|
+
channels: Optional[int] = 1 # Number of audio channels
|
|
65
132
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
format: Optional[str] = None
|
|
133
|
+
# Output-specific fields (from LLMs)
|
|
134
|
+
transcript: Optional[str] = None # Text transcript of audio
|
|
135
|
+
expires_at: Optional[int] = None # Expiration timestamp for temporary URLs
|
|
70
136
|
|
|
71
137
|
@model_validator(mode="before")
|
|
72
|
-
def
|
|
73
|
-
"""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
138
|
+
def validate_and_normalize_content(cls, data: Any):
|
|
139
|
+
"""Ensure exactly one content source and normalize to bytes"""
|
|
140
|
+
if isinstance(data, dict):
|
|
141
|
+
url = data.get("url")
|
|
142
|
+
filepath = data.get("filepath")
|
|
143
|
+
content = data.get("content")
|
|
144
|
+
|
|
145
|
+
sources = [x for x in [url, filepath, content] if x is not None]
|
|
146
|
+
if len(sources) == 0:
|
|
147
|
+
raise ValueError("One of 'url', 'filepath', or 'content' must be provided")
|
|
148
|
+
elif len(sources) > 1:
|
|
149
|
+
raise ValueError("Only one of 'url', 'filepath', or 'content' should be provided")
|
|
150
|
+
|
|
151
|
+
if data.get("id") is None:
|
|
152
|
+
data["id"] = str(uuid4())
|
|
79
153
|
|
|
80
|
-
|
|
81
|
-
count = len([field for field in [filepath, content] if field is not None])
|
|
154
|
+
return data
|
|
82
155
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
156
|
+
def get_content_bytes(self) -> Optional[bytes]:
|
|
157
|
+
"""Get audio content as raw bytes"""
|
|
158
|
+
if self.content:
|
|
159
|
+
return self.content
|
|
160
|
+
elif self.url:
|
|
161
|
+
import httpx
|
|
87
162
|
|
|
88
|
-
|
|
163
|
+
return httpx.get(self.url).content
|
|
164
|
+
elif self.filepath:
|
|
165
|
+
with open(self.filepath, "rb") as f:
|
|
166
|
+
return f.read()
|
|
167
|
+
return None
|
|
168
|
+
|
|
169
|
+
def to_base64(self) -> Optional[str]:
|
|
170
|
+
"""Convert content to base64 string"""
|
|
171
|
+
content_bytes = self.get_content_bytes()
|
|
172
|
+
if content_bytes:
|
|
173
|
+
import base64
|
|
174
|
+
|
|
175
|
+
return base64.b64encode(content_bytes).decode("utf-8")
|
|
176
|
+
return None
|
|
177
|
+
|
|
178
|
+
@classmethod
|
|
179
|
+
def from_base64(
|
|
180
|
+
cls,
|
|
181
|
+
base64_content: str,
|
|
182
|
+
id: Optional[str] = None,
|
|
183
|
+
mime_type: Optional[str] = None,
|
|
184
|
+
transcript: Optional[str] = None,
|
|
185
|
+
expires_at: Optional[int] = None,
|
|
186
|
+
sample_rate: Optional[int] = 24000,
|
|
187
|
+
channels: Optional[int] = 1,
|
|
188
|
+
**kwargs,
|
|
189
|
+
) -> "Audio":
|
|
190
|
+
"""Create Audio from base64 content (useful for API responses)"""
|
|
191
|
+
import base64
|
|
192
|
+
|
|
193
|
+
try:
|
|
194
|
+
content_bytes = base64.b64decode(base64_content)
|
|
195
|
+
except Exception:
|
|
196
|
+
# If not valid base64, encode as UTF-8 bytes
|
|
197
|
+
content_bytes = base64_content.encode("utf-8")
|
|
198
|
+
|
|
199
|
+
return cls(
|
|
200
|
+
content=content_bytes,
|
|
201
|
+
id=id or str(uuid4()),
|
|
202
|
+
mime_type=mime_type,
|
|
203
|
+
transcript=transcript,
|
|
204
|
+
expires_at=expires_at,
|
|
205
|
+
sample_rate=sample_rate,
|
|
206
|
+
channels=channels,
|
|
207
|
+
**kwargs,
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
def to_dict(self, include_base64_content: bool = True) -> Dict[str, Any]:
|
|
211
|
+
"""Convert to dict, optionally including base64-encoded content"""
|
|
212
|
+
result = {
|
|
213
|
+
"id": self.id,
|
|
214
|
+
"url": self.url,
|
|
215
|
+
"filepath": str(self.filepath) if self.filepath else None,
|
|
216
|
+
"format": self.format,
|
|
217
|
+
"mime_type": self.mime_type,
|
|
218
|
+
"duration": self.duration,
|
|
219
|
+
"sample_rate": self.sample_rate,
|
|
220
|
+
"channels": self.channels,
|
|
221
|
+
"transcript": self.transcript,
|
|
222
|
+
"expires_at": self.expires_at,
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if include_base64_content and self.content:
|
|
226
|
+
result["content"] = self.to_base64()
|
|
227
|
+
|
|
228
|
+
return {k: v for k, v in result.items() if v is not None}
|
|
89
229
|
|
|
90
230
|
|
|
91
|
-
class
|
|
92
|
-
|
|
93
|
-
content: str # Base64 encoded
|
|
94
|
-
expires_at: int
|
|
95
|
-
transcript: str
|
|
231
|
+
class Video(BaseModel):
|
|
232
|
+
"""Unified Video class for all use cases (input, output, artifacts)"""
|
|
96
233
|
|
|
234
|
+
# Core content fields (exactly one required)
|
|
235
|
+
url: Optional[str] = None
|
|
236
|
+
filepath: Optional[Union[Path, str]] = None
|
|
237
|
+
content: Optional[bytes] = None # Raw video bytes (standardized to bytes)
|
|
97
238
|
|
|
98
|
-
|
|
99
|
-
url: Optional[str] = None # Remote location for image
|
|
100
|
-
filepath: Optional[Union[Path, str]] = None # Absolute local location for image
|
|
101
|
-
content: Optional[Any] = None # Actual image bytes content
|
|
102
|
-
detail: Optional[str] = (
|
|
103
|
-
None # low, medium, high or auto (per OpenAI spec https://platform.openai.com/docs/guides/vision?lang=node#low-or-high-fidelity-image-understanding)
|
|
104
|
-
)
|
|
239
|
+
# Metadata fields
|
|
105
240
|
id: Optional[str] = None
|
|
241
|
+
format: Optional[str] = None # E.g. 'mp4', 'mov', 'avi', 'webm'
|
|
242
|
+
mime_type: Optional[str] = None # E.g. 'video/mp4', 'video/quicktime'
|
|
106
243
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
244
|
+
# Video-specific metadata
|
|
245
|
+
duration: Optional[float] = None # Duration in seconds
|
|
246
|
+
width: Optional[int] = None # Video width in pixels
|
|
247
|
+
height: Optional[int] = None # Video height in pixels
|
|
248
|
+
fps: Optional[float] = None # Frames per second
|
|
249
|
+
|
|
250
|
+
# Output-specific fields (from tools)
|
|
251
|
+
eta: Optional[str] = None # Estimated time for generation
|
|
252
|
+
original_prompt: Optional[str] = None
|
|
253
|
+
revised_prompt: Optional[str] = None
|
|
254
|
+
|
|
255
|
+
@model_validator(mode="before")
|
|
256
|
+
def validate_and_normalize_content(cls, data: Any):
|
|
257
|
+
"""Ensure exactly one content source and normalize to bytes"""
|
|
258
|
+
if isinstance(data, dict):
|
|
259
|
+
url = data.get("url")
|
|
260
|
+
filepath = data.get("filepath")
|
|
261
|
+
content = data.get("content")
|
|
262
|
+
|
|
263
|
+
sources = [x for x in [url, filepath, content] if x is not None]
|
|
264
|
+
if len(sources) == 0:
|
|
265
|
+
raise ValueError("One of 'url', 'filepath', or 'content' must be provided")
|
|
266
|
+
elif len(sources) > 1:
|
|
267
|
+
raise ValueError("Only one of 'url', 'filepath', or 'content' should be provided")
|
|
268
|
+
|
|
269
|
+
if data.get("id") is None:
|
|
270
|
+
data["id"] = str(uuid4())
|
|
271
|
+
|
|
272
|
+
return data
|
|
273
|
+
|
|
274
|
+
def get_content_bytes(self) -> Optional[bytes]:
|
|
275
|
+
"""Get video content as raw bytes"""
|
|
276
|
+
if self.content:
|
|
277
|
+
return self.content
|
|
278
|
+
elif self.url:
|
|
279
|
+
import httpx
|
|
110
280
|
|
|
111
|
-
if self.url:
|
|
112
281
|
return httpx.get(self.url).content
|
|
113
|
-
|
|
114
|
-
|
|
282
|
+
elif self.filepath:
|
|
283
|
+
with open(self.filepath, "rb") as f:
|
|
284
|
+
return f.read()
|
|
285
|
+
return None
|
|
286
|
+
|
|
287
|
+
def to_base64(self) -> Optional[str]:
|
|
288
|
+
"""Convert content to base64 string"""
|
|
289
|
+
content_bytes = self.get_content_bytes()
|
|
290
|
+
if content_bytes:
|
|
291
|
+
import base64
|
|
292
|
+
|
|
293
|
+
return base64.b64encode(content_bytes).decode("utf-8")
|
|
294
|
+
return None
|
|
295
|
+
|
|
296
|
+
@classmethod
|
|
297
|
+
def from_base64(
|
|
298
|
+
cls,
|
|
299
|
+
base64_content: str,
|
|
300
|
+
id: Optional[str] = None,
|
|
301
|
+
mime_type: Optional[str] = None,
|
|
302
|
+
format: Optional[str] = None,
|
|
303
|
+
**kwargs,
|
|
304
|
+
) -> "Video":
|
|
305
|
+
"""Create Image from base64 content"""
|
|
306
|
+
import base64
|
|
307
|
+
|
|
308
|
+
try:
|
|
309
|
+
content_bytes = base64.b64decode(base64_content)
|
|
310
|
+
except Exception:
|
|
311
|
+
content_bytes = base64_content.encode("utf-8")
|
|
312
|
+
|
|
313
|
+
return cls(content=content_bytes, id=id or str(uuid4()), mime_type=mime_type, format=format, **kwargs)
|
|
314
|
+
|
|
315
|
+
def to_dict(self, include_base64_content: bool = True) -> Dict[str, Any]:
|
|
316
|
+
"""Convert to dict, optionally including base64-encoded content"""
|
|
317
|
+
result = {
|
|
318
|
+
"id": self.id,
|
|
319
|
+
"url": self.url,
|
|
320
|
+
"filepath": str(self.filepath) if self.filepath else None,
|
|
321
|
+
"format": self.format,
|
|
322
|
+
"mime_type": self.mime_type,
|
|
323
|
+
"duration": self.duration,
|
|
324
|
+
"width": self.width,
|
|
325
|
+
"height": self.height,
|
|
326
|
+
"fps": self.fps,
|
|
327
|
+
"eta": self.eta,
|
|
328
|
+
"original_prompt": self.original_prompt,
|
|
329
|
+
"revised_prompt": self.revised_prompt,
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
if include_base64_content and self.content:
|
|
333
|
+
result["content"] = self.to_base64()
|
|
334
|
+
|
|
335
|
+
return {k: v for k, v in result.items() if v is not None}
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class File(BaseModel):
|
|
339
|
+
id: Optional[str] = None
|
|
340
|
+
url: Optional[str] = None
|
|
341
|
+
filepath: Optional[Union[Path, str]] = None
|
|
342
|
+
# Raw bytes content of a file
|
|
343
|
+
content: Optional[Any] = None
|
|
344
|
+
mime_type: Optional[str] = None
|
|
345
|
+
|
|
346
|
+
file_type: Optional[str] = None
|
|
347
|
+
filename: Optional[str] = None
|
|
348
|
+
size: Optional[int] = None
|
|
349
|
+
# External file object (e.g. GeminiFile, must be a valid object as expected by the model you are using)
|
|
350
|
+
external: Optional[Any] = None
|
|
351
|
+
format: Optional[str] = None # E.g. `pdf`, `txt`, `csv`, `xml`, etc.
|
|
352
|
+
name: Optional[str] = None # Name of the file, mandatory for AWS Bedrock document input
|
|
115
353
|
|
|
116
354
|
@model_validator(mode="before")
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
Ensure
|
|
355
|
+
@classmethod
|
|
356
|
+
def check_at_least_one_source(cls, data):
|
|
357
|
+
"""Ensure at least one of url, filepath, or content is provided."""
|
|
358
|
+
if isinstance(data, dict) and not any(data.get(field) for field in ["url", "filepath", "content", "external"]):
|
|
359
|
+
raise ValueError("At least one of url, filepath, content or external must be provided")
|
|
360
|
+
return data
|
|
361
|
+
|
|
362
|
+
@field_validator("mime_type")
|
|
363
|
+
@classmethod
|
|
364
|
+
def validate_mime_type(cls, v):
|
|
365
|
+
"""Validate that the mime_type is one of the allowed types."""
|
|
366
|
+
if v is not None and v not in cls.valid_mime_types():
|
|
367
|
+
raise ValueError(f"Invalid MIME type: {v}. Must be one of: {cls.valid_mime_types()}")
|
|
368
|
+
return v
|
|
369
|
+
|
|
370
|
+
@classmethod
|
|
371
|
+
def valid_mime_types(cls) -> List[str]:
|
|
372
|
+
return [
|
|
373
|
+
"application/pdf",
|
|
374
|
+
"application/json",
|
|
375
|
+
"application/x-javascript",
|
|
376
|
+
"application/json",
|
|
377
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
378
|
+
"text/javascript",
|
|
379
|
+
"application/x-python",
|
|
380
|
+
"text/x-python",
|
|
381
|
+
"text/plain",
|
|
382
|
+
"text/html",
|
|
383
|
+
"text/css",
|
|
384
|
+
"text/md",
|
|
385
|
+
"text/csv",
|
|
386
|
+
"text/xml",
|
|
387
|
+
"text/rtf",
|
|
388
|
+
]
|
|
389
|
+
|
|
390
|
+
@classmethod
|
|
391
|
+
def from_base64(
|
|
392
|
+
cls,
|
|
393
|
+
base64_content: str,
|
|
394
|
+
id: Optional[str] = None,
|
|
395
|
+
mime_type: Optional[str] = None,
|
|
396
|
+
filename: Optional[str] = None,
|
|
397
|
+
name: Optional[str] = None,
|
|
398
|
+
format: Optional[str] = None,
|
|
399
|
+
) -> "File":
|
|
400
|
+
"""Create File from base64 encoded content or plain text.
|
|
401
|
+
|
|
402
|
+
Handles both base64-encoded binary content and plain text content
|
|
403
|
+
(which is stored as UTF-8 strings for text/* MIME types).
|
|
120
404
|
"""
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
405
|
+
import base64
|
|
406
|
+
|
|
407
|
+
try:
|
|
408
|
+
content_bytes = base64.b64decode(base64_content)
|
|
409
|
+
except Exception:
|
|
410
|
+
# If not valid base64, it might be plain text content (text/csv, text/plain, etc.)
|
|
411
|
+
# which is stored as UTF-8 strings, not base64
|
|
412
|
+
content_bytes = base64_content.encode("utf-8")
|
|
413
|
+
|
|
414
|
+
return cls(
|
|
415
|
+
content=content_bytes,
|
|
416
|
+
id=id,
|
|
417
|
+
mime_type=mime_type,
|
|
418
|
+
filename=filename,
|
|
419
|
+
name=name,
|
|
420
|
+
format=format,
|
|
421
|
+
)
|
|
125
422
|
|
|
126
|
-
|
|
127
|
-
|
|
423
|
+
@property
|
|
424
|
+
def file_url_content(self) -> Optional[Tuple[bytes, str]]:
|
|
425
|
+
import httpx
|
|
128
426
|
|
|
129
|
-
if
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
427
|
+
if self.url:
|
|
428
|
+
try:
|
|
429
|
+
response = httpx.get(self.url)
|
|
430
|
+
content = response.content
|
|
431
|
+
mime_type = response.headers.get("Content-Type", "").split(";")[0]
|
|
432
|
+
return content, mime_type
|
|
433
|
+
except Exception:
|
|
434
|
+
log_error(f"Failed to download file from {self.url}")
|
|
435
|
+
return None
|
|
436
|
+
else:
|
|
437
|
+
return None
|
|
133
438
|
|
|
134
|
-
|
|
439
|
+
def _normalise_content(self) -> Optional[Union[str, bytes]]:
|
|
440
|
+
if self.content is None:
|
|
441
|
+
return None
|
|
442
|
+
content_normalised: Union[str, bytes] = self.content
|
|
443
|
+
if content_normalised and isinstance(content_normalised, bytes):
|
|
444
|
+
from base64 import b64encode
|
|
445
|
+
|
|
446
|
+
try:
|
|
447
|
+
if self.mime_type and self.mime_type.startswith("text/"):
|
|
448
|
+
content_normalised = content_normalised.decode("utf-8")
|
|
449
|
+
else:
|
|
450
|
+
content_normalised = b64encode(content_normalised).decode("utf-8")
|
|
451
|
+
except UnicodeDecodeError:
|
|
452
|
+
if isinstance(self.content, bytes):
|
|
453
|
+
content_normalised = b64encode(self.content).decode("utf-8")
|
|
454
|
+
except Exception:
|
|
455
|
+
try:
|
|
456
|
+
if isinstance(self.content, bytes):
|
|
457
|
+
content_normalised = b64encode(self.content).decode("utf-8")
|
|
458
|
+
except Exception:
|
|
459
|
+
pass
|
|
460
|
+
return content_normalised
|
|
461
|
+
|
|
462
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
463
|
+
content_normalised = self._normalise_content()
|
|
464
|
+
|
|
465
|
+
response_dict = {
|
|
466
|
+
"id": self.id,
|
|
467
|
+
"url": self.url,
|
|
468
|
+
"filepath": str(self.filepath) if self.filepath else None,
|
|
469
|
+
"content": content_normalised,
|
|
470
|
+
"mime_type": self.mime_type,
|
|
471
|
+
"file_type": self.file_type,
|
|
472
|
+
"filename": self.filename,
|
|
473
|
+
"size": self.size,
|
|
474
|
+
"external": self.external,
|
|
475
|
+
"format": self.format,
|
|
476
|
+
"name": self.name,
|
|
477
|
+
}
|
|
478
|
+
return {k: v for k, v in response_dict.items() if v is not None}
|
agno/memory/__init__.py
CHANGED
|
@@ -1,3 +1,16 @@
|
|
|
1
|
-
from agno.memory.
|
|
2
|
-
from agno.memory.
|
|
3
|
-
|
|
1
|
+
from agno.memory.manager import MemoryManager, UserMemory
|
|
2
|
+
from agno.memory.strategies import (
|
|
3
|
+
MemoryOptimizationStrategy,
|
|
4
|
+
MemoryOptimizationStrategyFactory,
|
|
5
|
+
MemoryOptimizationStrategyType,
|
|
6
|
+
SummarizeStrategy,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"MemoryManager",
|
|
11
|
+
"UserMemory",
|
|
12
|
+
"MemoryOptimizationStrategy",
|
|
13
|
+
"MemoryOptimizationStrategyType",
|
|
14
|
+
"MemoryOptimizationStrategyFactory",
|
|
15
|
+
"SummarizeStrategy",
|
|
16
|
+
]
|