agno 1.8.1__py3-none-any.whl → 2.0.0rc1__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 +19 -27
- agno/agent/agent.py +3181 -4169
- agno/api/agent.py +11 -67
- agno/api/api.py +5 -46
- agno/api/evals.py +8 -19
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -41
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +5 -21
- agno/api/schemas/evals.py +7 -16
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +5 -21
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +11 -7
- agno/api/settings.py +53 -0
- agno/api/team.py +11 -66
- 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/db/__init__.py +24 -0
- agno/db/base.py +245 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +1743 -0
- agno/db/dynamo/schemas.py +278 -0
- agno/db/dynamo/utils.py +684 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +1432 -0
- agno/db/firestore/schemas.py +130 -0
- agno/db/firestore/utils.py +278 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1001 -0
- agno/db/gcs_json/utils.py +194 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +882 -0
- agno/db/in_memory/utils.py +172 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1045 -0
- agno/db/json/utils.py +196 -0
- agno/db/migrations/v1_to_v2.py +162 -0
- agno/db/mongo/__init__.py +3 -0
- agno/db/mongo/mongo.py +1411 -0
- agno/db/mongo/schemas.py +77 -0
- agno/db/mongo/utils.py +204 -0
- agno/db/mysql/__init__.py +3 -0
- agno/db/mysql/mysql.py +1719 -0
- agno/db/mysql/schemas.py +124 -0
- agno/db/mysql/utils.py +297 -0
- agno/db/postgres/__init__.py +3 -0
- agno/db/postgres/postgres.py +1710 -0
- agno/db/postgres/schemas.py +124 -0
- agno/db/postgres/utils.py +280 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +1367 -0
- agno/db/redis/schemas.py +109 -0
- agno/db/redis/utils.py +288 -0
- agno/db/schemas/__init__.py +3 -0
- agno/db/schemas/evals.py +33 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +46 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +116 -0
- agno/db/singlestore/singlestore.py +1712 -0
- agno/db/singlestore/utils.py +326 -0
- agno/db/sqlite/__init__.py +3 -0
- agno/db/sqlite/schemas.py +119 -0
- agno/db/sqlite/sqlite.py +1676 -0
- agno/db/sqlite/utils.py +268 -0
- agno/db/utils.py +88 -0
- agno/eval/__init__.py +14 -0
- agno/eval/accuracy.py +142 -43
- agno/eval/performance.py +88 -23
- agno/eval/reliability.py +73 -20
- agno/eval/utils.py +23 -13
- agno/integrations/discord/__init__.py +3 -0
- agno/{app → integrations}/discord/client.py +15 -11
- agno/knowledge/__init__.py +2 -2
- agno/{document → knowledge}/chunking/agentic.py +2 -2
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +3 -3
- agno/{document → knowledge}/chunking/markdown.py +2 -2
- agno/{document → knowledge}/chunking/recursive.py +2 -2
- agno/{document → knowledge}/chunking/row.py +2 -2
- agno/knowledge/chunking/semantic.py +59 -0
- agno/knowledge/chunking/strategy.py +121 -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/{embedder → knowledge/embedder}/aws_bedrock.py +127 -1
- agno/{embedder → knowledge/embedder}/azure_openai.py +65 -1
- agno/{embedder → knowledge/embedder}/base.py +6 -0
- agno/{embedder → knowledge/embedder}/cohere.py +72 -1
- agno/{embedder → knowledge/embedder}/fastembed.py +17 -1
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/{embedder → knowledge/embedder}/google.py +74 -1
- agno/{embedder → knowledge/embedder}/huggingface.py +36 -2
- agno/{embedder → knowledge/embedder}/jina.py +48 -2
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +139 -0
- agno/{embedder → knowledge/embedder}/nebius.py +1 -1
- agno/{embedder → knowledge/embedder}/ollama.py +54 -3
- agno/knowledge/embedder/openai.py +223 -0
- agno/{embedder → knowledge/embedder}/sentence_transformer.py +16 -1
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/{embedder → knowledge/embedder}/voyageai.py +49 -1
- agno/knowledge/knowledge.py +1515 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/{document → knowledge}/reader/arxiv_reader.py +32 -4
- agno/knowledge/reader/base.py +88 -0
- agno/{document → knowledge}/reader/csv_reader.py +68 -15
- agno/knowledge/reader/docx_reader.py +83 -0
- agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
- agno/knowledge/reader/gcs_reader.py +67 -0
- agno/{document → knowledge}/reader/json_reader.py +30 -9
- agno/{document → knowledge}/reader/markdown_reader.py +36 -9
- agno/{document → knowledge}/reader/pdf_reader.py +79 -21
- agno/knowledge/reader/reader_factory.py +275 -0
- agno/knowledge/reader/s3_reader.py +171 -0
- agno/{document → knowledge}/reader/text_reader.py +31 -10
- agno/knowledge/reader/url_reader.py +84 -0
- agno/knowledge/reader/web_search_reader.py +389 -0
- agno/{document → knowledge}/reader/website_reader.py +37 -10
- agno/knowledge/reader/wikipedia_reader.py +59 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/{reranker → knowledge/reranker}/infinity.py +2 -2
- agno/{reranker → knowledge/reranker}/sentence_transformer.py +2 -2
- agno/knowledge/types.py +30 -0
- agno/knowledge/utils.py +169 -0
- agno/memory/__init__.py +2 -10
- agno/memory/manager.py +1003 -148
- agno/models/aimlapi/__init__.py +2 -2
- agno/models/aimlapi/aimlapi.py +6 -6
- agno/models/anthropic/claude.py +131 -131
- agno/models/aws/bedrock.py +107 -175
- agno/models/aws/claude.py +64 -18
- agno/models/azure/ai_foundry.py +73 -23
- agno/models/base.py +347 -287
- agno/models/cerebras/cerebras.py +84 -27
- agno/models/cohere/chat.py +106 -98
- agno/models/google/gemini.py +100 -42
- agno/models/groq/groq.py +97 -35
- agno/models/huggingface/huggingface.py +92 -27
- agno/models/ibm/watsonx.py +72 -13
- agno/models/litellm/chat.py +85 -13
- agno/models/message.py +45 -150
- agno/models/meta/llama.py +85 -49
- agno/models/metrics.py +120 -0
- agno/models/mistral/mistral.py +90 -21
- agno/models/ollama/__init__.py +0 -2
- agno/models/ollama/chat.py +84 -46
- agno/models/openai/chat.py +121 -23
- agno/models/openai/responses.py +178 -105
- agno/models/perplexity/perplexity.py +26 -2
- agno/models/portkey/portkey.py +0 -7
- agno/models/response.py +14 -8
- agno/models/utils.py +20 -0
- agno/models/vercel/__init__.py +2 -2
- agno/models/vercel/v0.py +1 -1
- agno/models/vllm/__init__.py +2 -2
- agno/models/vllm/vllm.py +3 -3
- agno/models/xai/xai.py +10 -10
- agno/os/__init__.py +3 -0
- agno/os/app.py +489 -0
- agno/os/auth.py +47 -0
- agno/os/config.py +103 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +31 -0
- agno/{app/agui/async_router.py → os/interfaces/agui/router.py} +16 -16
- agno/{app → os/interfaces}/agui/utils.py +77 -33
- agno/os/interfaces/base.py +21 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/{app/slack/async_router.py → os/interfaces/slack/router.py} +3 -5
- agno/os/interfaces/slack/slack.py +32 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/{app/whatsapp/async_router.py → os/interfaces/whatsapp/router.py} +4 -7
- agno/os/interfaces/whatsapp/whatsapp.py +29 -0
- agno/os/mcp.py +255 -0
- agno/os/router.py +869 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +208 -0
- agno/os/routers/evals/schemas.py +142 -0
- agno/os/routers/evals/utils.py +161 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +436 -0
- agno/os/routers/knowledge/schemas.py +118 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +188 -0
- agno/os/routers/memory/schemas.py +58 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +60 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +168 -0
- agno/os/schema.py +892 -0
- agno/{app/playground → os}/settings.py +7 -15
- agno/os/utils.py +270 -0
- agno/reasoning/azure_ai_foundry.py +4 -4
- agno/reasoning/deepseek.py +4 -4
- agno/reasoning/default.py +6 -11
- agno/reasoning/groq.py +4 -4
- agno/reasoning/helpers.py +4 -6
- agno/reasoning/ollama.py +4 -4
- agno/reasoning/openai.py +4 -4
- agno/run/{response.py → agent.py} +231 -74
- agno/run/base.py +44 -58
- agno/run/cancel.py +81 -0
- agno/run/team.py +133 -77
- agno/run/workflow.py +537 -12
- agno/session/__init__.py +10 -0
- agno/session/agent.py +244 -0
- agno/session/summary.py +225 -0
- agno/session/team.py +262 -0
- agno/{storage/session/v2 → session}/workflow.py +47 -24
- agno/team/__init__.py +15 -16
- agno/team/team.py +2960 -4252
- agno/tools/agentql.py +14 -5
- agno/tools/airflow.py +9 -4
- agno/tools/api.py +7 -3
- agno/tools/apify.py +2 -46
- agno/tools/arxiv.py +8 -3
- agno/tools/aws_lambda.py +7 -5
- agno/tools/aws_ses.py +7 -1
- agno/tools/baidusearch.py +4 -1
- agno/tools/bitbucket.py +4 -4
- agno/tools/brandfetch.py +14 -11
- agno/tools/bravesearch.py +4 -1
- agno/tools/brightdata.py +42 -22
- agno/tools/browserbase.py +13 -4
- agno/tools/calcom.py +12 -10
- agno/tools/calculator.py +10 -27
- agno/tools/cartesia.py +18 -13
- agno/tools/{clickup_tool.py → clickup.py} +12 -25
- agno/tools/confluence.py +8 -8
- agno/tools/crawl4ai.py +7 -1
- agno/tools/csv_toolkit.py +9 -8
- agno/tools/dalle.py +18 -11
- agno/tools/daytona.py +13 -16
- agno/tools/decorator.py +6 -3
- agno/tools/desi_vocal.py +16 -7
- agno/tools/discord.py +11 -8
- agno/tools/docker.py +30 -42
- agno/tools/duckdb.py +34 -53
- agno/tools/duckduckgo.py +8 -7
- agno/tools/e2b.py +61 -61
- agno/tools/eleven_labs.py +35 -28
- agno/tools/email.py +4 -1
- agno/tools/evm.py +7 -1
- agno/tools/exa.py +19 -14
- agno/tools/fal.py +29 -29
- agno/tools/file.py +9 -8
- agno/tools/financial_datasets.py +25 -44
- agno/tools/firecrawl.py +22 -22
- agno/tools/function.py +127 -18
- agno/tools/giphy.py +22 -10
- agno/tools/github.py +48 -126
- agno/tools/gmail.py +45 -61
- agno/tools/google_bigquery.py +7 -6
- agno/tools/google_maps.py +11 -26
- agno/tools/googlesearch.py +7 -2
- agno/tools/googlesheets.py +21 -17
- agno/tools/hackernews.py +9 -5
- agno/tools/jina.py +5 -4
- agno/tools/jira.py +18 -9
- agno/tools/knowledge.py +31 -32
- agno/tools/linear.py +19 -34
- agno/tools/linkup.py +5 -1
- agno/tools/local_file_system.py +8 -5
- agno/tools/lumalab.py +31 -19
- agno/tools/mem0.py +18 -12
- agno/tools/memori.py +14 -10
- agno/tools/mlx_transcribe.py +3 -2
- agno/tools/models/azure_openai.py +32 -14
- agno/tools/models/gemini.py +58 -31
- agno/tools/models/groq.py +29 -20
- agno/tools/models/nebius.py +27 -11
- agno/tools/models_labs.py +39 -15
- agno/tools/moviepy_video.py +7 -6
- agno/tools/neo4j.py +10 -8
- agno/tools/newspaper.py +7 -2
- agno/tools/newspaper4k.py +8 -3
- agno/tools/openai.py +57 -26
- agno/tools/openbb.py +12 -11
- agno/tools/opencv.py +62 -46
- agno/tools/openweather.py +14 -12
- agno/tools/pandas.py +11 -3
- agno/tools/postgres.py +4 -12
- agno/tools/pubmed.py +4 -1
- agno/tools/python.py +9 -22
- agno/tools/reasoning.py +35 -27
- agno/tools/reddit.py +11 -26
- agno/tools/replicate.py +54 -41
- agno/tools/resend.py +4 -1
- agno/tools/scrapegraph.py +15 -14
- agno/tools/searxng.py +10 -23
- agno/tools/serpapi.py +6 -3
- agno/tools/serper.py +13 -4
- agno/tools/shell.py +9 -2
- agno/tools/slack.py +12 -11
- agno/tools/sleep.py +3 -2
- agno/tools/spider.py +24 -4
- agno/tools/sql.py +7 -6
- agno/tools/tavily.py +6 -4
- agno/tools/telegram.py +12 -4
- agno/tools/todoist.py +11 -31
- agno/tools/toolkit.py +1 -1
- agno/tools/trafilatura.py +22 -6
- agno/tools/trello.py +9 -22
- agno/tools/twilio.py +10 -3
- agno/tools/user_control_flow.py +6 -1
- agno/tools/valyu.py +34 -5
- agno/tools/visualization.py +19 -28
- agno/tools/webbrowser.py +4 -3
- agno/tools/webex.py +11 -7
- agno/tools/website.py +15 -46
- agno/tools/webtools.py +12 -4
- agno/tools/whatsapp.py +5 -9
- agno/tools/wikipedia.py +20 -13
- agno/tools/x.py +14 -13
- agno/tools/yfinance.py +13 -40
- agno/tools/youtube.py +26 -20
- agno/tools/zendesk.py +7 -2
- agno/tools/zep.py +10 -7
- agno/tools/zoom.py +10 -9
- agno/utils/common.py +1 -19
- agno/utils/events.py +95 -118
- agno/utils/gemini.py +31 -1
- agno/utils/knowledge.py +29 -0
- agno/utils/log.py +2 -2
- agno/utils/mcp.py +11 -5
- agno/utils/media.py +39 -0
- agno/utils/message.py +12 -1
- agno/utils/models/claude.py +55 -4
- agno/utils/models/mistral.py +8 -7
- agno/utils/models/schema_utils.py +3 -3
- agno/utils/pprint.py +33 -32
- agno/utils/print_response/agent.py +779 -0
- agno/utils/print_response/team.py +1565 -0
- agno/utils/print_response/workflow.py +1451 -0
- agno/utils/prompts.py +14 -14
- agno/utils/reasoning.py +87 -0
- agno/utils/response.py +42 -42
- agno/utils/streamlit.py +454 -0
- agno/utils/string.py +8 -22
- agno/utils/team.py +50 -0
- agno/utils/timer.py +2 -2
- agno/vectordb/base.py +33 -21
- agno/vectordb/cassandra/cassandra.py +287 -23
- agno/vectordb/chroma/chromadb.py +482 -59
- agno/vectordb/clickhouse/clickhousedb.py +270 -63
- agno/vectordb/couchbase/couchbase.py +309 -29
- agno/vectordb/lancedb/lance_db.py +360 -21
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +145 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +374 -0
- agno/vectordb/llamaindex/llamaindexdb.py +127 -0
- agno/vectordb/milvus/milvus.py +242 -32
- agno/vectordb/mongodb/mongodb.py +200 -24
- agno/vectordb/pgvector/pgvector.py +319 -37
- agno/vectordb/pineconedb/pineconedb.py +221 -27
- agno/vectordb/qdrant/qdrant.py +334 -14
- agno/vectordb/singlestore/singlestore.py +286 -29
- agno/vectordb/surrealdb/surrealdb.py +187 -7
- agno/vectordb/upstashdb/upstashdb.py +342 -26
- agno/vectordb/weaviate/weaviate.py +227 -165
- agno/workflow/__init__.py +17 -13
- agno/workflow/{v2/condition.py → condition.py} +135 -32
- agno/workflow/{v2/loop.py → loop.py} +115 -28
- agno/workflow/{v2/parallel.py → parallel.py} +138 -108
- agno/workflow/{v2/router.py → router.py} +133 -32
- agno/workflow/{v2/step.py → step.py} +200 -42
- agno/workflow/{v2/steps.py → steps.py} +147 -66
- agno/workflow/types.py +482 -0
- agno/workflow/workflow.py +2401 -696
- agno-2.0.0rc1.dist-info/METADATA +355 -0
- agno-2.0.0rc1.dist-info/RECORD +516 -0
- agno/agent/metrics.py +0 -107
- agno/api/app.py +0 -35
- agno/api/playground.py +0 -92
- agno/api/schemas/app.py +0 -12
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -35
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workflows.py +0 -33
- agno/api/workspace.py +0 -175
- agno/app/agui/__init__.py +0 -3
- agno/app/agui/app.py +0 -17
- agno/app/agui/sync_router.py +0 -120
- agno/app/base.py +0 -186
- agno/app/discord/__init__.py +0 -3
- agno/app/fastapi/__init__.py +0 -3
- agno/app/fastapi/app.py +0 -107
- agno/app/fastapi/async_router.py +0 -457
- agno/app/fastapi/sync_router.py +0 -448
- agno/app/playground/app.py +0 -228
- agno/app/playground/async_router.py +0 -1050
- agno/app/playground/deploy.py +0 -249
- agno/app/playground/operator.py +0 -183
- agno/app/playground/schemas.py +0 -220
- agno/app/playground/serve.py +0 -55
- agno/app/playground/sync_router.py +0 -1042
- agno/app/playground/utils.py +0 -46
- agno/app/settings.py +0 -15
- agno/app/slack/__init__.py +0 -3
- agno/app/slack/app.py +0 -19
- agno/app/slack/sync_router.py +0 -92
- agno/app/utils.py +0 -54
- agno/app/whatsapp/__init__.py +0 -3
- agno/app/whatsapp/app.py +0 -15
- agno/app/whatsapp/sync_router.py +0 -197
- agno/cli/auth_server.py +0 -249
- agno/cli/config.py +0 -274
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -357
- agno/cli/settings.py +0 -96
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -5
- agno/document/chunking/semantic.py +0 -45
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -5
- agno/document/reader/base.py +0 -47
- agno/document/reader/docx_reader.py +0 -60
- agno/document/reader/gcs/pdf_reader.py +0 -44
- agno/document/reader/s3/pdf_reader.py +0 -59
- agno/document/reader/s3/text_reader.py +0 -63
- agno/document/reader/url_reader.py +0 -59
- agno/document/reader/youtube_reader.py +0 -58
- agno/embedder/__init__.py +0 -5
- agno/embedder/langdb.py +0 -80
- agno/embedder/mistral.py +0 -82
- agno/embedder/openai.py +0 -78
- agno/file/__init__.py +0 -5
- 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 -702
- agno/knowledge/arxiv.py +0 -33
- agno/knowledge/combined.py +0 -36
- agno/knowledge/csv.py +0 -144
- agno/knowledge/csv_url.py +0 -124
- agno/knowledge/document.py +0 -223
- agno/knowledge/docx.py +0 -137
- agno/knowledge/firecrawl.py +0 -34
- agno/knowledge/gcs/__init__.py +0 -0
- agno/knowledge/gcs/base.py +0 -39
- agno/knowledge/gcs/pdf.py +0 -125
- agno/knowledge/json.py +0 -137
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/light_rag.py +0 -273
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/markdown.py +0 -154
- agno/knowledge/pdf.py +0 -164
- agno/knowledge/pdf_bytes.py +0 -42
- agno/knowledge/pdf_url.py +0 -148
- agno/knowledge/s3/__init__.py +0 -0
- agno/knowledge/s3/base.py +0 -64
- agno/knowledge/s3/pdf.py +0 -33
- agno/knowledge/s3/text.py +0 -34
- agno/knowledge/text.py +0 -141
- agno/knowledge/url.py +0 -46
- agno/knowledge/website.py +0 -179
- agno/knowledge/wikipedia.py +0 -32
- agno/knowledge/youtube.py +0 -35
- agno/memory/agent.py +0 -423
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -5
- 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 -22
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -201
- agno/memory/summary.py +0 -19
- agno/memory/team.py +0 -415
- agno/memory/v2/__init__.py +0 -2
- agno/memory/v2/db/__init__.py +0 -1
- agno/memory/v2/db/base.py +0 -42
- agno/memory/v2/db/firestore.py +0 -339
- agno/memory/v2/db/mongodb.py +0 -196
- agno/memory/v2/db/postgres.py +0 -214
- agno/memory/v2/db/redis.py +0 -187
- agno/memory/v2/db/schema.py +0 -54
- agno/memory/v2/db/sqlite.py +0 -209
- agno/memory/v2/manager.py +0 -437
- agno/memory/v2/memory.py +0 -1097
- agno/memory/v2/schema.py +0 -55
- agno/memory/v2/summarizer.py +0 -215
- agno/memory/workflow.py +0 -38
- agno/models/ollama/tools.py +0 -430
- agno/models/qwen/__init__.py +0 -5
- agno/playground/__init__.py +0 -10
- agno/playground/deploy.py +0 -3
- agno/playground/playground.py +0 -3
- agno/playground/serve.py +0 -3
- agno/playground/settings.py +0 -3
- agno/reranker/__init__.py +0 -0
- agno/run/v2/__init__.py +0 -0
- agno/run/v2/workflow.py +0 -567
- agno/storage/__init__.py +0 -0
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/dynamodb.py +0 -1
- agno/storage/agent/json.py +0 -1
- agno/storage/agent/mongodb.py +0 -1
- agno/storage/agent/postgres.py +0 -1
- agno/storage/agent/singlestore.py +0 -1
- agno/storage/agent/sqlite.py +0 -1
- agno/storage/agent/yaml.py +0 -1
- agno/storage/base.py +0 -60
- agno/storage/dynamodb.py +0 -673
- agno/storage/firestore.py +0 -297
- agno/storage/gcs_json.py +0 -261
- agno/storage/in_memory.py +0 -234
- agno/storage/json.py +0 -237
- agno/storage/mongodb.py +0 -328
- agno/storage/mysql.py +0 -685
- agno/storage/postgres.py +0 -682
- agno/storage/redis.py +0 -336
- agno/storage/session/__init__.py +0 -16
- agno/storage/session/agent.py +0 -64
- agno/storage/session/team.py +0 -63
- agno/storage/session/v2/__init__.py +0 -5
- agno/storage/session/workflow.py +0 -61
- agno/storage/singlestore.py +0 -606
- agno/storage/sqlite.py +0 -646
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/mongodb.py +0 -1
- agno/storage/workflow/postgres.py +0 -1
- agno/storage/workflow/sqlite.py +0 -1
- agno/storage/yaml.py +0 -241
- agno/tools/thinking.py +0 -73
- 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/workflow/v2/__init__.py +0 -21
- agno/workflow/v2/types.py +0 -357
- agno/workflow/v2/workflow.py +0 -3312
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -52
- agno/workspace/operator.py +0 -757
- agno/workspace/settings.py +0 -158
- agno-1.8.1.dist-info/METADATA +0 -982
- agno-1.8.1.dist-info/RECORD +0 -566
- agno-1.8.1.dist-info/entry_points.txt +0 -3
- /agno/{app → db/migrations}/__init__.py +0 -0
- /agno/{app/playground/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{cli → integrations}/__init__.py +0 -0
- /agno/{cli/ws → knowledge/chunking}/__init__.py +0 -0
- /agno/{document/chunking → knowledge/remote_content}/__init__.py +0 -0
- /agno/{document/reader/gcs → knowledge/reranker}/__init__.py +0 -0
- /agno/{document/reader/s3 → os/interfaces}/__init__.py +0 -0
- /agno/{app → os/interfaces}/slack/security.py +0 -0
- /agno/{app → os/interfaces}/whatsapp/security.py +0 -0
- /agno/{file/local → utils/print_response}/__init__.py +0 -0
- /agno/{infra → vectordb/llamaindex}/__init__.py +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0rc1.dist-info}/WHEEL +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0rc1.dist-info}/licenses/LICENSE +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Main class for the AG-UI app, used to expose an Agno Agent or Team in an AG-UI compatible format."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from fastapi.routing import APIRouter
|
|
6
|
+
|
|
7
|
+
from agno.agent import Agent
|
|
8
|
+
from agno.os.interfaces.agui.router import attach_routes
|
|
9
|
+
from agno.os.interfaces.base import BaseInterface
|
|
10
|
+
from agno.team import Team
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AGUI(BaseInterface):
|
|
14
|
+
type = "agui"
|
|
15
|
+
|
|
16
|
+
router: APIRouter
|
|
17
|
+
|
|
18
|
+
def __init__(self, agent: Optional[Agent] = None, team: Optional[Team] = None):
|
|
19
|
+
self.agent = agent
|
|
20
|
+
self.team = team
|
|
21
|
+
|
|
22
|
+
if not self.agent and not self.team:
|
|
23
|
+
raise ValueError("AGUI requires an agent and a team")
|
|
24
|
+
|
|
25
|
+
def get_router(self, **kwargs) -> APIRouter:
|
|
26
|
+
# Cannot be overridden
|
|
27
|
+
self.router = APIRouter(tags=["AGUI"])
|
|
28
|
+
|
|
29
|
+
self.router = attach_routes(router=self.router, agent=self.agent, team=self.team)
|
|
30
|
+
|
|
31
|
+
return self.router
|
|
@@ -16,7 +16,10 @@ from fastapi import APIRouter
|
|
|
16
16
|
from fastapi.responses import StreamingResponse
|
|
17
17
|
|
|
18
18
|
from agno.agent.agent import Agent
|
|
19
|
-
from agno.
|
|
19
|
+
from agno.os.interfaces.agui.utils import (
|
|
20
|
+
async_stream_agno_response_as_agui_events,
|
|
21
|
+
convert_agui_messages_to_agno_messages,
|
|
22
|
+
)
|
|
20
23
|
from agno.team.team import Team
|
|
21
24
|
|
|
22
25
|
logger = logging.getLogger(__name__)
|
|
@@ -32,8 +35,8 @@ async def run_agent(agent: Agent, run_input: RunAgentInput) -> AsyncIterator[Bas
|
|
|
32
35
|
yield RunStartedEvent(type=EventType.RUN_STARTED, thread_id=run_input.thread_id, run_id=run_id)
|
|
33
36
|
|
|
34
37
|
# Request streaming response from agent
|
|
35
|
-
response_stream =
|
|
36
|
-
|
|
38
|
+
response_stream = agent.arun(
|
|
39
|
+
input=messages,
|
|
37
40
|
session_id=run_input.thread_id,
|
|
38
41
|
stream=True,
|
|
39
42
|
stream_intermediate_steps=True,
|
|
@@ -41,7 +44,9 @@ async def run_agent(agent: Agent, run_input: RunAgentInput) -> AsyncIterator[Bas
|
|
|
41
44
|
|
|
42
45
|
# Stream the response content in AG-UI format
|
|
43
46
|
async for event in async_stream_agno_response_as_agui_events(
|
|
44
|
-
response_stream=response_stream,
|
|
47
|
+
response_stream=response_stream, # type: ignore
|
|
48
|
+
thread_id=run_input.thread_id,
|
|
49
|
+
run_id=run_id,
|
|
45
50
|
):
|
|
46
51
|
yield event
|
|
47
52
|
|
|
@@ -60,8 +65,8 @@ async def run_team(team: Team, input: RunAgentInput) -> AsyncIterator[BaseEvent]
|
|
|
60
65
|
yield RunStartedEvent(type=EventType.RUN_STARTED, thread_id=input.thread_id, run_id=run_id)
|
|
61
66
|
|
|
62
67
|
# Request streaming response from team
|
|
63
|
-
response_stream =
|
|
64
|
-
|
|
68
|
+
response_stream = team.arun(
|
|
69
|
+
input=messages,
|
|
65
70
|
session_id=input.thread_id,
|
|
66
71
|
stream=True,
|
|
67
72
|
stream_intermediate_steps=True,
|
|
@@ -78,15 +83,14 @@ async def run_team(team: Team, input: RunAgentInput) -> AsyncIterator[BaseEvent]
|
|
|
78
83
|
yield RunErrorEvent(type=EventType.RUN_ERROR, message=str(e))
|
|
79
84
|
|
|
80
85
|
|
|
81
|
-
def
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
raise ValueError("One of 'agent' or 'team' must be provided.")
|
|
86
|
+
def attach_routes(router: APIRouter, agent: Optional[Agent] = None, team: Optional[Team] = None) -> APIRouter:
|
|
87
|
+
if agent is None and team is None:
|
|
88
|
+
raise ValueError("Either agent or team must be provided.")
|
|
85
89
|
|
|
86
|
-
router = APIRouter()
|
|
87
90
|
encoder = EventEncoder()
|
|
88
91
|
|
|
89
|
-
|
|
92
|
+
@router.post("/agui")
|
|
93
|
+
async def run_agent_agui(run_input: RunAgentInput):
|
|
90
94
|
async def event_generator():
|
|
91
95
|
if agent:
|
|
92
96
|
async for event in run_agent(agent, run_input):
|
|
@@ -109,10 +113,6 @@ def get_async_agui_router(agent: Optional[Agent] = None, team: Optional[Team] =
|
|
|
109
113
|
},
|
|
110
114
|
)
|
|
111
115
|
|
|
112
|
-
@router.post("/agui")
|
|
113
|
-
async def run_agent_agui(run_input: RunAgentInput):
|
|
114
|
-
return await _run(run_input)
|
|
115
|
-
|
|
116
116
|
@router.get("/status")
|
|
117
117
|
async def get_status():
|
|
118
118
|
return {"status": "available"}
|
|
@@ -24,9 +24,10 @@ from ag_ui.core import (
|
|
|
24
24
|
from ag_ui.core.types import Message as AGUIMessage
|
|
25
25
|
|
|
26
26
|
from agno.models.message import Message
|
|
27
|
-
from agno.run.
|
|
28
|
-
from agno.run.team import
|
|
29
|
-
from agno.run.team import TeamRunEvent,
|
|
27
|
+
from agno.run.agent import RunContentEvent, RunEvent, RunOutputEvent, RunPausedEvent
|
|
28
|
+
from agno.run.team import RunContentEvent as TeamRunContentEvent
|
|
29
|
+
from agno.run.team import TeamRunEvent, TeamRunOutputEvent
|
|
30
|
+
from agno.utils.message import get_text_from_message
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
@dataclass
|
|
@@ -89,38 +90,44 @@ def convert_agui_messages_to_agno_messages(messages: List[AGUIMessage]) -> List[
|
|
|
89
90
|
return result
|
|
90
91
|
|
|
91
92
|
|
|
92
|
-
def extract_team_response_chunk_content(response:
|
|
93
|
+
def extract_team_response_chunk_content(response: TeamRunContentEvent) -> str:
|
|
93
94
|
"""Given a response stream chunk, find and extract the content."""
|
|
94
95
|
|
|
95
96
|
# Handle Team members' responses
|
|
96
97
|
members_content = []
|
|
97
98
|
if hasattr(response, "member_responses") and response.member_responses: # type: ignore
|
|
98
99
|
for member_resp in response.member_responses: # type: ignore
|
|
99
|
-
if isinstance(member_resp,
|
|
100
|
+
if isinstance(member_resp, RunContentEvent):
|
|
100
101
|
member_content = extract_response_chunk_content(member_resp)
|
|
101
102
|
if member_content:
|
|
102
103
|
members_content.append(f"Team member: {member_content}")
|
|
103
|
-
elif isinstance(member_resp,
|
|
104
|
+
elif isinstance(member_resp, TeamRunContentEvent):
|
|
104
105
|
member_content = extract_team_response_chunk_content(member_resp)
|
|
105
106
|
if member_content:
|
|
106
107
|
members_content.append(f"Team member: {member_content}")
|
|
107
108
|
members_response = "\n".join(members_content) if members_content else ""
|
|
108
109
|
|
|
109
|
-
|
|
110
|
+
# Handle structured outputs
|
|
111
|
+
main_content = get_text_from_message(response.content) if response.content is not None else ""
|
|
110
112
|
|
|
113
|
+
return main_content + members_response
|
|
111
114
|
|
|
112
|
-
|
|
115
|
+
|
|
116
|
+
def extract_response_chunk_content(response: RunContentEvent) -> str:
|
|
113
117
|
"""Given a response stream chunk, find and extract the content."""
|
|
118
|
+
|
|
114
119
|
if hasattr(response, "messages") and response.messages: # type: ignore
|
|
115
120
|
for msg in reversed(response.messages): # type: ignore
|
|
116
121
|
if hasattr(msg, "role") and msg.role == "assistant" and hasattr(msg, "content") and msg.content:
|
|
117
|
-
|
|
122
|
+
# Handle structured outputs from messages
|
|
123
|
+
return get_text_from_message(msg.content)
|
|
118
124
|
|
|
119
|
-
|
|
125
|
+
# Handle structured outputs
|
|
126
|
+
return get_text_from_message(response.content) if response.content is not None else ""
|
|
120
127
|
|
|
121
128
|
|
|
122
129
|
def _create_events_from_chunk(
|
|
123
|
-
chunk: Union[
|
|
130
|
+
chunk: Union[RunOutputEvent, TeamRunOutputEvent],
|
|
124
131
|
message_id: str,
|
|
125
132
|
message_started: bool,
|
|
126
133
|
event_buffer: EventBuffer,
|
|
@@ -132,9 +139,9 @@ def _create_events_from_chunk(
|
|
|
132
139
|
events_to_emit: List[BaseEvent] = []
|
|
133
140
|
|
|
134
141
|
# Extract content if the contextual event is a content event
|
|
135
|
-
if chunk.event == RunEvent.
|
|
142
|
+
if chunk.event == RunEvent.run_content:
|
|
136
143
|
content = extract_response_chunk_content(chunk) # type: ignore
|
|
137
|
-
elif chunk.event == TeamRunEvent.
|
|
144
|
+
elif chunk.event == TeamRunEvent.run_content:
|
|
138
145
|
content = extract_team_response_chunk_content(chunk) # type: ignore
|
|
139
146
|
else:
|
|
140
147
|
content = None
|
|
@@ -158,7 +165,7 @@ def _create_events_from_chunk(
|
|
|
158
165
|
message_id=message_id,
|
|
159
166
|
delta=content,
|
|
160
167
|
)
|
|
161
|
-
events_to_emit.append(content_event)
|
|
168
|
+
events_to_emit.append(content_event) # type: ignore
|
|
162
169
|
|
|
163
170
|
# Handle starting a new tool call
|
|
164
171
|
elif chunk.event == RunEvent.tool_call_started:
|
|
@@ -177,7 +184,7 @@ def _create_events_from_chunk(
|
|
|
177
184
|
tool_call_id=tool_call.tool_call_id, # type: ignore
|
|
178
185
|
delta=json.dumps(tool_call.tool_args),
|
|
179
186
|
)
|
|
180
|
-
events_to_emit.append(args_event)
|
|
187
|
+
events_to_emit.append(args_event) # type: ignore
|
|
181
188
|
|
|
182
189
|
# Handle tool call completion
|
|
183
190
|
elif chunk.event == RunEvent.tool_call_completed:
|
|
@@ -188,7 +195,7 @@ def _create_events_from_chunk(
|
|
|
188
195
|
type=EventType.TOOL_CALL_END,
|
|
189
196
|
tool_call_id=tool_call.tool_call_id, # type: ignore
|
|
190
197
|
)
|
|
191
|
-
events_to_emit.append(end_event)
|
|
198
|
+
events_to_emit.append(end_event) # type: ignore
|
|
192
199
|
|
|
193
200
|
if tool_call.result is not None:
|
|
194
201
|
result_event = ToolCallResultEvent(
|
|
@@ -198,21 +205,31 @@ def _create_events_from_chunk(
|
|
|
198
205
|
role="tool",
|
|
199
206
|
message_id=str(uuid.uuid4()),
|
|
200
207
|
)
|
|
201
|
-
events_to_emit.append(result_event)
|
|
208
|
+
events_to_emit.append(result_event) # type: ignore
|
|
209
|
+
|
|
210
|
+
if tool_call.result is not None:
|
|
211
|
+
result_event = ToolCallResultEvent(
|
|
212
|
+
type=EventType.TOOL_CALL_RESULT,
|
|
213
|
+
tool_call_id=tool_call.tool_call_id, # type: ignore
|
|
214
|
+
content=str(tool_call.result),
|
|
215
|
+
role="tool",
|
|
216
|
+
message_id=str(uuid.uuid4()),
|
|
217
|
+
)
|
|
218
|
+
events_to_emit.append(result_event) # type: ignore
|
|
202
219
|
|
|
203
220
|
# Handle reasoning
|
|
204
221
|
elif chunk.event == RunEvent.reasoning_started:
|
|
205
|
-
|
|
206
|
-
events_to_emit.append(
|
|
222
|
+
step_started_event = StepStartedEvent(type=EventType.STEP_STARTED, step_name="reasoning") # type: ignore
|
|
223
|
+
events_to_emit.append(step_started_event) # type: ignore
|
|
207
224
|
elif chunk.event == RunEvent.reasoning_completed:
|
|
208
|
-
|
|
209
|
-
events_to_emit.append(
|
|
225
|
+
step_started_event = StepFinishedEvent(type=EventType.STEP_FINISHED, step_name="reasoning") # type: ignore
|
|
226
|
+
events_to_emit.append(step_started_event) # type: ignore
|
|
210
227
|
|
|
211
|
-
return events_to_emit, message_started
|
|
228
|
+
return events_to_emit, message_started # type: ignore
|
|
212
229
|
|
|
213
230
|
|
|
214
231
|
def _create_completion_events(
|
|
215
|
-
chunk: Union[
|
|
232
|
+
chunk: Union[RunOutputEvent, TeamRunOutputEvent],
|
|
216
233
|
event_buffer: EventBuffer,
|
|
217
234
|
message_started: bool,
|
|
218
235
|
message_id: str,
|
|
@@ -220,7 +237,7 @@ def _create_completion_events(
|
|
|
220
237
|
run_id: str,
|
|
221
238
|
) -> List[BaseEvent]:
|
|
222
239
|
"""Create events for run completion."""
|
|
223
|
-
events_to_emit = []
|
|
240
|
+
events_to_emit: List[BaseEvent] = []
|
|
224
241
|
|
|
225
242
|
# End remaining active tool calls if needed
|
|
226
243
|
for tool_call_id in list(event_buffer.active_tool_call_ids):
|
|
@@ -234,10 +251,10 @@ def _create_completion_events(
|
|
|
234
251
|
# End the message and run, denoting the end of the session
|
|
235
252
|
if message_started:
|
|
236
253
|
end_message_event = TextMessageEndEvent(type=EventType.TEXT_MESSAGE_END, message_id=message_id)
|
|
237
|
-
events_to_emit.append(end_message_event)
|
|
254
|
+
events_to_emit.append(end_message_event) # type: ignore
|
|
238
255
|
|
|
239
256
|
# emit frontend tool calls, i.e. external_execution=True
|
|
240
|
-
if isinstance(chunk,
|
|
257
|
+
if isinstance(chunk, RunPausedEvent) and chunk.tools is not None:
|
|
241
258
|
for tool in chunk.tools:
|
|
242
259
|
if tool.tool_call_id is None or tool.tool_name is None:
|
|
243
260
|
continue
|
|
@@ -248,14 +265,14 @@ def _create_completion_events(
|
|
|
248
265
|
tool_call_name=tool.tool_name,
|
|
249
266
|
parent_message_id=message_id,
|
|
250
267
|
)
|
|
251
|
-
events_to_emit.append(start_event)
|
|
268
|
+
events_to_emit.append(start_event) # type: ignore
|
|
252
269
|
|
|
253
270
|
args_event = ToolCallArgsEvent(
|
|
254
271
|
type=EventType.TOOL_CALL_ARGS,
|
|
255
272
|
tool_call_id=tool.tool_call_id,
|
|
256
273
|
delta=json.dumps(tool.tool_args),
|
|
257
274
|
)
|
|
258
|
-
events_to_emit.append(args_event)
|
|
275
|
+
events_to_emit.append(args_event) # type: ignore
|
|
259
276
|
|
|
260
277
|
end_event = ToolCallEndEvent(
|
|
261
278
|
type=EventType.TOOL_CALL_END,
|
|
@@ -263,15 +280,42 @@ def _create_completion_events(
|
|
|
263
280
|
)
|
|
264
281
|
events_to_emit.append(end_event)
|
|
265
282
|
|
|
283
|
+
# emit frontend tool calls, i.e. external_execution=True
|
|
284
|
+
if isinstance(chunk, RunPausedEvent) and chunk.tools is not None:
|
|
285
|
+
for tool in chunk.tools:
|
|
286
|
+
if tool.tool_call_id is None or tool.tool_name is None:
|
|
287
|
+
continue
|
|
288
|
+
|
|
289
|
+
start_event = ToolCallStartEvent(
|
|
290
|
+
type=EventType.TOOL_CALL_START,
|
|
291
|
+
tool_call_id=tool.tool_call_id,
|
|
292
|
+
tool_call_name=tool.tool_name,
|
|
293
|
+
parent_message_id=message_id,
|
|
294
|
+
)
|
|
295
|
+
events_to_emit.append(start_event) # type: ignore
|
|
296
|
+
|
|
297
|
+
args_event = ToolCallArgsEvent(
|
|
298
|
+
type=EventType.TOOL_CALL_ARGS,
|
|
299
|
+
tool_call_id=tool.tool_call_id,
|
|
300
|
+
delta=json.dumps(tool.tool_args),
|
|
301
|
+
)
|
|
302
|
+
events_to_emit.append(args_event) # type: ignore
|
|
303
|
+
|
|
304
|
+
end_event = ToolCallEndEvent(
|
|
305
|
+
type=EventType.TOOL_CALL_END,
|
|
306
|
+
tool_call_id=tool.tool_call_id,
|
|
307
|
+
)
|
|
308
|
+
events_to_emit.append(end_event) # type: ignore
|
|
309
|
+
|
|
266
310
|
run_finished_event = RunFinishedEvent(type=EventType.RUN_FINISHED, thread_id=thread_id, run_id=run_id)
|
|
267
|
-
events_to_emit.append(run_finished_event)
|
|
311
|
+
events_to_emit.append(run_finished_event) # type: ignore
|
|
268
312
|
|
|
269
|
-
return events_to_emit
|
|
313
|
+
return events_to_emit # type: ignore
|
|
270
314
|
|
|
271
315
|
|
|
272
316
|
def _emit_event_logic(event: BaseEvent, event_buffer: EventBuffer) -> List[BaseEvent]:
|
|
273
317
|
"""Process an event through the buffer and return events to actually emit."""
|
|
274
|
-
events_to_emit = []
|
|
318
|
+
events_to_emit: List[BaseEvent] = []
|
|
275
319
|
|
|
276
320
|
if event_buffer.is_blocked():
|
|
277
321
|
# Handle events related to the current blocking tool call
|
|
@@ -320,7 +364,7 @@ def _emit_event_logic(event: BaseEvent, event_buffer: EventBuffer) -> List[BaseE
|
|
|
320
364
|
|
|
321
365
|
|
|
322
366
|
def stream_agno_response_as_agui_events(
|
|
323
|
-
response_stream: Iterator[Union[
|
|
367
|
+
response_stream: Iterator[Union[RunOutputEvent, TeamRunOutputEvent]], thread_id: str, run_id: str
|
|
324
368
|
) -> Iterator[BaseEvent]:
|
|
325
369
|
"""Map the Agno response stream to AG-UI format, handling event ordering constraints."""
|
|
326
370
|
message_id = str(uuid.uuid4())
|
|
@@ -355,7 +399,7 @@ def stream_agno_response_as_agui_events(
|
|
|
355
399
|
|
|
356
400
|
# Async version - thin wrapper
|
|
357
401
|
async def async_stream_agno_response_as_agui_events(
|
|
358
|
-
response_stream: AsyncIterator[Union[
|
|
402
|
+
response_stream: AsyncIterator[Union[RunOutputEvent, TeamRunOutputEvent]],
|
|
359
403
|
thread_id: str,
|
|
360
404
|
run_id: str,
|
|
361
405
|
) -> AsyncIterator[BaseEvent]:
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from fastapi import APIRouter
|
|
5
|
+
|
|
6
|
+
from agno.agent import Agent
|
|
7
|
+
from agno.team import Team
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class BaseInterface(ABC):
|
|
11
|
+
type: str
|
|
12
|
+
version: str = "1.0"
|
|
13
|
+
router_prefix: str = ""
|
|
14
|
+
agent: Optional[Agent] = None
|
|
15
|
+
team: Optional[Team] = None
|
|
16
|
+
|
|
17
|
+
router: APIRouter
|
|
18
|
+
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def get_router(self, use_async: bool = True, **kwargs) -> APIRouter:
|
|
21
|
+
pass
|
|
@@ -3,15 +3,13 @@ from typing import Optional
|
|
|
3
3
|
from fastapi import APIRouter, BackgroundTasks, HTTPException, Request
|
|
4
4
|
|
|
5
5
|
from agno.agent.agent import Agent
|
|
6
|
-
from agno.
|
|
6
|
+
from agno.os.interfaces.slack.security import verify_slack_signature
|
|
7
7
|
from agno.team.team import Team
|
|
8
8
|
from agno.tools.slack import SlackTools
|
|
9
9
|
from agno.utils.log import log_info
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def
|
|
13
|
-
router = APIRouter()
|
|
14
|
-
|
|
12
|
+
def attach_routes(router: APIRouter, agent: Optional[Agent] = None, team: Optional[Team] = None) -> APIRouter:
|
|
15
13
|
@router.post("/slack/events")
|
|
16
14
|
async def slack_events(request: Request, background_tasks: BackgroundTasks):
|
|
17
15
|
body = await request.body()
|
|
@@ -44,7 +42,7 @@ def get_async_router(agent: Optional[Agent] = None, team: Optional[Team] = None)
|
|
|
44
42
|
async def _process_slack_event(event: dict):
|
|
45
43
|
if event.get("type") == "message":
|
|
46
44
|
user = None
|
|
47
|
-
message_text = event.get("text")
|
|
45
|
+
message_text = event.get("text", "")
|
|
48
46
|
channel_id = event.get("channel", "")
|
|
49
47
|
user = event.get("user")
|
|
50
48
|
if event.get("thread_ts"):
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from fastapi.routing import APIRouter
|
|
5
|
+
|
|
6
|
+
from agno.agent.agent import Agent
|
|
7
|
+
from agno.os.interfaces.base import BaseInterface
|
|
8
|
+
from agno.os.interfaces.slack.router import attach_routes
|
|
9
|
+
from agno.team.team import Team
|
|
10
|
+
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Slack(BaseInterface):
|
|
15
|
+
type = "slack"
|
|
16
|
+
|
|
17
|
+
router: APIRouter
|
|
18
|
+
|
|
19
|
+
def __init__(self, agent: Optional[Agent] = None, team: Optional[Team] = None):
|
|
20
|
+
self.agent = agent
|
|
21
|
+
self.team = team
|
|
22
|
+
|
|
23
|
+
if not self.agent and not self.team:
|
|
24
|
+
raise ValueError("Slack requires an agent and a team")
|
|
25
|
+
|
|
26
|
+
def get_router(self, **kwargs) -> APIRouter:
|
|
27
|
+
# Cannot be overridden
|
|
28
|
+
self.router = APIRouter(prefix="/slack", tags=["Slack"])
|
|
29
|
+
|
|
30
|
+
self.router = attach_routes(router=self.router, agent=self.agent, team=self.team)
|
|
31
|
+
|
|
32
|
+
return self.router
|
|
@@ -15,9 +15,7 @@ from agno.utils.whatsapp import get_media_async, send_image_message_async, typin
|
|
|
15
15
|
from .security import validate_webhook_signature
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
def
|
|
19
|
-
router = APIRouter()
|
|
20
|
-
|
|
18
|
+
def attach_routes(router: APIRouter, agent: Optional[Agent] = None, team: Optional[Team] = None) -> APIRouter:
|
|
21
19
|
if agent is None and team is None:
|
|
22
20
|
raise ValueError("Either agent or team must be provided.")
|
|
23
21
|
|
|
@@ -128,7 +126,7 @@ def get_async_router(agent: Optional[Agent] = None, team: Optional[Team] = None)
|
|
|
128
126
|
audio=[Audio(content=await get_media_async(message_audio))] if message_audio else None,
|
|
129
127
|
)
|
|
130
128
|
elif team:
|
|
131
|
-
response = await team.arun(
|
|
129
|
+
response = await team.arun( # type: ignore
|
|
132
130
|
message_text,
|
|
133
131
|
user_id=phone_number,
|
|
134
132
|
files=[File(content=await get_media_async(message_doc))] if message_doc else None,
|
|
@@ -167,9 +165,8 @@ def get_async_router(agent: Optional[Agent] = None, team: Optional[Team] = None)
|
|
|
167
165
|
log_warning(
|
|
168
166
|
f"Could not process image content for user {phone_number}. Type: {type(image_content)}"
|
|
169
167
|
)
|
|
170
|
-
await _send_whatsapp_message(phone_number, response.content) #
|
|
171
|
-
|
|
172
|
-
await _send_whatsapp_message(phone_number, response.content)
|
|
168
|
+
await _send_whatsapp_message(phone_number, response.content) # type: ignore
|
|
169
|
+
await _send_whatsapp_message(phone_number, response.content) # type: ignore
|
|
173
170
|
|
|
174
171
|
except Exception as e:
|
|
175
172
|
log_error(f"Error processing message: {str(e)}")
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from fastapi.routing import APIRouter
|
|
4
|
+
|
|
5
|
+
from agno.agent import Agent
|
|
6
|
+
from agno.os.interfaces.base import BaseInterface
|
|
7
|
+
from agno.os.interfaces.whatsapp.router import attach_routes
|
|
8
|
+
from agno.team import Team
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Whatsapp(BaseInterface):
|
|
12
|
+
type = "whatsapp"
|
|
13
|
+
|
|
14
|
+
router: APIRouter
|
|
15
|
+
|
|
16
|
+
def __init__(self, agent: Optional[Agent] = None, team: Optional[Team] = None):
|
|
17
|
+
self.agent = agent
|
|
18
|
+
self.team = team
|
|
19
|
+
|
|
20
|
+
if not self.agent and not self.team:
|
|
21
|
+
raise ValueError("Whatsapp requires an agent and a team")
|
|
22
|
+
|
|
23
|
+
def get_router(self, **kwargs) -> APIRouter:
|
|
24
|
+
# Cannot be overridden
|
|
25
|
+
self.router = APIRouter(prefix="/whatsapp", tags=["Whatsapp"])
|
|
26
|
+
|
|
27
|
+
self.router = attach_routes(router=self.router, agent=self.agent, team=self.team)
|
|
28
|
+
|
|
29
|
+
return self.router
|