agno 1.8.1__py3-none-any.whl → 2.0.0a1__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 +2778 -4123
- agno/api/agent.py +9 -65
- agno/api/api.py +5 -46
- agno/api/evals.py +6 -17
- 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 +9 -64
- 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 +1749 -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 +1438 -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 +888 -0
- agno/db/in_memory/utils.py +172 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1051 -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 +1417 -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 +298 -0
- agno/db/postgres/__init__.py +3 -0
- agno/db/postgres/postgres.py +1720 -0
- agno/db/postgres/schemas.py +124 -0
- agno/db/postgres/utils.py +281 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +1371 -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 +1722 -0
- agno/db/singlestore/utils.py +327 -0
- agno/db/sqlite/__init__.py +3 -0
- agno/db/sqlite/schemas.py +119 -0
- agno/db/sqlite/sqlite.py +1680 -0
- agno/db/sqlite/utils.py +269 -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 +10 -10
- 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 +129 -82
- 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 +38 -144
- 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 +393 -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 +65 -28
- 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 +33 -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 +30 -0
- agno/os/router.py +843 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +204 -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 +413 -0
- agno/os/routers/knowledge/schemas.py +118 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +179 -0
- agno/os/routers/memory/schemas.py +58 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +58 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +163 -0
- agno/os/schema.py +892 -0
- agno/{app/playground → os}/settings.py +8 -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} +144 -72
- agno/run/base.py +44 -58
- agno/run/cancel.py +83 -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 +2961 -4253
- 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 +68 -17
- 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 +18 -33
- 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/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 +6 -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/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 +2394 -696
- agno-2.0.0a1.dist-info/METADATA +355 -0
- agno-2.0.0a1.dist-info/RECORD +514 -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.0a1.dist-info}/WHEEL +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
- {agno-1.8.1.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
|
@@ -1,1050 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
from io import BytesIO
|
|
3
|
-
from typing import Any, AsyncGenerator, Dict, List, Optional, cast
|
|
4
|
-
from uuid import uuid4
|
|
5
|
-
|
|
6
|
-
from fastapi import APIRouter, File, Form, HTTPException, Query, UploadFile
|
|
7
|
-
from fastapi.responses import JSONResponse, StreamingResponse
|
|
8
|
-
|
|
9
|
-
from agno.agent.agent import Agent, RunResponse
|
|
10
|
-
from agno.app.playground.operator import (
|
|
11
|
-
format_tools,
|
|
12
|
-
get_agent_by_id,
|
|
13
|
-
get_session_title,
|
|
14
|
-
get_session_title_from_team_session,
|
|
15
|
-
get_session_title_from_workflow_session,
|
|
16
|
-
get_team_by_id,
|
|
17
|
-
get_workflow_by_id,
|
|
18
|
-
)
|
|
19
|
-
from agno.app.playground.schemas import (
|
|
20
|
-
AgentGetResponse,
|
|
21
|
-
AgentModel,
|
|
22
|
-
AgentRenameRequest,
|
|
23
|
-
AgentSessionsResponse,
|
|
24
|
-
MemoryResponse,
|
|
25
|
-
TeamGetResponse,
|
|
26
|
-
TeamRenameRequest,
|
|
27
|
-
TeamSessionResponse,
|
|
28
|
-
WorkflowGetResponse,
|
|
29
|
-
WorkflowRenameRequest,
|
|
30
|
-
WorkflowRunRequest,
|
|
31
|
-
WorkflowSessionResponse,
|
|
32
|
-
WorkflowsGetResponse,
|
|
33
|
-
)
|
|
34
|
-
from agno.app.playground.utils import process_audio, process_document, process_image, process_video
|
|
35
|
-
from agno.media import Audio, Image, Video
|
|
36
|
-
from agno.media import File as FileMedia
|
|
37
|
-
from agno.memory.agent import AgentMemory
|
|
38
|
-
from agno.memory.v2 import Memory
|
|
39
|
-
from agno.run.response import RunResponseErrorEvent, RunResponseEvent
|
|
40
|
-
from agno.run.team import RunResponseErrorEvent as TeamRunResponseErrorEvent
|
|
41
|
-
from agno.run.v2.workflow import WorkflowErrorEvent
|
|
42
|
-
from agno.storage.session.agent import AgentSession
|
|
43
|
-
from agno.storage.session.team import TeamSession
|
|
44
|
-
from agno.storage.session.workflow import WorkflowSession
|
|
45
|
-
from agno.team.team import Team
|
|
46
|
-
from agno.utils.log import logger
|
|
47
|
-
from agno.workflow.v2.workflow import Workflow as WorkflowV2
|
|
48
|
-
from agno.workflow.workflow import Workflow
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
async def chat_response_streamer(
|
|
52
|
-
agent: Agent,
|
|
53
|
-
message: str,
|
|
54
|
-
session_id: Optional[str] = None,
|
|
55
|
-
user_id: Optional[str] = None,
|
|
56
|
-
images: Optional[List[Image]] = None,
|
|
57
|
-
audio: Optional[List[Audio]] = None,
|
|
58
|
-
videos: Optional[List[Video]] = None,
|
|
59
|
-
files: Optional[List[FileMedia]] = None,
|
|
60
|
-
) -> AsyncGenerator:
|
|
61
|
-
try:
|
|
62
|
-
run_response = await agent.arun(
|
|
63
|
-
message,
|
|
64
|
-
session_id=session_id,
|
|
65
|
-
user_id=user_id,
|
|
66
|
-
images=images,
|
|
67
|
-
audio=audio,
|
|
68
|
-
videos=videos,
|
|
69
|
-
files=files,
|
|
70
|
-
stream=True,
|
|
71
|
-
stream_intermediate_steps=True,
|
|
72
|
-
)
|
|
73
|
-
async for run_response_chunk in run_response:
|
|
74
|
-
yield run_response_chunk.to_json()
|
|
75
|
-
except Exception as e:
|
|
76
|
-
import traceback
|
|
77
|
-
|
|
78
|
-
traceback.print_exc(limit=3)
|
|
79
|
-
error_response = RunResponseErrorEvent(
|
|
80
|
-
content=str(e),
|
|
81
|
-
)
|
|
82
|
-
yield error_response.to_json()
|
|
83
|
-
return
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
async def agent_acontinue_run_streamer(
|
|
87
|
-
agent: Agent,
|
|
88
|
-
run_id: Optional[str] = None,
|
|
89
|
-
updated_tools: Optional[List] = None,
|
|
90
|
-
session_id: Optional[str] = None,
|
|
91
|
-
user_id: Optional[str] = None,
|
|
92
|
-
) -> AsyncGenerator:
|
|
93
|
-
try:
|
|
94
|
-
continue_response = await agent.acontinue_run(
|
|
95
|
-
run_id=run_id,
|
|
96
|
-
updated_tools=updated_tools,
|
|
97
|
-
session_id=session_id,
|
|
98
|
-
user_id=user_id,
|
|
99
|
-
stream=True,
|
|
100
|
-
stream_intermediate_steps=True,
|
|
101
|
-
)
|
|
102
|
-
async for run_response_chunk in continue_response:
|
|
103
|
-
run_response_chunk = cast(RunResponseEvent, run_response_chunk)
|
|
104
|
-
yield run_response_chunk.to_json()
|
|
105
|
-
except Exception as e:
|
|
106
|
-
import traceback
|
|
107
|
-
|
|
108
|
-
traceback.print_exc(limit=3)
|
|
109
|
-
error_response = RunResponseErrorEvent(
|
|
110
|
-
content=str(e),
|
|
111
|
-
)
|
|
112
|
-
yield error_response.to_json()
|
|
113
|
-
return
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
async def team_chat_response_streamer(
|
|
117
|
-
team: Team,
|
|
118
|
-
message: str,
|
|
119
|
-
session_id: Optional[str] = None,
|
|
120
|
-
user_id: Optional[str] = None,
|
|
121
|
-
images: Optional[List[Image]] = None,
|
|
122
|
-
audio: Optional[List[Audio]] = None,
|
|
123
|
-
videos: Optional[List[Video]] = None,
|
|
124
|
-
files: Optional[List[FileMedia]] = None,
|
|
125
|
-
) -> AsyncGenerator:
|
|
126
|
-
try:
|
|
127
|
-
run_response = await team.arun(
|
|
128
|
-
message,
|
|
129
|
-
session_id=session_id,
|
|
130
|
-
user_id=user_id,
|
|
131
|
-
images=images,
|
|
132
|
-
audio=audio,
|
|
133
|
-
videos=videos,
|
|
134
|
-
files=files,
|
|
135
|
-
stream=True,
|
|
136
|
-
stream_intermediate_steps=True,
|
|
137
|
-
)
|
|
138
|
-
async for run_response_chunk in run_response:
|
|
139
|
-
yield run_response_chunk.to_json()
|
|
140
|
-
except Exception as e:
|
|
141
|
-
import traceback
|
|
142
|
-
|
|
143
|
-
traceback.print_exc()
|
|
144
|
-
error_response = TeamRunResponseErrorEvent(
|
|
145
|
-
content=str(e),
|
|
146
|
-
)
|
|
147
|
-
yield error_response.to_json()
|
|
148
|
-
return
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
async def workflow_response_streamer(
|
|
152
|
-
workflow: WorkflowV2,
|
|
153
|
-
body: WorkflowRunRequest,
|
|
154
|
-
) -> AsyncGenerator:
|
|
155
|
-
try:
|
|
156
|
-
run_response = await workflow.arun(
|
|
157
|
-
**body.input,
|
|
158
|
-
user_id=body.user_id,
|
|
159
|
-
session_id=body.session_id or str(uuid4()),
|
|
160
|
-
stream=True,
|
|
161
|
-
stream_intermediate_steps=True,
|
|
162
|
-
)
|
|
163
|
-
async for run_response_chunk in run_response:
|
|
164
|
-
yield run_response_chunk.to_json()
|
|
165
|
-
except Exception as e:
|
|
166
|
-
import traceback
|
|
167
|
-
|
|
168
|
-
traceback.print_exc(limit=3)
|
|
169
|
-
error_response = WorkflowErrorEvent(
|
|
170
|
-
error=str(e),
|
|
171
|
-
)
|
|
172
|
-
yield error_response.to_json()
|
|
173
|
-
return
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
def get_async_playground_router(
|
|
177
|
-
agents: Optional[List[Agent]] = None,
|
|
178
|
-
workflows: Optional[List[Workflow]] = None,
|
|
179
|
-
teams: Optional[List[Team]] = None,
|
|
180
|
-
active_app_id: Optional[str] = None,
|
|
181
|
-
) -> APIRouter:
|
|
182
|
-
playground_router = APIRouter(prefix="/playground", tags=["Playground"])
|
|
183
|
-
|
|
184
|
-
if agents is None and workflows is None and teams is None:
|
|
185
|
-
raise ValueError("Either agents, teams or workflows must be provided.")
|
|
186
|
-
|
|
187
|
-
@playground_router.get("/status")
|
|
188
|
-
async def playground_status(app_id: Optional[str] = None):
|
|
189
|
-
if app_id is None:
|
|
190
|
-
return {"playground": "available"}
|
|
191
|
-
else:
|
|
192
|
-
if active_app_id == app_id:
|
|
193
|
-
return {"playground": "available"}
|
|
194
|
-
else:
|
|
195
|
-
raise HTTPException(status_code=404, detail="Playground not available")
|
|
196
|
-
|
|
197
|
-
@playground_router.get("/agents", response_model=List[AgentGetResponse])
|
|
198
|
-
async def get_agents():
|
|
199
|
-
agent_list: List[AgentGetResponse] = []
|
|
200
|
-
if agents is None:
|
|
201
|
-
return agent_list
|
|
202
|
-
|
|
203
|
-
for agent in agents:
|
|
204
|
-
agent_tools = agent.get_tools(session_id=str(uuid4()), async_mode=True)
|
|
205
|
-
formatted_tools = format_tools(agent_tools)
|
|
206
|
-
|
|
207
|
-
name = agent.model.name or agent.model.__class__.__name__ if agent.model else None
|
|
208
|
-
provider = agent.model.provider or agent.model.__class__.__name__ if agent.model else ""
|
|
209
|
-
model_id = agent.model.id if agent.model else None
|
|
210
|
-
|
|
211
|
-
# Create an agent_id if its not set on the agent
|
|
212
|
-
if agent.agent_id is None:
|
|
213
|
-
agent.set_agent_id()
|
|
214
|
-
|
|
215
|
-
if provider and model_id:
|
|
216
|
-
provider = f"{provider} {model_id}"
|
|
217
|
-
elif name and model_id:
|
|
218
|
-
provider = f"{name} {model_id}"
|
|
219
|
-
elif model_id:
|
|
220
|
-
provider = model_id
|
|
221
|
-
else:
|
|
222
|
-
provider = ""
|
|
223
|
-
|
|
224
|
-
if agent.memory:
|
|
225
|
-
memory_dict: Optional[Dict[str, Any]] = {}
|
|
226
|
-
if isinstance(agent.memory, AgentMemory) and agent.memory.db:
|
|
227
|
-
memory_dict = {"name": agent.memory.db.__class__.__name__}
|
|
228
|
-
elif isinstance(agent.memory, Memory) and agent.memory.db:
|
|
229
|
-
memory_dict = {"name": "Memory"}
|
|
230
|
-
if agent.memory.model is not None:
|
|
231
|
-
memory_dict["model"] = AgentModel(
|
|
232
|
-
name=agent.memory.model.name,
|
|
233
|
-
model=agent.memory.model.id,
|
|
234
|
-
provider=agent.memory.model.provider,
|
|
235
|
-
)
|
|
236
|
-
else:
|
|
237
|
-
memory_dict["model"] = AgentModel(
|
|
238
|
-
name=name,
|
|
239
|
-
model=model_id,
|
|
240
|
-
provider=provider,
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
if agent.memory.db is not None:
|
|
244
|
-
memory_dict["db"] = agent.memory.db.__dict__() # type: ignore
|
|
245
|
-
|
|
246
|
-
else:
|
|
247
|
-
memory_dict = None
|
|
248
|
-
else:
|
|
249
|
-
memory_dict = None
|
|
250
|
-
|
|
251
|
-
agent_list.append(
|
|
252
|
-
AgentGetResponse(
|
|
253
|
-
agent_id=agent.agent_id,
|
|
254
|
-
name=agent.name,
|
|
255
|
-
model=AgentModel(
|
|
256
|
-
name=name,
|
|
257
|
-
model=model_id,
|
|
258
|
-
provider=provider,
|
|
259
|
-
),
|
|
260
|
-
add_context=agent.add_context,
|
|
261
|
-
tools=formatted_tools,
|
|
262
|
-
memory=memory_dict,
|
|
263
|
-
storage={"name": agent.storage.__class__.__name__} if agent.storage else None,
|
|
264
|
-
knowledge={"name": agent.knowledge.__class__.__name__} if agent.knowledge else None,
|
|
265
|
-
description=agent.description,
|
|
266
|
-
instructions=agent.instructions,
|
|
267
|
-
)
|
|
268
|
-
)
|
|
269
|
-
|
|
270
|
-
return agent_list
|
|
271
|
-
|
|
272
|
-
@playground_router.post("/agents/{agent_id}/runs")
|
|
273
|
-
async def create_agent_run(
|
|
274
|
-
agent_id: str,
|
|
275
|
-
message: str = Form(...),
|
|
276
|
-
stream: bool = Form(True),
|
|
277
|
-
monitor: bool = Form(False),
|
|
278
|
-
session_id: Optional[str] = Form(None),
|
|
279
|
-
user_id: Optional[str] = Form(None),
|
|
280
|
-
files: Optional[List[UploadFile]] = File(None),
|
|
281
|
-
):
|
|
282
|
-
logger.debug(f"AgentRunRequest: {message} {session_id} {user_id} {agent_id}")
|
|
283
|
-
agent = get_agent_by_id(agent_id, agents)
|
|
284
|
-
if agent is None:
|
|
285
|
-
raise HTTPException(status_code=404, detail="Agent not found")
|
|
286
|
-
|
|
287
|
-
if session_id is not None and session_id != "":
|
|
288
|
-
logger.debug(f"Continuing session: {session_id}")
|
|
289
|
-
else:
|
|
290
|
-
logger.debug("Creating new session")
|
|
291
|
-
session_id = str(uuid4())
|
|
292
|
-
|
|
293
|
-
if monitor:
|
|
294
|
-
agent.monitoring = True
|
|
295
|
-
else:
|
|
296
|
-
agent.monitoring = False
|
|
297
|
-
|
|
298
|
-
base64_images: List[Image] = []
|
|
299
|
-
base64_audios: List[Audio] = []
|
|
300
|
-
base64_videos: List[Video] = []
|
|
301
|
-
input_files: List[FileMedia] = []
|
|
302
|
-
|
|
303
|
-
if files:
|
|
304
|
-
for file in files:
|
|
305
|
-
logger.info(f"Processing file: {file.content_type}")
|
|
306
|
-
if file.content_type in ["image/png", "image/jpeg", "image/jpg", "image/webp"]:
|
|
307
|
-
try:
|
|
308
|
-
base64_image = process_image(file)
|
|
309
|
-
base64_images.append(base64_image)
|
|
310
|
-
except Exception as e:
|
|
311
|
-
logger.error(f"Error processing image {file.filename}: {e}")
|
|
312
|
-
continue
|
|
313
|
-
elif file.content_type in ["audio/wav", "audio/mp3", "audio/mpeg"]:
|
|
314
|
-
try:
|
|
315
|
-
base64_audio = process_audio(file)
|
|
316
|
-
base64_audios.append(base64_audio)
|
|
317
|
-
except Exception as e:
|
|
318
|
-
logger.error(f"Error processing audio {file.filename}: {e}")
|
|
319
|
-
continue
|
|
320
|
-
elif file.content_type in [
|
|
321
|
-
"video/x-flv",
|
|
322
|
-
"video/quicktime",
|
|
323
|
-
"video/mpeg",
|
|
324
|
-
"video/mpegs",
|
|
325
|
-
"video/mpgs",
|
|
326
|
-
"video/mpg",
|
|
327
|
-
"video/mpg",
|
|
328
|
-
"video/mp4",
|
|
329
|
-
"video/webm",
|
|
330
|
-
"video/wmv",
|
|
331
|
-
"video/3gpp",
|
|
332
|
-
]:
|
|
333
|
-
try:
|
|
334
|
-
base64_video = process_video(file)
|
|
335
|
-
base64_videos.append(base64_video)
|
|
336
|
-
except Exception as e:
|
|
337
|
-
logger.error(f"Error processing video {file.filename}: {e}")
|
|
338
|
-
continue
|
|
339
|
-
else:
|
|
340
|
-
# Process document files
|
|
341
|
-
if file.content_type == "application/pdf":
|
|
342
|
-
from agno.document.reader.pdf_reader import PDFReader
|
|
343
|
-
|
|
344
|
-
contents = await file.read()
|
|
345
|
-
|
|
346
|
-
# If agent has knowledge base, load the document into it
|
|
347
|
-
if agent.knowledge is not None:
|
|
348
|
-
pdf_file = BytesIO(contents)
|
|
349
|
-
pdf_file.name = file.filename
|
|
350
|
-
file_content = PDFReader().read(pdf_file)
|
|
351
|
-
agent.knowledge.load_documents(file_content)
|
|
352
|
-
else:
|
|
353
|
-
# If no knowledge base, treat as direct file input (similar to cookbook examples)
|
|
354
|
-
input_files.append(FileMedia(content=contents))
|
|
355
|
-
|
|
356
|
-
elif file.content_type == "text/csv":
|
|
357
|
-
from agno.document.reader.csv_reader import CSVReader
|
|
358
|
-
|
|
359
|
-
contents = await file.read()
|
|
360
|
-
|
|
361
|
-
# If agent has knowledge base, load the document into it
|
|
362
|
-
if agent.knowledge is not None:
|
|
363
|
-
csv_file = BytesIO(contents)
|
|
364
|
-
csv_file.name = file.filename
|
|
365
|
-
file_content = CSVReader().read(csv_file)
|
|
366
|
-
agent.knowledge.load_documents(file_content)
|
|
367
|
-
else:
|
|
368
|
-
# If no knowledge base, treat as direct file input
|
|
369
|
-
input_files.append(FileMedia(content=contents))
|
|
370
|
-
|
|
371
|
-
elif file.content_type == "application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
|
372
|
-
from agno.document.reader.docx_reader import DocxReader
|
|
373
|
-
|
|
374
|
-
contents = await file.read()
|
|
375
|
-
|
|
376
|
-
# If agent has knowledge base, load the document into it
|
|
377
|
-
if agent.knowledge is not None:
|
|
378
|
-
docx_file = BytesIO(contents)
|
|
379
|
-
docx_file.name = file.filename
|
|
380
|
-
file_content = DocxReader().read(docx_file)
|
|
381
|
-
agent.knowledge.load_documents(file_content)
|
|
382
|
-
else:
|
|
383
|
-
# If no knowledge base, treat as direct file input
|
|
384
|
-
input_files.append(FileMedia(content=contents))
|
|
385
|
-
|
|
386
|
-
elif file.content_type == "text/plain":
|
|
387
|
-
from agno.document.reader.text_reader import TextReader
|
|
388
|
-
|
|
389
|
-
contents = await file.read()
|
|
390
|
-
|
|
391
|
-
# If agent has knowledge base, load the document into it
|
|
392
|
-
if agent.knowledge is not None:
|
|
393
|
-
text_file = BytesIO(contents)
|
|
394
|
-
text_file.name = file.filename
|
|
395
|
-
file_content = TextReader().read(text_file)
|
|
396
|
-
agent.knowledge.load_documents(file_content)
|
|
397
|
-
else:
|
|
398
|
-
# If no knowledge base, treat as direct file input
|
|
399
|
-
input_files.append(FileMedia(content=contents))
|
|
400
|
-
|
|
401
|
-
elif file.content_type == "application/json":
|
|
402
|
-
from agno.document.reader.json_reader import JSONReader
|
|
403
|
-
|
|
404
|
-
contents = await file.read()
|
|
405
|
-
|
|
406
|
-
# If agent has knowledge base, load the document into it
|
|
407
|
-
if agent.knowledge is not None:
|
|
408
|
-
json_file = BytesIO(contents)
|
|
409
|
-
json_file.name = file.filename
|
|
410
|
-
file_content = JSONReader().read(json_file)
|
|
411
|
-
agent.knowledge.load_documents(file_content)
|
|
412
|
-
else:
|
|
413
|
-
# If no knowledge base, treat as direct file input
|
|
414
|
-
input_files.append(FileMedia(content=contents))
|
|
415
|
-
else:
|
|
416
|
-
raise HTTPException(status_code=400, detail="Unsupported file type")
|
|
417
|
-
|
|
418
|
-
if stream:
|
|
419
|
-
return StreamingResponse(
|
|
420
|
-
chat_response_streamer(
|
|
421
|
-
agent,
|
|
422
|
-
message,
|
|
423
|
-
session_id=session_id,
|
|
424
|
-
user_id=user_id,
|
|
425
|
-
images=base64_images if base64_images else None,
|
|
426
|
-
audio=base64_audios if base64_audios else None,
|
|
427
|
-
videos=base64_videos if base64_videos else None,
|
|
428
|
-
files=input_files if input_files else None,
|
|
429
|
-
),
|
|
430
|
-
media_type="text/event-stream",
|
|
431
|
-
)
|
|
432
|
-
else:
|
|
433
|
-
run_response = cast(
|
|
434
|
-
RunResponse,
|
|
435
|
-
await agent.arun(
|
|
436
|
-
message=message,
|
|
437
|
-
session_id=session_id,
|
|
438
|
-
user_id=user_id,
|
|
439
|
-
images=base64_images if base64_images else None,
|
|
440
|
-
audio=base64_audios if base64_audios else None,
|
|
441
|
-
videos=base64_videos if base64_videos else None,
|
|
442
|
-
files=input_files if input_files else None,
|
|
443
|
-
stream=False,
|
|
444
|
-
),
|
|
445
|
-
)
|
|
446
|
-
return run_response.to_dict()
|
|
447
|
-
|
|
448
|
-
@playground_router.post("/agents/{agent_id}/runs/{run_id}/continue")
|
|
449
|
-
async def continue_agent_run(
|
|
450
|
-
agent_id: str,
|
|
451
|
-
run_id: str,
|
|
452
|
-
tools: str = Form(...), # JSON string of tools
|
|
453
|
-
session_id: Optional[str] = Form(None),
|
|
454
|
-
user_id: Optional[str] = Form(None),
|
|
455
|
-
stream: bool = Form(True),
|
|
456
|
-
):
|
|
457
|
-
# Parse the JSON string manually
|
|
458
|
-
try:
|
|
459
|
-
tools_data = json.loads(tools) if tools else None
|
|
460
|
-
except json.JSONDecodeError:
|
|
461
|
-
raise HTTPException(status_code=400, detail="Invalid JSON in tools field")
|
|
462
|
-
|
|
463
|
-
logger.debug(
|
|
464
|
-
f"AgentContinueRunRequest: run_id={run_id} session_id={session_id} user_id={user_id} agent_id={agent_id}"
|
|
465
|
-
)
|
|
466
|
-
agent = get_agent_by_id(agent_id, agents)
|
|
467
|
-
if agent is None:
|
|
468
|
-
raise HTTPException(status_code=404, detail="Agent not found")
|
|
469
|
-
|
|
470
|
-
if session_id is None or session_id == "":
|
|
471
|
-
logger.warning(
|
|
472
|
-
"Continuing run without session_id. This might lead to unexpected behavior if session context is important."
|
|
473
|
-
)
|
|
474
|
-
else:
|
|
475
|
-
logger.debug(f"Continuing run within session: {session_id}")
|
|
476
|
-
|
|
477
|
-
# Convert tools dict to ToolExecution objects if provided
|
|
478
|
-
updated_tools = None
|
|
479
|
-
if tools_data:
|
|
480
|
-
try:
|
|
481
|
-
from agno.models.response import ToolExecution
|
|
482
|
-
|
|
483
|
-
updated_tools = [ToolExecution.from_dict(tool) for tool in tools_data]
|
|
484
|
-
except Exception as e:
|
|
485
|
-
raise HTTPException(status_code=400, detail=f"Invalid structure or content for tools: {str(e)}")
|
|
486
|
-
|
|
487
|
-
if stream:
|
|
488
|
-
return StreamingResponse(
|
|
489
|
-
agent_acontinue_run_streamer(
|
|
490
|
-
agent,
|
|
491
|
-
run_id=run_id, # run_id from path
|
|
492
|
-
updated_tools=updated_tools,
|
|
493
|
-
session_id=session_id,
|
|
494
|
-
user_id=user_id,
|
|
495
|
-
),
|
|
496
|
-
media_type="text/event-stream",
|
|
497
|
-
)
|
|
498
|
-
else:
|
|
499
|
-
run_response_obj = cast(
|
|
500
|
-
RunResponse,
|
|
501
|
-
await agent.acontinue_run(
|
|
502
|
-
run_id=run_id, # run_id from path
|
|
503
|
-
updated_tools=updated_tools,
|
|
504
|
-
session_id=session_id,
|
|
505
|
-
user_id=user_id,
|
|
506
|
-
stream=False,
|
|
507
|
-
),
|
|
508
|
-
)
|
|
509
|
-
return run_response_obj.to_dict()
|
|
510
|
-
|
|
511
|
-
@playground_router.get("/agents/{agent_id}/sessions")
|
|
512
|
-
async def get_all_agent_sessions(agent_id: str, user_id: Optional[str] = Query(None, min_length=1)):
|
|
513
|
-
logger.debug(f"AgentSessionsRequest: {agent_id} {user_id}")
|
|
514
|
-
agent = get_agent_by_id(agent_id, agents)
|
|
515
|
-
if agent is None:
|
|
516
|
-
return JSONResponse(status_code=404, content="Agent not found.")
|
|
517
|
-
|
|
518
|
-
if agent.storage is None:
|
|
519
|
-
return JSONResponse(status_code=404, content="Agent does not have storage enabled.")
|
|
520
|
-
|
|
521
|
-
agent_sessions: List[AgentSessionsResponse] = []
|
|
522
|
-
all_agent_sessions: List[AgentSession] = agent.storage.get_all_sessions(user_id=user_id, entity_id=agent_id) # type: ignore
|
|
523
|
-
for session in all_agent_sessions:
|
|
524
|
-
title = get_session_title(session)
|
|
525
|
-
agent_sessions.append(
|
|
526
|
-
AgentSessionsResponse(
|
|
527
|
-
title=title,
|
|
528
|
-
session_id=session.session_id,
|
|
529
|
-
session_name=session.session_data.get("session_name") if session.session_data else None,
|
|
530
|
-
created_at=session.created_at,
|
|
531
|
-
)
|
|
532
|
-
)
|
|
533
|
-
return agent_sessions
|
|
534
|
-
|
|
535
|
-
@playground_router.get("/agents/{agent_id}/sessions/{session_id}")
|
|
536
|
-
async def get_agent_session(agent_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)):
|
|
537
|
-
logger.debug(f"AgentSessionsRequest: {agent_id} {user_id} {session_id}")
|
|
538
|
-
agent = get_agent_by_id(agent_id, agents)
|
|
539
|
-
if agent is None:
|
|
540
|
-
raise HTTPException(status_code=404, detail="Agent not found")
|
|
541
|
-
|
|
542
|
-
if agent.storage is None:
|
|
543
|
-
return JSONResponse(status_code=404, content="Agent does not have storage enabled.")
|
|
544
|
-
|
|
545
|
-
agent_session: Optional[AgentSession] = agent.storage.read(session_id, user_id) # type: ignore
|
|
546
|
-
if agent_session is None:
|
|
547
|
-
return JSONResponse(status_code=404, content="Session not found.")
|
|
548
|
-
|
|
549
|
-
agent_session_dict = agent_session.to_dict()
|
|
550
|
-
if agent_session.memory is not None:
|
|
551
|
-
runs = agent_session.memory.get("runs")
|
|
552
|
-
if runs is not None:
|
|
553
|
-
first_run = runs[0]
|
|
554
|
-
# This is how we know it is a RunResponse or RunPaused
|
|
555
|
-
if "content" in first_run or first_run.get("is_paused", False) or first_run.get("event") == "RunPaused":
|
|
556
|
-
agent_session_dict["runs"] = []
|
|
557
|
-
|
|
558
|
-
for run in runs:
|
|
559
|
-
first_user_message = None
|
|
560
|
-
for msg in run.get("messages", []):
|
|
561
|
-
if msg.get("role") == "user" and msg.get("from_history", False) is False:
|
|
562
|
-
first_user_message = msg
|
|
563
|
-
break
|
|
564
|
-
# Remove the memory from the response
|
|
565
|
-
run.pop("memory", None)
|
|
566
|
-
agent_session_dict["runs"].append(
|
|
567
|
-
{
|
|
568
|
-
"message": first_user_message,
|
|
569
|
-
"response": run,
|
|
570
|
-
}
|
|
571
|
-
)
|
|
572
|
-
return agent_session_dict
|
|
573
|
-
|
|
574
|
-
@playground_router.post("/agents/{agent_id}/sessions/{session_id}/rename")
|
|
575
|
-
async def rename_agent_session(agent_id: str, session_id: str, body: AgentRenameRequest):
|
|
576
|
-
agent = get_agent_by_id(agent_id, agents)
|
|
577
|
-
if agent is None:
|
|
578
|
-
return JSONResponse(status_code=404, content=f"couldn't find agent with {agent_id}")
|
|
579
|
-
|
|
580
|
-
if agent.storage is None:
|
|
581
|
-
return JSONResponse(status_code=404, content="Agent does not have storage enabled.")
|
|
582
|
-
|
|
583
|
-
all_agent_sessions: List[AgentSession] = agent.storage.get_all_sessions(user_id=body.user_id) # type: ignore
|
|
584
|
-
for session in all_agent_sessions:
|
|
585
|
-
if session.session_id == session_id:
|
|
586
|
-
agent.rename_session(body.name, session_id=session_id)
|
|
587
|
-
return JSONResponse(content={"message": f"successfully renamed session {session.session_id}"})
|
|
588
|
-
|
|
589
|
-
return JSONResponse(status_code=404, content="Session not found.")
|
|
590
|
-
|
|
591
|
-
@playground_router.delete("/agents/{agent_id}/sessions/{session_id}")
|
|
592
|
-
async def delete_agent_session(agent_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)):
|
|
593
|
-
agent = get_agent_by_id(agent_id, agents)
|
|
594
|
-
if agent is None:
|
|
595
|
-
return JSONResponse(status_code=404, content="Agent not found.")
|
|
596
|
-
|
|
597
|
-
if agent.storage is None:
|
|
598
|
-
return JSONResponse(status_code=404, content="Agent does not have storage enabled.")
|
|
599
|
-
|
|
600
|
-
all_agent_sessions: List[AgentSession] = agent.storage.get_all_sessions(user_id=user_id, entity_id=agent_id) # type: ignore
|
|
601
|
-
for session in all_agent_sessions:
|
|
602
|
-
if session.session_id == session_id:
|
|
603
|
-
agent.delete_session(session_id)
|
|
604
|
-
return JSONResponse(content={"message": f"successfully deleted session {session_id}"})
|
|
605
|
-
|
|
606
|
-
return JSONResponse(status_code=404, content="Session not found.")
|
|
607
|
-
|
|
608
|
-
@playground_router.get("/agents/{agent_id}/memories")
|
|
609
|
-
async def get_agent_memories(agent_id: str, user_id: str = Query(..., min_length=1)):
|
|
610
|
-
agent = get_agent_by_id(agent_id, agents)
|
|
611
|
-
if agent is None:
|
|
612
|
-
return JSONResponse(status_code=404, content="Agent not found.")
|
|
613
|
-
|
|
614
|
-
if agent.memory is None:
|
|
615
|
-
return JSONResponse(status_code=404, content="Agent does not have memory enabled.")
|
|
616
|
-
|
|
617
|
-
if isinstance(agent.memory, Memory):
|
|
618
|
-
memories = agent.memory.get_user_memories(user_id=user_id)
|
|
619
|
-
return [
|
|
620
|
-
MemoryResponse(memory=memory.memory, topics=memory.topics, last_updated=memory.last_updated)
|
|
621
|
-
for memory in memories
|
|
622
|
-
]
|
|
623
|
-
else:
|
|
624
|
-
return []
|
|
625
|
-
|
|
626
|
-
@playground_router.get("/workflows", response_model=List[WorkflowsGetResponse])
|
|
627
|
-
async def get_workflows():
|
|
628
|
-
if workflows is None:
|
|
629
|
-
return []
|
|
630
|
-
|
|
631
|
-
return [
|
|
632
|
-
WorkflowsGetResponse(
|
|
633
|
-
workflow_id=str(workflow.workflow_id),
|
|
634
|
-
name=workflow.name,
|
|
635
|
-
description=workflow.description,
|
|
636
|
-
)
|
|
637
|
-
for workflow in workflows
|
|
638
|
-
]
|
|
639
|
-
|
|
640
|
-
@playground_router.get("/workflows/{workflow_id}", response_model=WorkflowGetResponse)
|
|
641
|
-
async def get_workflow(workflow_id: str):
|
|
642
|
-
workflow = get_workflow_by_id(workflow_id, workflows)
|
|
643
|
-
if workflow is None:
|
|
644
|
-
raise HTTPException(status_code=404, detail="Workflow not found")
|
|
645
|
-
|
|
646
|
-
if isinstance(workflow, Workflow):
|
|
647
|
-
return WorkflowGetResponse(
|
|
648
|
-
workflow_id=workflow.workflow_id,
|
|
649
|
-
name=workflow.name,
|
|
650
|
-
description=workflow.description,
|
|
651
|
-
parameters=workflow._run_parameters or {},
|
|
652
|
-
storage=workflow.storage.__class__.__name__ if workflow.storage else None,
|
|
653
|
-
)
|
|
654
|
-
else:
|
|
655
|
-
return WorkflowGetResponse(
|
|
656
|
-
workflow_id=workflow.workflow_id,
|
|
657
|
-
name=workflow.name,
|
|
658
|
-
description=workflow.description,
|
|
659
|
-
parameters=workflow.run_parameters,
|
|
660
|
-
storage=workflow.storage.__class__.__name__ if workflow.storage else None,
|
|
661
|
-
)
|
|
662
|
-
|
|
663
|
-
@playground_router.post("/workflows/{workflow_id}/runs")
|
|
664
|
-
async def create_workflow_run(workflow_id: str, body: WorkflowRunRequest):
|
|
665
|
-
# Retrieve the workflow by ID
|
|
666
|
-
workflow = get_workflow_by_id(workflow_id, workflows)
|
|
667
|
-
if workflow is None:
|
|
668
|
-
raise HTTPException(status_code=404, detail="Workflow not found")
|
|
669
|
-
|
|
670
|
-
if body.session_id is not None:
|
|
671
|
-
logger.debug(f"Continuing session: {body.session_id}")
|
|
672
|
-
else:
|
|
673
|
-
logger.debug("Creating new session")
|
|
674
|
-
|
|
675
|
-
# Create a new instance of this workflow
|
|
676
|
-
if isinstance(workflow, Workflow):
|
|
677
|
-
new_workflow_instance = workflow.deep_copy(
|
|
678
|
-
update={"workflow_id": workflow_id, "session_id": body.session_id}
|
|
679
|
-
)
|
|
680
|
-
new_workflow_instance.user_id = body.user_id
|
|
681
|
-
new_workflow_instance.session_name = None
|
|
682
|
-
|
|
683
|
-
# Return based on the response type
|
|
684
|
-
try:
|
|
685
|
-
if new_workflow_instance._run_return_type == "RunResponse":
|
|
686
|
-
# Return as a normal response
|
|
687
|
-
return new_workflow_instance.run(**body.input)
|
|
688
|
-
else:
|
|
689
|
-
# Return as a streaming response
|
|
690
|
-
return StreamingResponse(
|
|
691
|
-
(result.to_json() for result in new_workflow_instance.run(**body.input)),
|
|
692
|
-
media_type="text/event-stream",
|
|
693
|
-
headers={
|
|
694
|
-
"Access-Control-Allow-Origin": "*",
|
|
695
|
-
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
696
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
697
|
-
},
|
|
698
|
-
)
|
|
699
|
-
except Exception as e:
|
|
700
|
-
# Handle unexpected runtime errors
|
|
701
|
-
raise HTTPException(status_code=500, detail=f"Error running workflow: {str(e)}")
|
|
702
|
-
else:
|
|
703
|
-
# Return based on the response type
|
|
704
|
-
try:
|
|
705
|
-
if body.stream:
|
|
706
|
-
# Return as a streaming response
|
|
707
|
-
return StreamingResponse(
|
|
708
|
-
workflow_response_streamer(workflow, body),
|
|
709
|
-
media_type="text/event-stream",
|
|
710
|
-
headers={
|
|
711
|
-
"Access-Control-Allow-Origin": "*",
|
|
712
|
-
"Access-Control-Allow-Methods": "POST, OPTIONS",
|
|
713
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
714
|
-
},
|
|
715
|
-
)
|
|
716
|
-
else:
|
|
717
|
-
# Return as a normal response
|
|
718
|
-
return await workflow.arun(
|
|
719
|
-
**body.input, session_id=body.session_id or str(uuid4()), user_id=body.user_id
|
|
720
|
-
)
|
|
721
|
-
except Exception as e:
|
|
722
|
-
# Handle unexpected runtime errors
|
|
723
|
-
raise HTTPException(status_code=500, detail=f"Error running workflow: {str(e)}")
|
|
724
|
-
|
|
725
|
-
@playground_router.get("/workflows/{workflow_id}/sessions")
|
|
726
|
-
async def get_all_workflow_sessions(workflow_id: str, user_id: Optional[str] = Query(None, min_length=1)):
|
|
727
|
-
# Retrieve the workflow by ID
|
|
728
|
-
workflow = get_workflow_by_id(workflow_id, workflows)
|
|
729
|
-
if not workflow:
|
|
730
|
-
raise HTTPException(status_code=404, detail="Workflow not found")
|
|
731
|
-
|
|
732
|
-
# Ensure storage is enabled for the workflow
|
|
733
|
-
if not workflow.storage:
|
|
734
|
-
raise HTTPException(status_code=404, detail="Workflow does not have storage enabled")
|
|
735
|
-
|
|
736
|
-
# Retrieve all sessions for the given workflow and user
|
|
737
|
-
try:
|
|
738
|
-
all_workflow_sessions: List[WorkflowSession] = workflow.storage.get_all_sessions(
|
|
739
|
-
user_id=user_id, entity_id=workflow_id
|
|
740
|
-
) # type: ignore
|
|
741
|
-
except Exception as e:
|
|
742
|
-
raise HTTPException(status_code=500, detail=f"Error retrieving sessions: {str(e)}")
|
|
743
|
-
|
|
744
|
-
# Return the sessions
|
|
745
|
-
workflow_sessions: List[WorkflowSessionResponse] = []
|
|
746
|
-
for session in all_workflow_sessions:
|
|
747
|
-
title = get_session_title_from_workflow_session(session)
|
|
748
|
-
workflow_sessions.append(
|
|
749
|
-
{
|
|
750
|
-
"title": title,
|
|
751
|
-
"session_id": session.session_id,
|
|
752
|
-
"session_name": session.session_data.get("session_name") if session.session_data else None,
|
|
753
|
-
"created_at": session.created_at,
|
|
754
|
-
} # type: ignore
|
|
755
|
-
)
|
|
756
|
-
return workflow_sessions
|
|
757
|
-
|
|
758
|
-
@playground_router.get("/workflows/{workflow_id}/sessions/{session_id}")
|
|
759
|
-
async def get_workflow_session(
|
|
760
|
-
workflow_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)
|
|
761
|
-
):
|
|
762
|
-
# Retrieve the workflow by ID
|
|
763
|
-
workflow = get_workflow_by_id(workflow_id, workflows)
|
|
764
|
-
if not workflow:
|
|
765
|
-
raise HTTPException(status_code=404, detail="Workflow not found")
|
|
766
|
-
|
|
767
|
-
# Ensure storage is enabled for the workflow
|
|
768
|
-
if not workflow.storage:
|
|
769
|
-
raise HTTPException(status_code=404, detail="Workflow does not have storage enabled")
|
|
770
|
-
|
|
771
|
-
# Retrieve the specific session
|
|
772
|
-
try:
|
|
773
|
-
workflow_session = workflow.storage.read(session_id, user_id) # type: ignore
|
|
774
|
-
except Exception as e:
|
|
775
|
-
raise HTTPException(status_code=500, detail=f"Error retrieving session: {str(e)}")
|
|
776
|
-
|
|
777
|
-
if not workflow_session:
|
|
778
|
-
raise HTTPException(status_code=404, detail="Session not found")
|
|
779
|
-
|
|
780
|
-
workflow_session_dict = workflow_session.to_dict()
|
|
781
|
-
if "memory" not in workflow_session_dict:
|
|
782
|
-
workflow_session_dict["memory"] = {"runs": workflow_session_dict.pop("runs", [])}
|
|
783
|
-
|
|
784
|
-
return JSONResponse(content=workflow_session_dict)
|
|
785
|
-
|
|
786
|
-
@playground_router.post("/workflows/{workflow_id}/sessions/{session_id}/rename")
|
|
787
|
-
async def rename_workflow_session(workflow_id: str, session_id: str, body: WorkflowRenameRequest):
|
|
788
|
-
workflow = get_workflow_by_id(workflow_id, workflows)
|
|
789
|
-
if workflow is None:
|
|
790
|
-
raise HTTPException(status_code=404, detail="Workflow not found")
|
|
791
|
-
workflow.session_id = session_id
|
|
792
|
-
workflow.rename_session(body.name)
|
|
793
|
-
return JSONResponse(content={"message": f"successfully renamed workflow {workflow.name}"})
|
|
794
|
-
|
|
795
|
-
@playground_router.delete("/workflows/{workflow_id}/sessions/{session_id}")
|
|
796
|
-
async def delete_workflow_session(workflow_id: str, session_id: str):
|
|
797
|
-
workflow = get_workflow_by_id(workflow_id, workflows)
|
|
798
|
-
if workflow is None:
|
|
799
|
-
raise HTTPException(status_code=404, detail="Workflow not found")
|
|
800
|
-
|
|
801
|
-
workflow.delete_session(session_id)
|
|
802
|
-
return JSONResponse(content={"message": f"successfully deleted workflow {workflow.name}"})
|
|
803
|
-
|
|
804
|
-
@playground_router.get("/teams")
|
|
805
|
-
async def get_teams():
|
|
806
|
-
if teams is None:
|
|
807
|
-
return []
|
|
808
|
-
|
|
809
|
-
return [TeamGetResponse.from_team(team, async_mode=True) for team in teams]
|
|
810
|
-
|
|
811
|
-
@playground_router.get("/teams/{team_id}")
|
|
812
|
-
async def get_team(team_id: str):
|
|
813
|
-
team = get_team_by_id(team_id, teams)
|
|
814
|
-
if team is None:
|
|
815
|
-
raise HTTPException(status_code=404, detail="Team not found")
|
|
816
|
-
|
|
817
|
-
return TeamGetResponse.from_team(team, async_mode=True)
|
|
818
|
-
|
|
819
|
-
@playground_router.post("/teams/{team_id}/runs")
|
|
820
|
-
async def create_team_run(
|
|
821
|
-
team_id: str,
|
|
822
|
-
message: str = Form(...),
|
|
823
|
-
stream: bool = Form(True),
|
|
824
|
-
monitor: bool = Form(True),
|
|
825
|
-
session_id: Optional[str] = Form(None),
|
|
826
|
-
user_id: Optional[str] = Form(None),
|
|
827
|
-
files: Optional[List[UploadFile]] = File(None),
|
|
828
|
-
):
|
|
829
|
-
logger.debug(f"Creating team run: {message} {session_id} {monitor} {user_id} {team_id} {files}")
|
|
830
|
-
team = get_team_by_id(team_id, teams)
|
|
831
|
-
if team is None:
|
|
832
|
-
raise HTTPException(status_code=404, detail="Team not found")
|
|
833
|
-
|
|
834
|
-
if session_id is not None and session_id != "":
|
|
835
|
-
logger.debug(f"Continuing session: {session_id}")
|
|
836
|
-
else:
|
|
837
|
-
logger.debug("Creating new session")
|
|
838
|
-
session_id = str(uuid4())
|
|
839
|
-
|
|
840
|
-
if monitor:
|
|
841
|
-
team.monitoring = True
|
|
842
|
-
else:
|
|
843
|
-
team.monitoring = False
|
|
844
|
-
|
|
845
|
-
base64_images: List[Image] = []
|
|
846
|
-
base64_audios: List[Audio] = []
|
|
847
|
-
base64_videos: List[Video] = []
|
|
848
|
-
document_files: List[FileMedia] = []
|
|
849
|
-
|
|
850
|
-
if files:
|
|
851
|
-
for file in files:
|
|
852
|
-
if file.content_type in ["image/png", "image/jpeg", "image/jpg", "image/webp"]:
|
|
853
|
-
try:
|
|
854
|
-
base64_image = process_image(file)
|
|
855
|
-
base64_images.append(base64_image)
|
|
856
|
-
except Exception as e:
|
|
857
|
-
logger.error(f"Error processing image {file.filename}: {e}")
|
|
858
|
-
continue
|
|
859
|
-
elif file.content_type in ["audio/wav", "audio/mp3", "audio/mpeg"]:
|
|
860
|
-
try:
|
|
861
|
-
base64_audio = process_audio(file)
|
|
862
|
-
base64_audios.append(base64_audio)
|
|
863
|
-
except Exception as e:
|
|
864
|
-
logger.error(f"Error processing audio {file.filename}: {e}")
|
|
865
|
-
continue
|
|
866
|
-
elif file.content_type in [
|
|
867
|
-
"video/x-flv",
|
|
868
|
-
"video/quicktime",
|
|
869
|
-
"video/mpeg",
|
|
870
|
-
"video/mpegs",
|
|
871
|
-
"video/mpgs",
|
|
872
|
-
"video/mpg",
|
|
873
|
-
"video/mpg",
|
|
874
|
-
"video/mp4",
|
|
875
|
-
"video/webm",
|
|
876
|
-
"video/wmv",
|
|
877
|
-
"video/3gpp",
|
|
878
|
-
]:
|
|
879
|
-
try:
|
|
880
|
-
base64_video = process_video(file)
|
|
881
|
-
base64_videos.append(base64_video)
|
|
882
|
-
except Exception as e:
|
|
883
|
-
logger.error(f"Error processing video {file.filename}: {e}")
|
|
884
|
-
continue
|
|
885
|
-
elif file.content_type in [
|
|
886
|
-
"application/pdf",
|
|
887
|
-
"text/csv",
|
|
888
|
-
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
889
|
-
"text/plain",
|
|
890
|
-
"application/json",
|
|
891
|
-
]:
|
|
892
|
-
document_file = process_document(file)
|
|
893
|
-
if document_file is not None:
|
|
894
|
-
document_files.append(document_file)
|
|
895
|
-
else:
|
|
896
|
-
raise HTTPException(status_code=400, detail="Unsupported file type")
|
|
897
|
-
|
|
898
|
-
if stream:
|
|
899
|
-
return StreamingResponse(
|
|
900
|
-
team_chat_response_streamer(
|
|
901
|
-
team,
|
|
902
|
-
message,
|
|
903
|
-
session_id=session_id,
|
|
904
|
-
user_id=user_id,
|
|
905
|
-
images=base64_images if base64_images else None,
|
|
906
|
-
audio=base64_audios if base64_audios else None,
|
|
907
|
-
videos=base64_videos if base64_videos else None,
|
|
908
|
-
files=document_files if document_files else None,
|
|
909
|
-
),
|
|
910
|
-
media_type="text/event-stream",
|
|
911
|
-
)
|
|
912
|
-
else:
|
|
913
|
-
run_response = await team.arun(
|
|
914
|
-
message=message,
|
|
915
|
-
session_id=session_id,
|
|
916
|
-
user_id=user_id,
|
|
917
|
-
images=base64_images if base64_images else None,
|
|
918
|
-
audio=base64_audios if base64_audios else None,
|
|
919
|
-
videos=base64_videos if base64_videos else None,
|
|
920
|
-
files=document_files if document_files else None,
|
|
921
|
-
stream=False,
|
|
922
|
-
)
|
|
923
|
-
return run_response.to_dict()
|
|
924
|
-
|
|
925
|
-
@playground_router.get("/teams/{team_id}/sessions", response_model=List[TeamSessionResponse])
|
|
926
|
-
async def get_all_team_sessions(team_id: str, user_id: Optional[str] = Query(None, min_length=1)):
|
|
927
|
-
team = get_team_by_id(team_id, teams)
|
|
928
|
-
if team is None:
|
|
929
|
-
raise HTTPException(status_code=404, detail="Team not found")
|
|
930
|
-
|
|
931
|
-
if team.storage is None:
|
|
932
|
-
raise HTTPException(status_code=404, detail="Team does not have storage enabled")
|
|
933
|
-
|
|
934
|
-
try:
|
|
935
|
-
all_team_sessions: List[TeamSession] = team.storage.get_all_sessions(user_id=user_id, entity_id=team_id) # type: ignore
|
|
936
|
-
except Exception as e:
|
|
937
|
-
raise HTTPException(status_code=500, detail=f"Error retrieving sessions: {str(e)}")
|
|
938
|
-
|
|
939
|
-
team_sessions: List[TeamSessionResponse] = []
|
|
940
|
-
for session in all_team_sessions:
|
|
941
|
-
title = get_session_title_from_team_session(session)
|
|
942
|
-
team_sessions.append(
|
|
943
|
-
TeamSessionResponse(
|
|
944
|
-
title=title,
|
|
945
|
-
session_id=session.session_id,
|
|
946
|
-
session_name=session.session_data.get("session_name") if session.session_data else None,
|
|
947
|
-
created_at=session.created_at,
|
|
948
|
-
)
|
|
949
|
-
)
|
|
950
|
-
return team_sessions
|
|
951
|
-
|
|
952
|
-
@playground_router.get("/teams/{team_id}/sessions/{session_id}")
|
|
953
|
-
async def get_team_session(team_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)):
|
|
954
|
-
team = get_team_by_id(team_id, teams)
|
|
955
|
-
if team is None:
|
|
956
|
-
raise HTTPException(status_code=404, detail="Team not found")
|
|
957
|
-
|
|
958
|
-
if team.storage is None:
|
|
959
|
-
raise HTTPException(status_code=404, detail="Team does not have storage enabled")
|
|
960
|
-
|
|
961
|
-
try:
|
|
962
|
-
team_session: Optional[TeamSession] = team.storage.read(session_id, user_id) # type: ignore
|
|
963
|
-
except Exception as e:
|
|
964
|
-
raise HTTPException(status_code=500, detail=f"Error retrieving session: {str(e)}")
|
|
965
|
-
|
|
966
|
-
if not team_session:
|
|
967
|
-
raise HTTPException(status_code=404, detail="Session not found")
|
|
968
|
-
|
|
969
|
-
team_session_dict = team_session.to_dict()
|
|
970
|
-
if team_session.memory is not None:
|
|
971
|
-
runs = team_session.memory.get("runs")
|
|
972
|
-
if runs is not None:
|
|
973
|
-
first_run = runs[0]
|
|
974
|
-
# This is how we know it is a RunResponse or RunPaused
|
|
975
|
-
if "content" in first_run or first_run.get("is_paused", False) or first_run.get("event") == "RunPaused":
|
|
976
|
-
team_session_dict["runs"] = []
|
|
977
|
-
for run in runs:
|
|
978
|
-
# We skip runs that are not from the parent team
|
|
979
|
-
if run.get("team_session_id") is not None and run.get("team_session_id") == session_id:
|
|
980
|
-
continue
|
|
981
|
-
|
|
982
|
-
first_user_message = None
|
|
983
|
-
for msg in run.get("messages", []):
|
|
984
|
-
if msg.get("role") == "user" and msg.get("from_history", False) is False:
|
|
985
|
-
first_user_message = msg
|
|
986
|
-
break
|
|
987
|
-
# Remove the memory from the response
|
|
988
|
-
team_session_dict.pop("memory", None)
|
|
989
|
-
team_session_dict["runs"].append(
|
|
990
|
-
{
|
|
991
|
-
"message": first_user_message,
|
|
992
|
-
"response": run,
|
|
993
|
-
}
|
|
994
|
-
)
|
|
995
|
-
|
|
996
|
-
return team_session_dict
|
|
997
|
-
|
|
998
|
-
@playground_router.post("/teams/{team_id}/sessions/{session_id}/rename")
|
|
999
|
-
async def rename_team_session(team_id: str, session_id: str, body: TeamRenameRequest):
|
|
1000
|
-
team = get_team_by_id(team_id, teams)
|
|
1001
|
-
if team is None:
|
|
1002
|
-
raise HTTPException(status_code=404, detail="Team not found")
|
|
1003
|
-
|
|
1004
|
-
if team.storage is None:
|
|
1005
|
-
raise HTTPException(status_code=404, detail="Team does not have storage enabled")
|
|
1006
|
-
|
|
1007
|
-
all_team_sessions: List[TeamSession] = team.storage.get_all_sessions(user_id=body.user_id, entity_id=team_id) # type: ignore
|
|
1008
|
-
for session in all_team_sessions:
|
|
1009
|
-
if session.session_id == session_id:
|
|
1010
|
-
team.rename_session(body.name, session_id=session_id)
|
|
1011
|
-
return JSONResponse(content={"message": f"successfully renamed team session {body.name}"})
|
|
1012
|
-
|
|
1013
|
-
raise HTTPException(status_code=404, detail="Session not found")
|
|
1014
|
-
|
|
1015
|
-
@playground_router.delete("/teams/{team_id}/sessions/{session_id}")
|
|
1016
|
-
async def delete_team_session(team_id: str, session_id: str, user_id: Optional[str] = Query(None, min_length=1)):
|
|
1017
|
-
team = get_team_by_id(team_id, teams)
|
|
1018
|
-
if team is None:
|
|
1019
|
-
raise HTTPException(status_code=404, detail="Team not found")
|
|
1020
|
-
|
|
1021
|
-
if team.storage is None:
|
|
1022
|
-
raise HTTPException(status_code=404, detail="Team does not have storage enabled")
|
|
1023
|
-
|
|
1024
|
-
all_team_sessions: List[TeamSession] = team.storage.get_all_sessions(user_id=user_id, entity_id=team_id) # type: ignore
|
|
1025
|
-
for session in all_team_sessions:
|
|
1026
|
-
if session.session_id == session_id:
|
|
1027
|
-
team.delete_session(session_id)
|
|
1028
|
-
return JSONResponse(content={"message": f"successfully deleted team session {session_id}"})
|
|
1029
|
-
|
|
1030
|
-
raise HTTPException(status_code=404, detail="Session not found")
|
|
1031
|
-
|
|
1032
|
-
@playground_router.get("/team/{team_id}/memories")
|
|
1033
|
-
async def get_team_memories(team_id: str, user_id: str = Query(..., min_length=1)):
|
|
1034
|
-
team = get_team_by_id(team_id, teams)
|
|
1035
|
-
if team is None:
|
|
1036
|
-
return JSONResponse(status_code=404, content="Teem not found.")
|
|
1037
|
-
|
|
1038
|
-
if team.memory is None:
|
|
1039
|
-
return JSONResponse(status_code=404, content="Team does not have memory enabled.")
|
|
1040
|
-
|
|
1041
|
-
if isinstance(team.memory, Memory):
|
|
1042
|
-
memories = team.memory.get_user_memories(user_id=user_id)
|
|
1043
|
-
return [
|
|
1044
|
-
MemoryResponse(memory=memory.memory, topics=memory.topics, last_updated=memory.last_updated)
|
|
1045
|
-
for memory in memories
|
|
1046
|
-
]
|
|
1047
|
-
else:
|
|
1048
|
-
return []
|
|
1049
|
-
|
|
1050
|
-
return playground_router
|