agno 1.8.1__py3-none-any.whl → 2.0.0__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 +3143 -4170
- 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 +1416 -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 +154 -48
- 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 +1551 -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 +47 -65
- agno/knowledge/reader/docx_reader.py +83 -0
- agno/{document → knowledge}/reader/firecrawl_reader.py +42 -21
- agno/{document → knowledge}/reader/json_reader.py +30 -9
- agno/{document → knowledge}/reader/markdown_reader.py +58 -9
- agno/{document → knowledge}/reader/pdf_reader.py +71 -126
- agno/knowledge/reader/reader_factory.py +268 -0
- agno/knowledge/reader/s3_reader.py +101 -0
- agno/{document → knowledge}/reader/text_reader.py +31 -10
- agno/knowledge/reader/url_reader.py +128 -0
- agno/knowledge/reader/web_search_reader.py +366 -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/media.py +269 -268
- 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 +110 -182
- agno/models/aws/claude.py +64 -18
- agno/models/azure/ai_foundry.py +73 -23
- agno/models/base.py +346 -290
- agno/models/cerebras/cerebras.py +84 -27
- agno/models/cohere/chat.py +106 -98
- agno/models/google/gemini.py +105 -46
- 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 +46 -151
- 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 +85 -47
- agno/models/openai/chat.py +154 -37
- 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 +15 -9
- 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 +497 -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 +235 -0
- agno/os/router.py +1400 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +393 -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 +850 -0
- agno/os/routers/knowledge/schemas.py +118 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +410 -0
- agno/os/routers/memory/schemas.py +58 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +178 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +536 -0
- agno/os/schema.py +945 -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/agent.py +633 -0
- agno/run/base.py +53 -77
- agno/run/cancel.py +81 -0
- agno/run/team.py +243 -96
- agno/run/workflow.py +550 -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 +3260 -4824
- 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 +43 -23
- agno/tools/browserbase.py +13 -4
- agno/tools/calcom.py +12 -10
- agno/tools/calculator.py +10 -27
- agno/tools/cartesia.py +20 -17
- 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 +22 -12
- agno/tools/daytona.py +13 -16
- agno/tools/decorator.py +6 -3
- agno/tools/desi_vocal.py +17 -8
- 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 +62 -62
- agno/tools/eleven_labs.py +36 -29
- agno/tools/email.py +4 -1
- agno/tools/evm.py +7 -1
- agno/tools/exa.py +19 -14
- agno/tools/fal.py +30 -30
- 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 +23 -11
- 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 +32 -20
- agno/tools/mcp.py +1 -2
- 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 +33 -15
- agno/tools/models/gemini.py +59 -32
- agno/tools/models/groq.py +30 -23
- agno/tools/models/nebius.py +28 -12
- agno/tools/models_labs.py +40 -16
- 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 +58 -32
- agno/tools/openbb.py +12 -11
- agno/tools/opencv.py +63 -47
- 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 +55 -42
- 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 +100 -123
- agno/utils/gemini.py +32 -2
- agno/utils/knowledge.py +29 -0
- agno/utils/log.py +54 -4
- agno/utils/mcp.py +68 -10
- agno/utils/media.py +39 -0
- agno/utils/message.py +12 -1
- agno/utils/models/aws_claude.py +1 -1
- agno/utils/models/claude.py +47 -4
- agno/utils/models/cohere.py +1 -1
- agno/utils/models/mistral.py +8 -7
- agno/utils/models/schema_utils.py +3 -3
- agno/utils/models/watsonx.py +1 -1
- agno/utils/openai.py +1 -1
- agno/utils/pprint.py +33 -32
- agno/utils/print_response/agent.py +779 -0
- agno/utils/print_response/team.py +1669 -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 +481 -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} +207 -49
- agno/workflow/{v2/steps.py → steps.py} +147 -66
- agno/workflow/types.py +482 -0
- agno/workflow/workflow.py +2410 -696
- agno-2.0.0.dist-info/METADATA +494 -0
- agno-2.0.0.dist-info/RECORD +515 -0
- agno-2.0.0.dist-info/licenses/LICENSE +201 -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/response.py +0 -467
- 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-1.8.1.dist-info/licenses/LICENSE +0 -375
- /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.0.dist-info}/WHEEL +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0.dist-info}/top_level.txt +0 -0
agno/app/playground/utils.py
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
|
|
3
|
-
from fastapi import HTTPException, UploadFile
|
|
4
|
-
|
|
5
|
-
from agno.media import Audio, Image, Video
|
|
6
|
-
from agno.media import File as FileMedia
|
|
7
|
-
from agno.utils.log import logger
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
def process_image(file: UploadFile) -> Image:
|
|
11
|
-
content = file.file.read()
|
|
12
|
-
if not content:
|
|
13
|
-
raise HTTPException(status_code=400, detail="Empty file")
|
|
14
|
-
return Image(content=content)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def process_audio(file: UploadFile) -> Audio:
|
|
18
|
-
content = file.file.read()
|
|
19
|
-
if not content:
|
|
20
|
-
raise HTTPException(status_code=400, detail="Empty file")
|
|
21
|
-
format = None
|
|
22
|
-
if file.filename and "." in file.filename:
|
|
23
|
-
format = file.filename.split(".")[-1].lower()
|
|
24
|
-
elif file.content_type:
|
|
25
|
-
format = file.content_type.split("/")[-1]
|
|
26
|
-
|
|
27
|
-
return Audio(content=content, format=format)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def process_video(file: UploadFile) -> Video:
|
|
31
|
-
content = file.file.read()
|
|
32
|
-
if not content:
|
|
33
|
-
raise HTTPException(status_code=400, detail="Empty file")
|
|
34
|
-
return Video(content=content, format=file.content_type)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
def process_document(file: UploadFile) -> Optional[FileMedia]:
|
|
38
|
-
try:
|
|
39
|
-
content = file.file.read()
|
|
40
|
-
if not content:
|
|
41
|
-
raise HTTPException(status_code=400, detail="Empty file")
|
|
42
|
-
|
|
43
|
-
return FileMedia(content=content)
|
|
44
|
-
except Exception as e:
|
|
45
|
-
logger.error(f"Error processing document {file.filename}: {e}")
|
|
46
|
-
return None
|
agno/app/settings.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from pydantic_settings import BaseSettings
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class APIAppSettings(BaseSettings):
|
|
7
|
-
"""App settings for API-based apps that can be set using environment variables.
|
|
8
|
-
|
|
9
|
-
Reference: https://pydantic-docs.helpmanual.io/usage/settings/
|
|
10
|
-
"""
|
|
11
|
-
|
|
12
|
-
title: str = "agno-app"
|
|
13
|
-
|
|
14
|
-
# Set to False to disable docs server at /docs and /redoc
|
|
15
|
-
docs_enabled: bool = True
|
agno/app/slack/__init__.py
DELETED
agno/app/slack/app.py
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
from fastapi.routing import APIRouter
|
|
4
|
-
|
|
5
|
-
from agno.app.base import BaseAPIApp
|
|
6
|
-
from agno.app.slack.async_router import get_async_router
|
|
7
|
-
from agno.app.slack.sync_router import get_sync_router
|
|
8
|
-
|
|
9
|
-
logger = logging.getLogger(__name__)
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class SlackAPI(BaseAPIApp):
|
|
13
|
-
type = "slack"
|
|
14
|
-
|
|
15
|
-
def get_router(self) -> APIRouter:
|
|
16
|
-
return get_sync_router(agent=self.agent, team=self.team)
|
|
17
|
-
|
|
18
|
-
def get_async_router(self) -> APIRouter:
|
|
19
|
-
return get_async_router(agent=self.agent, team=self.team)
|
agno/app/slack/sync_router.py
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
from typing import Optional, cast
|
|
2
|
-
|
|
3
|
-
from fastapi import APIRouter, BackgroundTasks, HTTPException, Request
|
|
4
|
-
|
|
5
|
-
from agno.agent.agent import Agent
|
|
6
|
-
from agno.app.slack.security import verify_slack_signature
|
|
7
|
-
from agno.team.team import Team
|
|
8
|
-
from agno.tools.slack import SlackTools
|
|
9
|
-
from agno.utils.log import log_info
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
def get_sync_router(agent: Optional[Agent] = None, team: Optional[Team] = None) -> APIRouter:
|
|
13
|
-
router = APIRouter()
|
|
14
|
-
|
|
15
|
-
@router.post("/slack/events")
|
|
16
|
-
def slack_events(request: Request, background_tasks: BackgroundTasks):
|
|
17
|
-
body = cast(bytes, request.body())
|
|
18
|
-
timestamp = request.headers.get("X-Slack-Request-Timestamp")
|
|
19
|
-
slack_signature = request.headers.get("X-Slack-Signature", "")
|
|
20
|
-
|
|
21
|
-
if not timestamp or not slack_signature:
|
|
22
|
-
raise HTTPException(status_code=400, detail="Missing Slack headers")
|
|
23
|
-
|
|
24
|
-
if not verify_slack_signature(body, timestamp, slack_signature):
|
|
25
|
-
raise HTTPException(status_code=403, detail="Invalid signature")
|
|
26
|
-
|
|
27
|
-
data = cast(dict, request.json())
|
|
28
|
-
|
|
29
|
-
# Handle URL verification
|
|
30
|
-
if data.get("type") == "url_verification":
|
|
31
|
-
return {"challenge": data.get("challenge")}
|
|
32
|
-
|
|
33
|
-
# Process other event types (e.g., message events) asynchronously
|
|
34
|
-
if "event" in data:
|
|
35
|
-
event = data["event"]
|
|
36
|
-
if event.get("bot_id"):
|
|
37
|
-
log_info("bot event")
|
|
38
|
-
pass
|
|
39
|
-
else:
|
|
40
|
-
background_tasks.add_task(_process_slack_event, event)
|
|
41
|
-
|
|
42
|
-
return {"status": "ok"}
|
|
43
|
-
|
|
44
|
-
def _process_slack_event(event: dict):
|
|
45
|
-
if event.get("type") == "message":
|
|
46
|
-
user = None
|
|
47
|
-
message_text = event.get("text")
|
|
48
|
-
channel_id = event.get("channel", "")
|
|
49
|
-
user = event.get("user")
|
|
50
|
-
if event.get("thread_ts"):
|
|
51
|
-
ts = event.get("thread_ts", "")
|
|
52
|
-
else:
|
|
53
|
-
ts = event.get("ts", "")
|
|
54
|
-
|
|
55
|
-
# Use the timestamp as the session id, so that each thread is a separate session
|
|
56
|
-
session_id = ts
|
|
57
|
-
|
|
58
|
-
if agent:
|
|
59
|
-
response = agent.run(message_text, user_id=user if user else None, session_id=session_id)
|
|
60
|
-
elif team:
|
|
61
|
-
response = team.run(message_text, user_id=user if user else None, session_id=session_id) # type: ignore
|
|
62
|
-
|
|
63
|
-
if response.reasoning_content:
|
|
64
|
-
_send_slack_message(
|
|
65
|
-
channel=channel_id, message=f"Reasoning: \n{response.reasoning_content}", thread_ts=ts, italics=True
|
|
66
|
-
)
|
|
67
|
-
_send_slack_message(channel=channel_id, message=response.content or "", thread_ts=ts)
|
|
68
|
-
|
|
69
|
-
def _send_slack_message(channel: str, thread_ts: str, message: str, italics: bool = False):
|
|
70
|
-
if len(message) <= 40000:
|
|
71
|
-
if italics:
|
|
72
|
-
# Handle multi-line messages by making each line italic
|
|
73
|
-
formatted_message = "\n".join([f"_{line}_" for line in message.split("\n")])
|
|
74
|
-
SlackTools().send_message_thread(channel=channel, text=formatted_message or "", thread_ts=thread_ts)
|
|
75
|
-
else:
|
|
76
|
-
SlackTools().send_message_thread(channel=channel, text=message or "", thread_ts=thread_ts)
|
|
77
|
-
return
|
|
78
|
-
|
|
79
|
-
# Split message into batches of 4000 characters (WhatsApp message limit is 4096)
|
|
80
|
-
message_batches = [message[i : i + 40000] for i in range(0, len(message), 40000)]
|
|
81
|
-
|
|
82
|
-
# Add a prefix with the batch number
|
|
83
|
-
for i, batch in enumerate(message_batches, 1):
|
|
84
|
-
batch_message = f"[{i}/{len(message_batches)}] {batch}"
|
|
85
|
-
if italics:
|
|
86
|
-
# Handle multi-line messages by making each line italic
|
|
87
|
-
formatted_batch = "\n".join([f"_{line}_" for line in batch_message.split("\n")])
|
|
88
|
-
SlackTools().send_message_thread(channel=channel, text=formatted_batch or "", thread_ts=thread_ts)
|
|
89
|
-
else:
|
|
90
|
-
SlackTools().send_message_thread(channel=channel, text=message or "", thread_ts=thread_ts)
|
|
91
|
-
|
|
92
|
-
return router
|
agno/app/utils.py
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
from typing import Optional
|
|
2
|
-
from uuid import uuid4
|
|
3
|
-
|
|
4
|
-
from fastapi import HTTPException, UploadFile
|
|
5
|
-
|
|
6
|
-
from agno.media import Audio, Image, Video
|
|
7
|
-
from agno.media import File as FileMedia
|
|
8
|
-
from agno.utils.log import logger
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def process_image(file: UploadFile) -> Image:
|
|
12
|
-
content = file.file.read()
|
|
13
|
-
if not content:
|
|
14
|
-
raise HTTPException(status_code=400, detail="Empty file")
|
|
15
|
-
return Image(content=content)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def process_audio(file: UploadFile) -> Audio:
|
|
19
|
-
content = file.file.read()
|
|
20
|
-
if not content:
|
|
21
|
-
raise HTTPException(status_code=400, detail="Empty file")
|
|
22
|
-
format = None
|
|
23
|
-
if file.filename and "." in file.filename:
|
|
24
|
-
format = file.filename.split(".")[-1].lower()
|
|
25
|
-
elif file.content_type:
|
|
26
|
-
format = file.content_type.split("/")[-1]
|
|
27
|
-
|
|
28
|
-
return Audio(content=content, format=format)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def process_video(file: UploadFile) -> Video:
|
|
32
|
-
content = file.file.read()
|
|
33
|
-
if not content:
|
|
34
|
-
raise HTTPException(status_code=400, detail="Empty file")
|
|
35
|
-
return Video(content=content, format=file.content_type)
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def process_document(file: UploadFile) -> Optional[FileMedia]:
|
|
39
|
-
try:
|
|
40
|
-
content = file.file.read()
|
|
41
|
-
if not content:
|
|
42
|
-
raise HTTPException(status_code=400, detail="Empty file")
|
|
43
|
-
|
|
44
|
-
return FileMedia(content=content, mime_type=file.content_type)
|
|
45
|
-
except Exception as e:
|
|
46
|
-
logger.error(f"Error processing document {file.filename}: {e}")
|
|
47
|
-
return None
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def generate_id(name: Optional[str] = None) -> str:
|
|
51
|
-
if name:
|
|
52
|
-
return name.lower().replace(" ", "-").replace("_", "-")
|
|
53
|
-
else:
|
|
54
|
-
return str(uuid4())
|
agno/app/whatsapp/__init__.py
DELETED
agno/app/whatsapp/app.py
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from fastapi.routing import APIRouter
|
|
2
|
-
|
|
3
|
-
from agno.app.base import BaseAPIApp
|
|
4
|
-
from agno.app.whatsapp.async_router import get_async_router
|
|
5
|
-
from agno.app.whatsapp.sync_router import get_sync_router
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class WhatsappAPI(BaseAPIApp):
|
|
9
|
-
type = "whatsapp"
|
|
10
|
-
|
|
11
|
-
def get_router(self) -> APIRouter:
|
|
12
|
-
return get_sync_router(agent=self.agent, team=self.team)
|
|
13
|
-
|
|
14
|
-
def get_async_router(self) -> APIRouter:
|
|
15
|
-
return get_async_router(agent=self.agent, team=self.team)
|
agno/app/whatsapp/sync_router.py
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
import base64
|
|
2
|
-
from os import getenv
|
|
3
|
-
from typing import Optional, cast
|
|
4
|
-
|
|
5
|
-
from fastapi import APIRouter, BackgroundTasks, HTTPException, Request
|
|
6
|
-
from fastapi.responses import PlainTextResponse
|
|
7
|
-
|
|
8
|
-
from agno.agent.agent import Agent
|
|
9
|
-
from agno.media import Audio, File, Image, Video
|
|
10
|
-
from agno.team.team import Team
|
|
11
|
-
from agno.tools.whatsapp import WhatsAppTools
|
|
12
|
-
from agno.utils.log import log_debug, log_error, log_info, log_warning
|
|
13
|
-
from agno.utils.whatsapp import get_media, send_image_message, typing_indicator, upload_media
|
|
14
|
-
|
|
15
|
-
from .security import validate_webhook_signature
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
def get_sync_router(agent: Optional[Agent] = None, team: Optional[Team] = None) -> APIRouter:
|
|
19
|
-
router = APIRouter()
|
|
20
|
-
|
|
21
|
-
if agent is None and team is None:
|
|
22
|
-
raise ValueError("Either agent or team must be provided.")
|
|
23
|
-
|
|
24
|
-
@router.get("/status")
|
|
25
|
-
def status():
|
|
26
|
-
return {"status": "available"}
|
|
27
|
-
|
|
28
|
-
@router.get("/webhook")
|
|
29
|
-
def verify_webhook(request: Request):
|
|
30
|
-
"""Handle WhatsApp webhook verification"""
|
|
31
|
-
mode = request.query_params.get("hub.mode")
|
|
32
|
-
token = request.query_params.get("hub.verify_token")
|
|
33
|
-
challenge = request.query_params.get("hub.challenge")
|
|
34
|
-
|
|
35
|
-
verify_token = getenv("WHATSAPP_VERIFY_TOKEN")
|
|
36
|
-
if not verify_token:
|
|
37
|
-
raise HTTPException(status_code=500, detail="WHATSAPP_VERIFY_TOKEN is not set")
|
|
38
|
-
|
|
39
|
-
if mode == "subscribe" and token == verify_token:
|
|
40
|
-
if not challenge:
|
|
41
|
-
raise HTTPException(status_code=400, detail="No challenge received")
|
|
42
|
-
return PlainTextResponse(content=challenge)
|
|
43
|
-
|
|
44
|
-
raise HTTPException(status_code=403, detail="Invalid verify token or mode")
|
|
45
|
-
|
|
46
|
-
@router.post("/webhook")
|
|
47
|
-
def webhook(request: Request, background_tasks: BackgroundTasks):
|
|
48
|
-
"""Handle incoming WhatsApp messages"""
|
|
49
|
-
try:
|
|
50
|
-
# Get raw payload for signature validation
|
|
51
|
-
payload = cast(bytes, request.body())
|
|
52
|
-
signature = request.headers.get("X-Hub-Signature-256")
|
|
53
|
-
|
|
54
|
-
# Validate webhook signature
|
|
55
|
-
if not validate_webhook_signature(payload, signature):
|
|
56
|
-
log_warning("Invalid webhook signature")
|
|
57
|
-
raise HTTPException(status_code=403, detail="Invalid signature")
|
|
58
|
-
|
|
59
|
-
body = cast(dict, request.json())
|
|
60
|
-
|
|
61
|
-
# Validate webhook data
|
|
62
|
-
if body.get("object") != "whatsapp_business_account":
|
|
63
|
-
log_warning(f"Received non-WhatsApp webhook object: {body.get('object')}")
|
|
64
|
-
return {"status": "ignored"}
|
|
65
|
-
|
|
66
|
-
# Process messages in background
|
|
67
|
-
for entry in body.get("entry", []):
|
|
68
|
-
for change in entry.get("changes", []):
|
|
69
|
-
messages = change.get("value", {}).get("messages", [])
|
|
70
|
-
|
|
71
|
-
if not messages:
|
|
72
|
-
continue
|
|
73
|
-
|
|
74
|
-
message = messages[0]
|
|
75
|
-
background_tasks.add_task(process_message, message, agent, team)
|
|
76
|
-
|
|
77
|
-
return {"status": "processing"}
|
|
78
|
-
|
|
79
|
-
except Exception as e:
|
|
80
|
-
log_error(f"Error processing webhook: {str(e)}")
|
|
81
|
-
raise HTTPException(status_code=500, detail=str(e))
|
|
82
|
-
|
|
83
|
-
def process_message(message: dict, agent: Optional[Agent], team: Optional[Team]):
|
|
84
|
-
"""Process a single WhatsApp message in the background"""
|
|
85
|
-
try:
|
|
86
|
-
message_image = None
|
|
87
|
-
message_video = None
|
|
88
|
-
message_audio = None
|
|
89
|
-
message_doc = None
|
|
90
|
-
|
|
91
|
-
message_id = message.get("id")
|
|
92
|
-
typing_indicator(message_id)
|
|
93
|
-
|
|
94
|
-
if message.get("type") == "text":
|
|
95
|
-
message_text = message["text"]["body"]
|
|
96
|
-
elif message.get("type") == "image":
|
|
97
|
-
try:
|
|
98
|
-
message_text = message["image"]["caption"]
|
|
99
|
-
except Exception:
|
|
100
|
-
message_text = "Describe the image"
|
|
101
|
-
message_image = message["image"]["id"]
|
|
102
|
-
elif message.get("type") == "video":
|
|
103
|
-
try:
|
|
104
|
-
message_text = message["video"]["caption"]
|
|
105
|
-
except Exception:
|
|
106
|
-
message_text = "Describe the video"
|
|
107
|
-
message_video = message["video"]["id"]
|
|
108
|
-
elif message.get("type") == "audio":
|
|
109
|
-
message_text = "Reply to audio"
|
|
110
|
-
message_audio = message["audio"]["id"]
|
|
111
|
-
elif message.get("type") == "document":
|
|
112
|
-
message_text = "Process the document"
|
|
113
|
-
message_doc = message["document"]["id"]
|
|
114
|
-
else:
|
|
115
|
-
return
|
|
116
|
-
|
|
117
|
-
phone_number = message.get("from", "")
|
|
118
|
-
log_debug(f"Processing message from {phone_number}: {message_text}")
|
|
119
|
-
|
|
120
|
-
# Generate and send response
|
|
121
|
-
if agent:
|
|
122
|
-
response = agent.run(
|
|
123
|
-
message_text,
|
|
124
|
-
user_id=phone_number,
|
|
125
|
-
images=[Image(content=get_media(message_image))] if message_image else None,
|
|
126
|
-
files=[File(content=get_media(message_doc))] if message_doc else None,
|
|
127
|
-
videos=[Video(content=get_media(message_video))] if message_video else None,
|
|
128
|
-
audio=[Audio(content=get_media(message_audio))] if message_audio else None,
|
|
129
|
-
)
|
|
130
|
-
elif team:
|
|
131
|
-
response = team.run( # type: ignore
|
|
132
|
-
message_text,
|
|
133
|
-
user_id=phone_number,
|
|
134
|
-
files=[File(content=get_media(message_doc))] if message_doc else None,
|
|
135
|
-
images=[Image(content=get_media(message_image))] if message_image else None,
|
|
136
|
-
videos=[Video(content=get_media(message_video))] if message_video else None,
|
|
137
|
-
audio=[Audio(content=get_media(message_audio))] if message_audio else None,
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
if response.reasoning_content:
|
|
141
|
-
_send_whatsapp_message(phone_number, f"Reasoning: \n{response.reasoning_content}", italics=True)
|
|
142
|
-
|
|
143
|
-
if response.images:
|
|
144
|
-
number_of_images = len(response.images)
|
|
145
|
-
log_info(f"images generated: f{number_of_images}")
|
|
146
|
-
for i in range(number_of_images):
|
|
147
|
-
image_content = response.images[0].content
|
|
148
|
-
image_bytes = None
|
|
149
|
-
if isinstance(image_content, bytes):
|
|
150
|
-
try:
|
|
151
|
-
decoded_string = image_content.decode("utf-8")
|
|
152
|
-
|
|
153
|
-
image_bytes = base64.b64decode(decoded_string)
|
|
154
|
-
except UnicodeDecodeError:
|
|
155
|
-
image_bytes = image_content
|
|
156
|
-
elif isinstance(image_content, str):
|
|
157
|
-
image_bytes = base64.b64decode(image_content)
|
|
158
|
-
else:
|
|
159
|
-
log_error(f"Unexpected image content type: {type(image_content)} for user {phone_number}")
|
|
160
|
-
|
|
161
|
-
if image_bytes:
|
|
162
|
-
media_id = upload_media(media_data=image_bytes, mime_type="image/png", filename="image.png")
|
|
163
|
-
send_image_message(media_id=media_id, recipient=phone_number, text=response.content)
|
|
164
|
-
else:
|
|
165
|
-
log_warning(
|
|
166
|
-
f"Could not process image content for user {phone_number}. Type: {type(image_content)}"
|
|
167
|
-
)
|
|
168
|
-
_send_whatsapp_message(phone_number, response.content or "")
|
|
169
|
-
else:
|
|
170
|
-
_send_whatsapp_message(phone_number, response.content or "")
|
|
171
|
-
|
|
172
|
-
except Exception as e:
|
|
173
|
-
log_error(f"Error processing message: {str(e)}")
|
|
174
|
-
# Optionally send an error message to the user
|
|
175
|
-
try:
|
|
176
|
-
_send_whatsapp_message(
|
|
177
|
-
phone_number, "Sorry, there was an error processing your message. Please try again later."
|
|
178
|
-
)
|
|
179
|
-
except Exception as send_error:
|
|
180
|
-
log_error(f"Error sending error message: {str(send_error)}")
|
|
181
|
-
|
|
182
|
-
def _send_whatsapp_message(recipient: str, message: str, italics: bool = False):
|
|
183
|
-
if len(message) <= 4096:
|
|
184
|
-
WhatsAppTools().send_text_message_sync(recipient=recipient, text=f"_{message}_" if italics else message)
|
|
185
|
-
return
|
|
186
|
-
|
|
187
|
-
# Split message into batches of 4000 characters (WhatsApp message limit is 4096)
|
|
188
|
-
message_batches = [message[i : i + 4000] for i in range(0, len(message), 4000)]
|
|
189
|
-
|
|
190
|
-
# Add a prefix with the batch number
|
|
191
|
-
for i, batch in enumerate(message_batches, 1):
|
|
192
|
-
batch_message = f"[{i}/{len(message_batches)}] {batch}"
|
|
193
|
-
WhatsAppTools().send_text_message_sync(
|
|
194
|
-
recipient=recipient, text=f"_{batch_message}_" if italics else batch_message
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
return router
|