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/workflow/types.py
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
5
|
+
|
|
6
|
+
from fastapi import WebSocket
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
from agno.media import Audio, File, Image, Video
|
|
10
|
+
from agno.models.metrics import Metrics
|
|
11
|
+
from agno.session.workflow import WorkflowSession
|
|
12
|
+
from agno.utils.log import log_warning
|
|
13
|
+
from agno.utils.media import (
|
|
14
|
+
reconstruct_audio_list,
|
|
15
|
+
reconstruct_files,
|
|
16
|
+
reconstruct_images,
|
|
17
|
+
reconstruct_videos,
|
|
18
|
+
)
|
|
19
|
+
from agno.utils.serialize import json_serializer
|
|
20
|
+
from agno.utils.timer import Timer
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class WorkflowExecutionInput:
|
|
25
|
+
"""Input data for a step execution"""
|
|
26
|
+
|
|
27
|
+
input: Optional[Union[str, Dict[str, Any], List[Any], BaseModel]] = None
|
|
28
|
+
|
|
29
|
+
additional_data: Optional[Dict[str, Any]] = None
|
|
30
|
+
|
|
31
|
+
# Media inputs
|
|
32
|
+
images: Optional[List[Image]] = None
|
|
33
|
+
videos: Optional[List[Video]] = None
|
|
34
|
+
audio: Optional[List[Audio]] = None
|
|
35
|
+
files: Optional[List[File]] = None
|
|
36
|
+
|
|
37
|
+
def get_input_as_string(self) -> Optional[str]:
|
|
38
|
+
"""Convert input to string representation"""
|
|
39
|
+
if self.input is None:
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
if isinstance(self.input, str):
|
|
43
|
+
return self.input
|
|
44
|
+
elif isinstance(self.input, BaseModel):
|
|
45
|
+
return self.input.model_dump_json(indent=2, exclude_none=True)
|
|
46
|
+
elif isinstance(self.input, (dict, list)):
|
|
47
|
+
import json
|
|
48
|
+
|
|
49
|
+
return json.dumps(self.input, indent=2, default=str)
|
|
50
|
+
else:
|
|
51
|
+
return str(self.input)
|
|
52
|
+
|
|
53
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
54
|
+
"""Convert to dictionary"""
|
|
55
|
+
input_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
|
|
56
|
+
if self.input is not None:
|
|
57
|
+
if isinstance(self.input, BaseModel):
|
|
58
|
+
input_dict = self.input.model_dump(exclude_none=True)
|
|
59
|
+
elif isinstance(self.input, (dict, list)):
|
|
60
|
+
input_dict = self.input
|
|
61
|
+
else:
|
|
62
|
+
input_dict = str(self.input)
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
"input": input_dict,
|
|
66
|
+
"additional_data": self.additional_data,
|
|
67
|
+
"images": [img.to_dict() for img in self.images] if self.images else None,
|
|
68
|
+
"videos": [vid.to_dict() for vid in self.videos] if self.videos else None,
|
|
69
|
+
"audio": [aud.to_dict() for aud in self.audio] if self.audio else None,
|
|
70
|
+
"files": [file.to_dict() for file in self.files] if self.files else None,
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass
|
|
75
|
+
class StepInput:
|
|
76
|
+
"""Input data for a step execution"""
|
|
77
|
+
|
|
78
|
+
input: Optional[Union[str, Dict[str, Any], List[Any], BaseModel]] = None
|
|
79
|
+
|
|
80
|
+
previous_step_content: Optional[Any] = None
|
|
81
|
+
previous_step_outputs: Optional[Dict[str, "StepOutput"]] = None
|
|
82
|
+
|
|
83
|
+
additional_data: Optional[Dict[str, Any]] = None
|
|
84
|
+
|
|
85
|
+
# Media inputs
|
|
86
|
+
images: Optional[List[Image]] = None
|
|
87
|
+
videos: Optional[List[Video]] = None
|
|
88
|
+
audio: Optional[List[Audio]] = None
|
|
89
|
+
files: Optional[List[File]] = None
|
|
90
|
+
|
|
91
|
+
workflow_session: Optional["WorkflowSession"] = None
|
|
92
|
+
|
|
93
|
+
def get_input_as_string(self) -> Optional[str]:
|
|
94
|
+
"""Convert input to string representation"""
|
|
95
|
+
if self.input is None:
|
|
96
|
+
return None
|
|
97
|
+
|
|
98
|
+
if isinstance(self.input, str):
|
|
99
|
+
return self.input
|
|
100
|
+
elif isinstance(self.input, BaseModel):
|
|
101
|
+
return self.input.model_dump_json(indent=2, exclude_none=True)
|
|
102
|
+
elif isinstance(self.input, (dict, list)):
|
|
103
|
+
import json
|
|
104
|
+
|
|
105
|
+
return json.dumps(self.input, indent=2, default=str)
|
|
106
|
+
else:
|
|
107
|
+
return str(self.input)
|
|
108
|
+
|
|
109
|
+
def get_step_output(self, step_name: str) -> Optional["StepOutput"]:
|
|
110
|
+
"""Get output from a specific previous step by name
|
|
111
|
+
|
|
112
|
+
Searches recursively through nested steps (Parallel, Condition, Router, Loop, Steps)
|
|
113
|
+
to find step outputs at any depth.
|
|
114
|
+
"""
|
|
115
|
+
if not self.previous_step_outputs:
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
# First try direct lookup
|
|
119
|
+
direct = self.previous_step_outputs.get(step_name)
|
|
120
|
+
if direct:
|
|
121
|
+
return direct
|
|
122
|
+
|
|
123
|
+
# Search recursively in nested steps
|
|
124
|
+
return self._search_nested_steps(step_name)
|
|
125
|
+
|
|
126
|
+
def _search_nested_steps(self, step_name: str) -> Optional["StepOutput"]:
|
|
127
|
+
"""Recursively search for a step output in nested steps (Parallel, Condition, etc.)"""
|
|
128
|
+
if not self.previous_step_outputs:
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
for step_output in self.previous_step_outputs.values():
|
|
132
|
+
result = self._search_in_step_output(step_output, step_name)
|
|
133
|
+
if result:
|
|
134
|
+
return result
|
|
135
|
+
return None
|
|
136
|
+
|
|
137
|
+
def _search_in_step_output(self, step_output: "StepOutput", step_name: str) -> Optional["StepOutput"]:
|
|
138
|
+
"""Helper to recursively search within a single StepOutput"""
|
|
139
|
+
if not step_output.steps:
|
|
140
|
+
return None
|
|
141
|
+
|
|
142
|
+
for nested_step in step_output.steps:
|
|
143
|
+
if nested_step.step_name == step_name:
|
|
144
|
+
return nested_step
|
|
145
|
+
# Recursively search deeper
|
|
146
|
+
result = self._search_in_step_output(nested_step, step_name)
|
|
147
|
+
if result:
|
|
148
|
+
return result
|
|
149
|
+
return None
|
|
150
|
+
|
|
151
|
+
def get_step_content(self, step_name: str) -> Optional[Union[str, Dict[str, str]]]:
|
|
152
|
+
"""Get content from a specific previous step by name
|
|
153
|
+
|
|
154
|
+
For parallel steps, if you ask for the parallel step name, returns a dict
|
|
155
|
+
with {step_name: content} for each sub-step.
|
|
156
|
+
For other nested steps (Condition, Router, Loop, Steps), returns the deepest content.
|
|
157
|
+
"""
|
|
158
|
+
step_output = self.get_step_output(step_name)
|
|
159
|
+
if not step_output:
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
# Check if this is a parallel step with nested steps
|
|
163
|
+
if step_output.step_type == "Parallel" and step_output.steps:
|
|
164
|
+
# Return dict with {step_name: content} for each sub-step
|
|
165
|
+
parallel_content = {}
|
|
166
|
+
for sub_step in step_output.steps:
|
|
167
|
+
if sub_step.step_name and sub_step.content:
|
|
168
|
+
# Check if this sub-step has its own nested steps (like Condition -> Research Step)
|
|
169
|
+
if sub_step.steps and len(sub_step.steps) > 0:
|
|
170
|
+
# This is a composite step (like Condition) - get content from its nested steps
|
|
171
|
+
for nested_step in sub_step.steps:
|
|
172
|
+
if nested_step.step_name and nested_step.content:
|
|
173
|
+
parallel_content[nested_step.step_name] = str(nested_step.content)
|
|
174
|
+
else:
|
|
175
|
+
# This is a direct step - use its content
|
|
176
|
+
parallel_content[sub_step.step_name] = str(sub_step.content)
|
|
177
|
+
return parallel_content if parallel_content else str(step_output.content)
|
|
178
|
+
|
|
179
|
+
# For other nested step types (Condition, Router, Loop, Steps), get the deepest content
|
|
180
|
+
elif step_output.steps and len(step_output.steps) > 0:
|
|
181
|
+
# This is a nested step structure - recursively get the deepest content
|
|
182
|
+
return self._get_deepest_step_content(step_output.steps[-1])
|
|
183
|
+
|
|
184
|
+
# Regular step, return content directly
|
|
185
|
+
return step_output.content # type: ignore[return-value]
|
|
186
|
+
|
|
187
|
+
def _get_deepest_step_content(self, step_output: "StepOutput") -> Optional[Union[str, Dict[str, str]]]:
|
|
188
|
+
"""Helper method to recursively extract deepest content from nested steps"""
|
|
189
|
+
# If this step has nested steps, go deeper
|
|
190
|
+
if step_output.steps and len(step_output.steps) > 0:
|
|
191
|
+
return self._get_deepest_step_content(step_output.steps[-1])
|
|
192
|
+
|
|
193
|
+
# Return the content of this step
|
|
194
|
+
return step_output.content # type: ignore[return-value]
|
|
195
|
+
|
|
196
|
+
def get_all_previous_content(self) -> str:
|
|
197
|
+
"""Get concatenated content from all previous steps"""
|
|
198
|
+
if not self.previous_step_outputs:
|
|
199
|
+
return ""
|
|
200
|
+
|
|
201
|
+
content_parts = []
|
|
202
|
+
for step_name, output in self.previous_step_outputs.items():
|
|
203
|
+
if output.content:
|
|
204
|
+
content_parts.append(f"=== {step_name} ===\n{output.content}")
|
|
205
|
+
|
|
206
|
+
return "\n\n".join(content_parts)
|
|
207
|
+
|
|
208
|
+
def get_last_step_content(self) -> Optional[str]:
|
|
209
|
+
"""Get content from the most recent step (for backward compatibility)"""
|
|
210
|
+
if not self.previous_step_outputs:
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
last_output = list(self.previous_step_outputs.values())[-1] if self.previous_step_outputs else None
|
|
214
|
+
if not last_output:
|
|
215
|
+
return None
|
|
216
|
+
|
|
217
|
+
# Use the helper method to get the deepest content
|
|
218
|
+
return self._get_deepest_step_content(last_output) # type: ignore[return-value]
|
|
219
|
+
|
|
220
|
+
def get_workflow_history(self, num_runs: Optional[int] = None) -> List[Tuple[str, str]]:
|
|
221
|
+
"""Get workflow conversation history as structured data for custom function steps
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
num_runs: Number of recent runs to include. If None, returns all available history.
|
|
225
|
+
"""
|
|
226
|
+
if not self.workflow_session:
|
|
227
|
+
return []
|
|
228
|
+
|
|
229
|
+
return self.workflow_session.get_workflow_history(num_runs=num_runs)
|
|
230
|
+
|
|
231
|
+
def get_workflow_history_context(self, num_runs: Optional[int] = None) -> Optional[str]:
|
|
232
|
+
"""Get formatted workflow conversation history context for custom function steps
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
num_runs: Number of recent runs to include. If None, returns all available history.
|
|
236
|
+
"""
|
|
237
|
+
if not self.workflow_session:
|
|
238
|
+
return None
|
|
239
|
+
|
|
240
|
+
return self.workflow_session.get_workflow_history_context(num_runs=num_runs)
|
|
241
|
+
|
|
242
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
243
|
+
"""Convert to dictionary"""
|
|
244
|
+
# Handle the unified message field
|
|
245
|
+
input_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
|
|
246
|
+
if self.input is not None:
|
|
247
|
+
if isinstance(self.input, BaseModel):
|
|
248
|
+
input_dict = self.input.model_dump(exclude_none=True, mode="json")
|
|
249
|
+
elif isinstance(self.input, (dict, list)):
|
|
250
|
+
input_dict = self.input
|
|
251
|
+
else:
|
|
252
|
+
input_dict = str(self.input)
|
|
253
|
+
|
|
254
|
+
previous_step_content_str: Optional[str] = None
|
|
255
|
+
# Handle previous_step_content (keep existing logic)
|
|
256
|
+
if isinstance(self.previous_step_content, BaseModel):
|
|
257
|
+
previous_step_content_str = self.previous_step_content.model_dump_json(indent=2, exclude_none=True)
|
|
258
|
+
elif isinstance(self.previous_step_content, dict):
|
|
259
|
+
import json
|
|
260
|
+
|
|
261
|
+
previous_step_content_str = json.dumps(self.previous_step_content, indent=2, default=str)
|
|
262
|
+
elif self.previous_step_content:
|
|
263
|
+
previous_step_content_str = str(self.previous_step_content)
|
|
264
|
+
|
|
265
|
+
# Convert previous_step_outputs to serializable format (keep existing logic)
|
|
266
|
+
previous_steps_dict = {}
|
|
267
|
+
if self.previous_step_outputs:
|
|
268
|
+
for step_name, output in self.previous_step_outputs.items():
|
|
269
|
+
previous_steps_dict[step_name] = output.to_dict()
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
"input": input_dict,
|
|
273
|
+
"previous_step_outputs": previous_steps_dict,
|
|
274
|
+
"previous_step_content": previous_step_content_str,
|
|
275
|
+
"additional_data": self.additional_data,
|
|
276
|
+
"images": [img.to_dict() for img in self.images] if self.images else None,
|
|
277
|
+
"videos": [vid.to_dict() for vid in self.videos] if self.videos else None,
|
|
278
|
+
"audio": [aud.to_dict() for aud in self.audio] if self.audio else None,
|
|
279
|
+
"files": [file for file in self.files] if self.files else None,
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
@dataclass
|
|
284
|
+
class StepOutput:
|
|
285
|
+
"""Output data from a step execution"""
|
|
286
|
+
|
|
287
|
+
step_name: Optional[str] = None
|
|
288
|
+
step_id: Optional[str] = None
|
|
289
|
+
step_type: Optional[str] = None
|
|
290
|
+
executor_type: Optional[str] = None
|
|
291
|
+
executor_name: Optional[str] = None
|
|
292
|
+
# Primary output
|
|
293
|
+
content: Optional[Union[str, Dict[str, Any], List[Any], BaseModel, Any]] = None
|
|
294
|
+
|
|
295
|
+
# Link to the run ID of the step execution
|
|
296
|
+
step_run_id: Optional[str] = None
|
|
297
|
+
|
|
298
|
+
# Media outputs
|
|
299
|
+
images: Optional[List[Image]] = None
|
|
300
|
+
videos: Optional[List[Video]] = None
|
|
301
|
+
audio: Optional[List[Audio]] = None
|
|
302
|
+
files: Optional[List[File]] = None
|
|
303
|
+
|
|
304
|
+
# Metrics for this step execution
|
|
305
|
+
metrics: Optional[Metrics] = None
|
|
306
|
+
|
|
307
|
+
success: bool = True
|
|
308
|
+
error: Optional[str] = None
|
|
309
|
+
|
|
310
|
+
stop: bool = False
|
|
311
|
+
|
|
312
|
+
steps: Optional[List["StepOutput"]] = None
|
|
313
|
+
|
|
314
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
315
|
+
"""Convert to dictionary"""
|
|
316
|
+
# Handle the unified content field
|
|
317
|
+
content_dict: Optional[Union[str, Dict[str, Any], List[Any]]] = None
|
|
318
|
+
if self.content is not None:
|
|
319
|
+
if isinstance(self.content, BaseModel):
|
|
320
|
+
content_dict = self.content.model_dump(exclude_none=True, mode="json")
|
|
321
|
+
elif isinstance(self.content, (dict, list)):
|
|
322
|
+
content_dict = self.content
|
|
323
|
+
else:
|
|
324
|
+
content_dict = str(self.content)
|
|
325
|
+
|
|
326
|
+
result = {
|
|
327
|
+
"content": content_dict,
|
|
328
|
+
"step_name": self.step_name,
|
|
329
|
+
"step_id": self.step_id,
|
|
330
|
+
"step_type": self.step_type,
|
|
331
|
+
"executor_type": self.executor_type,
|
|
332
|
+
"executor_name": self.executor_name,
|
|
333
|
+
"step_run_id": self.step_run_id,
|
|
334
|
+
"images": [img.to_dict() for img in self.images] if self.images else None,
|
|
335
|
+
"videos": [vid.to_dict() for vid in self.videos] if self.videos else None,
|
|
336
|
+
"audio": [aud.to_dict() for aud in self.audio] if self.audio else None,
|
|
337
|
+
"metrics": self.metrics.to_dict() if self.metrics else None,
|
|
338
|
+
"success": self.success,
|
|
339
|
+
"error": self.error,
|
|
340
|
+
"stop": self.stop,
|
|
341
|
+
"files": [file for file in self.files] if self.files else None,
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
# Add nested steps if they exist
|
|
345
|
+
if self.steps:
|
|
346
|
+
result["steps"] = [step.to_dict() for step in self.steps]
|
|
347
|
+
|
|
348
|
+
return result
|
|
349
|
+
|
|
350
|
+
@classmethod
|
|
351
|
+
def from_dict(cls, data: Dict[str, Any]) -> "StepOutput":
|
|
352
|
+
"""Create StepOutput from dictionary"""
|
|
353
|
+
# Reconstruct media artifacts
|
|
354
|
+
images = reconstruct_images(data.get("images"))
|
|
355
|
+
videos = reconstruct_videos(data.get("videos"))
|
|
356
|
+
audio = reconstruct_audio_list(data.get("audio"))
|
|
357
|
+
files = reconstruct_files(data.get("files"))
|
|
358
|
+
|
|
359
|
+
metrics_data = data.get("metrics")
|
|
360
|
+
metrics = None
|
|
361
|
+
if metrics_data:
|
|
362
|
+
if isinstance(metrics_data, dict):
|
|
363
|
+
# Convert dict to Metrics object
|
|
364
|
+
from agno.models.metrics import Metrics
|
|
365
|
+
|
|
366
|
+
metrics = Metrics(**metrics_data)
|
|
367
|
+
else:
|
|
368
|
+
# Already a Metrics object
|
|
369
|
+
metrics = metrics_data
|
|
370
|
+
|
|
371
|
+
# Handle nested steps
|
|
372
|
+
steps_data = data.get("steps")
|
|
373
|
+
steps = None
|
|
374
|
+
if steps_data:
|
|
375
|
+
steps = [cls.from_dict(step_data) for step_data in steps_data]
|
|
376
|
+
|
|
377
|
+
return cls(
|
|
378
|
+
step_name=data.get("step_name"),
|
|
379
|
+
step_id=data.get("step_id"),
|
|
380
|
+
step_type=data.get("step_type"),
|
|
381
|
+
executor_type=data.get("executor_type"),
|
|
382
|
+
executor_name=data.get("executor_name"),
|
|
383
|
+
content=data.get("content"),
|
|
384
|
+
step_run_id=data.get("step_run_id"),
|
|
385
|
+
images=images,
|
|
386
|
+
videos=videos,
|
|
387
|
+
audio=audio,
|
|
388
|
+
files=files,
|
|
389
|
+
metrics=metrics,
|
|
390
|
+
success=data.get("success", True),
|
|
391
|
+
error=data.get("error"),
|
|
392
|
+
stop=data.get("stop", False),
|
|
393
|
+
steps=steps,
|
|
394
|
+
)
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
@dataclass
|
|
398
|
+
class StepMetrics:
|
|
399
|
+
"""Metrics for a single step execution"""
|
|
400
|
+
|
|
401
|
+
step_name: str
|
|
402
|
+
executor_type: str # "agent", "team", etc.
|
|
403
|
+
executor_name: str
|
|
404
|
+
metrics: Optional[Metrics] = None
|
|
405
|
+
|
|
406
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
407
|
+
"""Convert to dictionary"""
|
|
408
|
+
return {
|
|
409
|
+
"step_name": self.step_name,
|
|
410
|
+
"executor_type": self.executor_type,
|
|
411
|
+
"executor_name": self.executor_name,
|
|
412
|
+
"metrics": self.metrics.to_dict() if self.metrics else None,
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
@classmethod
|
|
416
|
+
def from_dict(cls, data: Dict[str, Any]) -> "StepMetrics":
|
|
417
|
+
"""Create StepMetrics from dictionary"""
|
|
418
|
+
|
|
419
|
+
# Handle metrics properly
|
|
420
|
+
metrics_data = data.get("metrics")
|
|
421
|
+
metrics = None
|
|
422
|
+
if metrics_data:
|
|
423
|
+
if isinstance(metrics_data, dict):
|
|
424
|
+
# Convert dict to Metrics object
|
|
425
|
+
from agno.models.metrics import Metrics
|
|
426
|
+
|
|
427
|
+
metrics = Metrics(**metrics_data)
|
|
428
|
+
else:
|
|
429
|
+
# Already a Metrics object
|
|
430
|
+
metrics = metrics_data
|
|
431
|
+
|
|
432
|
+
return cls(
|
|
433
|
+
step_name=data["step_name"],
|
|
434
|
+
executor_type=data["executor_type"],
|
|
435
|
+
executor_name=data["executor_name"],
|
|
436
|
+
metrics=metrics,
|
|
437
|
+
)
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
@dataclass
|
|
441
|
+
class WorkflowMetrics:
|
|
442
|
+
"""Complete metrics for a workflow execution"""
|
|
443
|
+
|
|
444
|
+
steps: Dict[str, StepMetrics]
|
|
445
|
+
# Timer utility for tracking execution time
|
|
446
|
+
timer: Optional[Timer] = None
|
|
447
|
+
# Total workflow execution time
|
|
448
|
+
duration: Optional[float] = None
|
|
449
|
+
|
|
450
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
451
|
+
"""Convert to dictionary"""
|
|
452
|
+
result: Dict[str, Any] = {
|
|
453
|
+
"steps": {name: step.to_dict() for name, step in self.steps.items()},
|
|
454
|
+
"duration": self.duration,
|
|
455
|
+
}
|
|
456
|
+
return result
|
|
457
|
+
|
|
458
|
+
@classmethod
|
|
459
|
+
def from_dict(cls, data: Dict[str, Any]) -> "WorkflowMetrics":
|
|
460
|
+
"""Create WorkflowMetrics from dictionary"""
|
|
461
|
+
steps = {name: StepMetrics.from_dict(step_data) for name, step_data in data["steps"].items()}
|
|
462
|
+
|
|
463
|
+
return cls(
|
|
464
|
+
steps=steps,
|
|
465
|
+
duration=data.get("duration"),
|
|
466
|
+
)
|
|
467
|
+
|
|
468
|
+
def start_timer(self):
|
|
469
|
+
if self.timer is None:
|
|
470
|
+
self.timer = Timer()
|
|
471
|
+
self.timer.start()
|
|
472
|
+
|
|
473
|
+
def stop_timer(self, set_duration: bool = True):
|
|
474
|
+
if self.timer is not None:
|
|
475
|
+
self.timer.stop()
|
|
476
|
+
if set_duration:
|
|
477
|
+
self.duration = self.timer.elapsed
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
@dataclass
|
|
481
|
+
class WebSocketHandler:
|
|
482
|
+
"""Generic WebSocket handler for real-time workflow events"""
|
|
483
|
+
|
|
484
|
+
websocket: Optional[WebSocket] = None
|
|
485
|
+
|
|
486
|
+
def format_sse_event(self, json_data: str) -> str:
|
|
487
|
+
"""Parse JSON data into SSE-compliant format.
|
|
488
|
+
|
|
489
|
+
Args:
|
|
490
|
+
json_data: JSON string containing the event data
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
SSE-formatted response with event type and data
|
|
494
|
+
"""
|
|
495
|
+
import json
|
|
496
|
+
|
|
497
|
+
try:
|
|
498
|
+
# Parse the JSON to extract the event type
|
|
499
|
+
data = json.loads(json_data)
|
|
500
|
+
event_type = data.get("event", "message")
|
|
501
|
+
|
|
502
|
+
# Format as SSE: event: <event_type>\ndata: <json_data>\n\n
|
|
503
|
+
return f"event: {event_type}\ndata: {json_data}\n\n"
|
|
504
|
+
except (json.JSONDecodeError, KeyError):
|
|
505
|
+
# Fallback to generic message event if parsing fails
|
|
506
|
+
return f"event: message\ndata: {json_data}\n\n"
|
|
507
|
+
|
|
508
|
+
async def handle_event(self, event: Any) -> None:
|
|
509
|
+
"""Handle an event object - serializes and sends via WebSocket"""
|
|
510
|
+
if not self.websocket:
|
|
511
|
+
return
|
|
512
|
+
|
|
513
|
+
try:
|
|
514
|
+
if hasattr(event, "to_dict"):
|
|
515
|
+
data = event.to_dict()
|
|
516
|
+
elif hasattr(event, "__dict__"):
|
|
517
|
+
data = event.__dict__
|
|
518
|
+
elif isinstance(event, dict):
|
|
519
|
+
data = event
|
|
520
|
+
else:
|
|
521
|
+
data = {"type": "message", "content": str(event)}
|
|
522
|
+
|
|
523
|
+
await self.websocket.send_text(self.format_sse_event(json.dumps(data, default=json_serializer)))
|
|
524
|
+
|
|
525
|
+
except Exception as e:
|
|
526
|
+
log_warning(f"Failed to handle WebSocket event: {e}")
|
|
527
|
+
|
|
528
|
+
async def handle_text(self, message: str) -> None:
|
|
529
|
+
"""Handle a plain text message"""
|
|
530
|
+
if not self.websocket:
|
|
531
|
+
return
|
|
532
|
+
|
|
533
|
+
try:
|
|
534
|
+
await self.websocket.send_text(self.format_sse_event(message))
|
|
535
|
+
except Exception as e:
|
|
536
|
+
log_warning(f"Failed to send WebSocket text: {e}")
|
|
537
|
+
|
|
538
|
+
async def handle_dict(self, data: Dict[str, Any]) -> None:
|
|
539
|
+
"""Handle a dictionary directly"""
|
|
540
|
+
if not self.websocket:
|
|
541
|
+
return
|
|
542
|
+
|
|
543
|
+
try:
|
|
544
|
+
await self.websocket.send_text(self.format_sse_event(json.dumps(data, default=json_serializer)))
|
|
545
|
+
except Exception as e:
|
|
546
|
+
log_warning(f"Failed to send WebSocket dict: {e}")
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
class StepType(str, Enum):
|
|
550
|
+
FUNCTION = "Function"
|
|
551
|
+
STEP = "Step"
|
|
552
|
+
STEPS = "Steps"
|
|
553
|
+
LOOP = "Loop"
|
|
554
|
+
PARALLEL = "Parallel"
|
|
555
|
+
CONDITION = "Condition"
|
|
556
|
+
ROUTER = "Router"
|