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/run/base.py
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
from dataclasses import asdict, dataclass
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel
|
|
6
|
+
|
|
7
|
+
from agno.filters import FilterExpr
|
|
8
|
+
from agno.media import Audio, Image, Video
|
|
9
|
+
from agno.models.message import Citations, Message, MessageReferences
|
|
10
|
+
from agno.models.metrics import Metrics
|
|
11
|
+
from agno.reasoning.step import ReasoningStep
|
|
12
|
+
from agno.utils.log import log_error
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@dataclass
|
|
16
|
+
class RunContext:
|
|
17
|
+
run_id: str
|
|
18
|
+
session_id: str
|
|
19
|
+
user_id: Optional[str] = None
|
|
20
|
+
|
|
21
|
+
dependencies: Optional[Dict[str, Any]] = None
|
|
22
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
23
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
24
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
25
|
+
output_schema: Optional[Type[BaseModel]] = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass
|
|
29
|
+
class BaseRunOutputEvent:
|
|
30
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
31
|
+
_dict = {
|
|
32
|
+
k: v
|
|
33
|
+
for k, v in asdict(self).items()
|
|
34
|
+
if v is not None
|
|
35
|
+
and k
|
|
36
|
+
not in [
|
|
37
|
+
"tools",
|
|
38
|
+
"tool",
|
|
39
|
+
"metadata",
|
|
40
|
+
"image",
|
|
41
|
+
"images",
|
|
42
|
+
"videos",
|
|
43
|
+
"audio",
|
|
44
|
+
"response_audio",
|
|
45
|
+
"citations",
|
|
46
|
+
"member_responses",
|
|
47
|
+
"reasoning_messages",
|
|
48
|
+
"reasoning_steps",
|
|
49
|
+
"references",
|
|
50
|
+
"additional_input",
|
|
51
|
+
"session_summary",
|
|
52
|
+
"metrics",
|
|
53
|
+
"run_input",
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if hasattr(self, "metadata") and self.metadata is not None:
|
|
58
|
+
_dict["metadata"] = self.metadata
|
|
59
|
+
|
|
60
|
+
if hasattr(self, "additional_input") and self.additional_input is not None:
|
|
61
|
+
_dict["additional_input"] = [m.to_dict() for m in self.additional_input]
|
|
62
|
+
|
|
63
|
+
if hasattr(self, "reasoning_messages") and self.reasoning_messages is not None:
|
|
64
|
+
_dict["reasoning_messages"] = [m.to_dict() for m in self.reasoning_messages]
|
|
65
|
+
|
|
66
|
+
if hasattr(self, "reasoning_steps") and self.reasoning_steps is not None:
|
|
67
|
+
_dict["reasoning_steps"] = [rs.model_dump() for rs in self.reasoning_steps]
|
|
68
|
+
|
|
69
|
+
if hasattr(self, "references") and self.references is not None:
|
|
70
|
+
_dict["references"] = [r.model_dump() for r in self.references]
|
|
71
|
+
|
|
72
|
+
if hasattr(self, "member_responses") and self.member_responses:
|
|
73
|
+
_dict["member_responses"] = [response.to_dict() for response in self.member_responses]
|
|
74
|
+
|
|
75
|
+
if hasattr(self, "images") and self.images is not None:
|
|
76
|
+
_dict["images"] = []
|
|
77
|
+
for img in self.images:
|
|
78
|
+
if isinstance(img, Image):
|
|
79
|
+
_dict["images"].append(img.to_dict())
|
|
80
|
+
else:
|
|
81
|
+
_dict["images"].append(img)
|
|
82
|
+
|
|
83
|
+
if hasattr(self, "videos") and self.videos is not None:
|
|
84
|
+
_dict["videos"] = []
|
|
85
|
+
for vid in self.videos:
|
|
86
|
+
if isinstance(vid, Video):
|
|
87
|
+
_dict["videos"].append(vid.to_dict())
|
|
88
|
+
else:
|
|
89
|
+
_dict["videos"].append(vid)
|
|
90
|
+
|
|
91
|
+
if hasattr(self, "audio") and self.audio is not None:
|
|
92
|
+
_dict["audio"] = []
|
|
93
|
+
for aud in self.audio:
|
|
94
|
+
if isinstance(aud, Audio):
|
|
95
|
+
_dict["audio"].append(aud.to_dict())
|
|
96
|
+
else:
|
|
97
|
+
_dict["audio"].append(aud)
|
|
98
|
+
|
|
99
|
+
if hasattr(self, "response_audio") and self.response_audio is not None:
|
|
100
|
+
if isinstance(self.response_audio, Audio):
|
|
101
|
+
_dict["response_audio"] = self.response_audio.to_dict()
|
|
102
|
+
else:
|
|
103
|
+
_dict["response_audio"] = self.response_audio
|
|
104
|
+
|
|
105
|
+
if hasattr(self, "citations") and self.citations is not None:
|
|
106
|
+
if isinstance(self.citations, Citations):
|
|
107
|
+
_dict["citations"] = self.citations.model_dump(exclude_none=True)
|
|
108
|
+
else:
|
|
109
|
+
_dict["citations"] = self.citations
|
|
110
|
+
|
|
111
|
+
if hasattr(self, "content") and self.content and isinstance(self.content, BaseModel):
|
|
112
|
+
_dict["content"] = self.content.model_dump(exclude_none=True)
|
|
113
|
+
|
|
114
|
+
if hasattr(self, "tools") and self.tools is not None:
|
|
115
|
+
from agno.models.response import ToolExecution
|
|
116
|
+
|
|
117
|
+
_dict["tools"] = []
|
|
118
|
+
for tool in self.tools:
|
|
119
|
+
if isinstance(tool, ToolExecution):
|
|
120
|
+
_dict["tools"].append(tool.to_dict())
|
|
121
|
+
else:
|
|
122
|
+
_dict["tools"].append(tool)
|
|
123
|
+
|
|
124
|
+
if hasattr(self, "tool") and self.tool is not None:
|
|
125
|
+
from agno.models.response import ToolExecution
|
|
126
|
+
|
|
127
|
+
if isinstance(self.tool, ToolExecution):
|
|
128
|
+
_dict["tool"] = self.tool.to_dict()
|
|
129
|
+
else:
|
|
130
|
+
_dict["tool"] = self.tool
|
|
131
|
+
|
|
132
|
+
if hasattr(self, "metrics") and self.metrics is not None:
|
|
133
|
+
_dict["metrics"] = self.metrics.to_dict()
|
|
134
|
+
|
|
135
|
+
if hasattr(self, "session_summary") and self.session_summary is not None:
|
|
136
|
+
_dict["session_summary"] = self.session_summary.to_dict()
|
|
137
|
+
|
|
138
|
+
if hasattr(self, "run_input") and self.run_input is not None:
|
|
139
|
+
_dict["run_input"] = self.run_input.to_dict()
|
|
140
|
+
|
|
141
|
+
return _dict
|
|
142
|
+
|
|
143
|
+
def to_json(self, separators=(", ", ": "), indent: Optional[int] = 2) -> str:
|
|
144
|
+
import json
|
|
145
|
+
|
|
146
|
+
from agno.utils.serialize import json_serializer
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
_dict = self.to_dict()
|
|
150
|
+
except Exception:
|
|
151
|
+
log_error("Failed to convert response event to json", exc_info=True)
|
|
152
|
+
raise
|
|
153
|
+
|
|
154
|
+
if indent is None:
|
|
155
|
+
return json.dumps(_dict, separators=separators, default=json_serializer, ensure_ascii=False)
|
|
156
|
+
else:
|
|
157
|
+
return json.dumps(_dict, indent=indent, separators=separators, default=json_serializer, ensure_ascii=False)
|
|
158
|
+
|
|
159
|
+
@classmethod
|
|
160
|
+
def from_dict(cls, data: Dict[str, Any]):
|
|
161
|
+
tool = data.pop("tool", None)
|
|
162
|
+
if tool:
|
|
163
|
+
from agno.models.response import ToolExecution
|
|
164
|
+
|
|
165
|
+
data["tool"] = ToolExecution.from_dict(tool)
|
|
166
|
+
|
|
167
|
+
images = data.pop("images", None)
|
|
168
|
+
if images:
|
|
169
|
+
data["images"] = [Image.model_validate(image) for image in images]
|
|
170
|
+
|
|
171
|
+
videos = data.pop("videos", None)
|
|
172
|
+
if videos:
|
|
173
|
+
data["videos"] = [Video.model_validate(video) for video in videos]
|
|
174
|
+
|
|
175
|
+
audio = data.pop("audio", None)
|
|
176
|
+
if audio:
|
|
177
|
+
data["audio"] = [Audio.model_validate(audio) for audio in audio]
|
|
178
|
+
|
|
179
|
+
response_audio = data.pop("response_audio", None)
|
|
180
|
+
if response_audio:
|
|
181
|
+
data["response_audio"] = Audio.model_validate(response_audio)
|
|
182
|
+
|
|
183
|
+
additional_input = data.pop("additional_input", None)
|
|
184
|
+
if additional_input is not None:
|
|
185
|
+
data["additional_input"] = [Message.model_validate(message) for message in additional_input]
|
|
186
|
+
|
|
187
|
+
reasoning_steps = data.pop("reasoning_steps", None)
|
|
188
|
+
if reasoning_steps is not None:
|
|
189
|
+
data["reasoning_steps"] = [ReasoningStep.model_validate(step) for step in reasoning_steps]
|
|
190
|
+
|
|
191
|
+
reasoning_messages = data.pop("reasoning_messages", None)
|
|
192
|
+
if reasoning_messages is not None:
|
|
193
|
+
data["reasoning_messages"] = [Message.model_validate(message) for message in reasoning_messages]
|
|
194
|
+
|
|
195
|
+
references = data.pop("references", None)
|
|
196
|
+
if references is not None:
|
|
197
|
+
data["references"] = [MessageReferences.model_validate(reference) for reference in references]
|
|
198
|
+
|
|
199
|
+
metrics = data.pop("metrics", None)
|
|
200
|
+
if metrics:
|
|
201
|
+
data["metrics"] = Metrics(**metrics)
|
|
202
|
+
|
|
203
|
+
session_summary = data.pop("session_summary", None)
|
|
204
|
+
if session_summary:
|
|
205
|
+
from agno.session.summary import SessionSummary
|
|
206
|
+
|
|
207
|
+
data["session_summary"] = SessionSummary.from_dict(session_summary)
|
|
208
|
+
|
|
209
|
+
run_input = data.pop("run_input", None)
|
|
210
|
+
if run_input:
|
|
211
|
+
from agno.run.team import BaseTeamRunEvent
|
|
212
|
+
|
|
213
|
+
if issubclass(cls, BaseTeamRunEvent):
|
|
214
|
+
from agno.run.team import TeamRunInput
|
|
215
|
+
|
|
216
|
+
data["run_input"] = TeamRunInput.from_dict(run_input)
|
|
217
|
+
else:
|
|
218
|
+
from agno.run.agent import RunInput
|
|
219
|
+
|
|
220
|
+
data["run_input"] = RunInput.from_dict(run_input)
|
|
221
|
+
|
|
222
|
+
# Filter data to only include fields that are actually defined in the target class
|
|
223
|
+
from dataclasses import fields
|
|
224
|
+
|
|
225
|
+
supported_fields = {f.name for f in fields(cls)}
|
|
226
|
+
filtered_data = {k: v for k, v in data.items() if k in supported_fields}
|
|
227
|
+
|
|
228
|
+
return cls(**filtered_data)
|
|
229
|
+
|
|
230
|
+
@property
|
|
231
|
+
def is_paused(self):
|
|
232
|
+
return False
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def is_cancelled(self):
|
|
236
|
+
return False
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
class RunStatus(str, Enum):
|
|
240
|
+
"""State of the main run response"""
|
|
241
|
+
|
|
242
|
+
pending = "PENDING"
|
|
243
|
+
running = "RUNNING"
|
|
244
|
+
completed = "COMPLETED"
|
|
245
|
+
paused = "PAUSED"
|
|
246
|
+
cancelled = "CANCELLED"
|
|
247
|
+
error = "ERROR"
|
agno/run/cancel.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Run cancellation management."""
|
|
2
|
+
|
|
3
|
+
import threading
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
from agno.exceptions import RunCancelledException
|
|
7
|
+
from agno.utils.log import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class RunCancellationManager:
|
|
11
|
+
"""Manages cancellation state for agent runs."""
|
|
12
|
+
|
|
13
|
+
def __init__(self):
|
|
14
|
+
self._cancelled_runs: Dict[str, bool] = {}
|
|
15
|
+
self._lock = threading.Lock()
|
|
16
|
+
|
|
17
|
+
def register_run(self, run_id: str) -> None:
|
|
18
|
+
"""Register a new run as not cancelled."""
|
|
19
|
+
with self._lock:
|
|
20
|
+
self._cancelled_runs[run_id] = False
|
|
21
|
+
|
|
22
|
+
def cancel_run(self, run_id: str) -> bool:
|
|
23
|
+
"""Cancel a run by marking it as cancelled.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
bool: True if run was found and cancelled, False if run not found.
|
|
27
|
+
"""
|
|
28
|
+
with self._lock:
|
|
29
|
+
if run_id in self._cancelled_runs:
|
|
30
|
+
self._cancelled_runs[run_id] = True
|
|
31
|
+
logger.info(f"Run {run_id} marked for cancellation")
|
|
32
|
+
return True
|
|
33
|
+
else:
|
|
34
|
+
logger.warning(f"Attempted to cancel unknown run {run_id}")
|
|
35
|
+
return False
|
|
36
|
+
|
|
37
|
+
def is_cancelled(self, run_id: str) -> bool:
|
|
38
|
+
"""Check if a run is cancelled."""
|
|
39
|
+
with self._lock:
|
|
40
|
+
return self._cancelled_runs.get(run_id, False)
|
|
41
|
+
|
|
42
|
+
def cleanup_run(self, run_id: str) -> None:
|
|
43
|
+
"""Remove a run from tracking (called when run completes)."""
|
|
44
|
+
with self._lock:
|
|
45
|
+
if run_id in self._cancelled_runs:
|
|
46
|
+
del self._cancelled_runs[run_id]
|
|
47
|
+
|
|
48
|
+
def raise_if_cancelled(self, run_id: str) -> None:
|
|
49
|
+
"""Check if a run should be cancelled and raise exception if so."""
|
|
50
|
+
if self.is_cancelled(run_id):
|
|
51
|
+
logger.info(f"Cancelling run {run_id}")
|
|
52
|
+
raise RunCancelledException(f"Run {run_id} was cancelled")
|
|
53
|
+
|
|
54
|
+
def get_active_runs(self) -> Dict[str, bool]:
|
|
55
|
+
"""Get all currently tracked runs and their cancellation status."""
|
|
56
|
+
with self._lock:
|
|
57
|
+
return self._cancelled_runs.copy()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Global cancellation manager instance
|
|
61
|
+
_cancellation_manager = RunCancellationManager()
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def register_run(run_id: str) -> None:
|
|
65
|
+
"""Register a new run for cancellation tracking."""
|
|
66
|
+
_cancellation_manager.register_run(run_id)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def cancel_run(run_id: str) -> bool:
|
|
70
|
+
"""Cancel a run."""
|
|
71
|
+
return _cancellation_manager.cancel_run(run_id)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def cleanup_run(run_id: str) -> None:
|
|
75
|
+
"""Clean up cancellation tracking for a completed run."""
|
|
76
|
+
_cancellation_manager.cleanup_run(run_id)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def raise_if_cancelled(run_id: str) -> None:
|
|
80
|
+
"""Check if a run should be cancelled and raise exception if so."""
|
|
81
|
+
_cancellation_manager.raise_if_cancelled(run_id)
|
agno/run/requirement.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
4
|
+
from uuid import uuid4
|
|
5
|
+
|
|
6
|
+
from agno.models.response import ToolExecution, UserInputField
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class RunRequirement:
|
|
14
|
+
"""Requirement to complete a paused run (used in HITL flows)"""
|
|
15
|
+
|
|
16
|
+
tool_execution: Optional[ToolExecution] = None
|
|
17
|
+
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
|
18
|
+
|
|
19
|
+
# User confirmation
|
|
20
|
+
confirmation: Optional[bool] = None
|
|
21
|
+
confirmation_note: Optional[str] = None
|
|
22
|
+
|
|
23
|
+
# User input
|
|
24
|
+
user_input_schema: Optional[List[UserInputField]] = None
|
|
25
|
+
|
|
26
|
+
# External execution
|
|
27
|
+
external_execution_result: Optional[str] = None
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
tool_execution: ToolExecution,
|
|
32
|
+
id: Optional[str] = None,
|
|
33
|
+
created_at: Optional[datetime] = None,
|
|
34
|
+
):
|
|
35
|
+
self.id = id or str(uuid4())
|
|
36
|
+
self.tool_execution = tool_execution
|
|
37
|
+
self.user_input_schema = tool_execution.user_input_schema if tool_execution else None
|
|
38
|
+
self.created_at = created_at or datetime.now(timezone.utc)
|
|
39
|
+
self.confirmation = None
|
|
40
|
+
self.confirmation_note = None
|
|
41
|
+
self.external_execution_result = None
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def needs_confirmation(self) -> bool:
|
|
45
|
+
if self.confirmation is not None:
|
|
46
|
+
return False
|
|
47
|
+
if not self.tool_execution:
|
|
48
|
+
return False
|
|
49
|
+
if self.tool_execution.confirmed is True:
|
|
50
|
+
return True
|
|
51
|
+
|
|
52
|
+
return self.tool_execution.requires_confirmation or False
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def needs_user_input(self) -> bool:
|
|
56
|
+
if not self.tool_execution:
|
|
57
|
+
return False
|
|
58
|
+
if self.tool_execution.answered is True:
|
|
59
|
+
return False
|
|
60
|
+
if self.user_input_schema and not all(field.value is not None for field in self.user_input_schema):
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
return self.tool_execution.requires_user_input or False
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def needs_external_execution(self) -> bool:
|
|
67
|
+
if not self.tool_execution:
|
|
68
|
+
return False
|
|
69
|
+
if self.external_execution_result is not None:
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
return self.tool_execution.external_execution_required or False
|
|
73
|
+
|
|
74
|
+
def confirm(self):
|
|
75
|
+
if not self.needs_confirmation:
|
|
76
|
+
raise ValueError("This requirement does not require confirmation")
|
|
77
|
+
self.confirmation = True
|
|
78
|
+
if self.tool_execution:
|
|
79
|
+
self.tool_execution.confirmed = True
|
|
80
|
+
|
|
81
|
+
def reject(self):
|
|
82
|
+
if not self.needs_confirmation:
|
|
83
|
+
raise ValueError("This requirement does not require confirmation")
|
|
84
|
+
self.confirmation = False
|
|
85
|
+
if self.tool_execution:
|
|
86
|
+
self.tool_execution.confirmed = False
|
|
87
|
+
|
|
88
|
+
def set_external_execution_result(self, result: str):
|
|
89
|
+
if not self.needs_external_execution:
|
|
90
|
+
raise ValueError("This requirement does not require external execution")
|
|
91
|
+
self.external_execution_result = result
|
|
92
|
+
if self.tool_execution:
|
|
93
|
+
self.tool_execution.result = result
|
|
94
|
+
|
|
95
|
+
def update_tool(self):
|
|
96
|
+
if not self.tool_execution:
|
|
97
|
+
return
|
|
98
|
+
if self.confirmation is True:
|
|
99
|
+
self.tool_execution.confirmed = True
|
|
100
|
+
elif self.confirmation is False:
|
|
101
|
+
self.tool_execution.confirmed = False
|
|
102
|
+
else:
|
|
103
|
+
raise ValueError("This requirement does not require confirmation or user input")
|
|
104
|
+
|
|
105
|
+
def is_resolved(self) -> bool:
|
|
106
|
+
"""Return True if the requirement has been resolved"""
|
|
107
|
+
return not self.needs_confirmation and not self.needs_user_input and not self.needs_external_execution
|
|
108
|
+
|
|
109
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
110
|
+
"""Convert to JSON-serializable dictionary for storage."""
|
|
111
|
+
_dict: Dict[str, Any] = {
|
|
112
|
+
"id": self.id,
|
|
113
|
+
"created_at": self.created_at.isoformat() if isinstance(self.created_at, datetime) else self.created_at,
|
|
114
|
+
"confirmation": self.confirmation,
|
|
115
|
+
"confirmation_note": self.confirmation_note,
|
|
116
|
+
"external_execution_result": self.external_execution_result,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if self.tool_execution is not None:
|
|
120
|
+
_dict["tool_execution"] = (
|
|
121
|
+
self.tool_execution.to_dict() if isinstance(self.tool_execution, ToolExecution) else self.tool_execution
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if self.user_input_schema is not None:
|
|
125
|
+
_dict["user_input_schema"] = [f.to_dict() if hasattr(f, "to_dict") else f for f in self.user_input_schema]
|
|
126
|
+
|
|
127
|
+
return {k: v for k, v in _dict.items() if v is not None}
|
|
128
|
+
|
|
129
|
+
@classmethod
|
|
130
|
+
def from_dict(cls, data: Dict[str, Any]) -> "RunRequirement":
|
|
131
|
+
"""Reconstruct from stored dictionary."""
|
|
132
|
+
if data is None:
|
|
133
|
+
raise ValueError("RunRequirement.from_dict() requires a non-None dict")
|
|
134
|
+
|
|
135
|
+
# Handle tool_execution
|
|
136
|
+
tool_data = data.get("tool_execution")
|
|
137
|
+
tool_execution: Optional[ToolExecution] = None
|
|
138
|
+
if isinstance(tool_data, ToolExecution):
|
|
139
|
+
tool_execution = tool_data
|
|
140
|
+
elif isinstance(tool_data, dict):
|
|
141
|
+
tool_execution = ToolExecution.from_dict(tool_data)
|
|
142
|
+
|
|
143
|
+
# Handle created_at (ISO string or datetime)
|
|
144
|
+
created_at_raw = data.get("created_at")
|
|
145
|
+
created_at: Optional[datetime] = None
|
|
146
|
+
if isinstance(created_at_raw, datetime):
|
|
147
|
+
created_at = created_at_raw
|
|
148
|
+
elif isinstance(created_at_raw, str):
|
|
149
|
+
try:
|
|
150
|
+
created_at = datetime.fromisoformat(created_at_raw)
|
|
151
|
+
except ValueError:
|
|
152
|
+
created_at = None
|
|
153
|
+
|
|
154
|
+
# Build requirement - tool_execution is required by __init__
|
|
155
|
+
# For legacy data without tool_execution, create a minimal placeholder
|
|
156
|
+
if tool_execution is None:
|
|
157
|
+
tool_execution = ToolExecution(tool_name="unknown", tool_args={})
|
|
158
|
+
|
|
159
|
+
requirement = cls(
|
|
160
|
+
tool_execution=tool_execution,
|
|
161
|
+
id=data.get("id"),
|
|
162
|
+
created_at=created_at,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Set optional fields
|
|
166
|
+
requirement.confirmation = data.get("confirmation")
|
|
167
|
+
requirement.confirmation_note = data.get("confirmation_note")
|
|
168
|
+
requirement.external_execution_result = data.get("external_execution_result")
|
|
169
|
+
|
|
170
|
+
# Handle user_input_schema
|
|
171
|
+
schema_raw = data.get("user_input_schema")
|
|
172
|
+
if schema_raw is not None:
|
|
173
|
+
rebuilt_schema: List[UserInputField] = []
|
|
174
|
+
for item in schema_raw:
|
|
175
|
+
if isinstance(item, UserInputField):
|
|
176
|
+
rebuilt_schema.append(item)
|
|
177
|
+
elif isinstance(item, dict):
|
|
178
|
+
rebuilt_schema.append(UserInputField.from_dict(item))
|
|
179
|
+
requirement.user_input_schema = rebuilt_schema if rebuilt_schema else None
|
|
180
|
+
|
|
181
|
+
return requirement
|