agno 1.8.0__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 +2781 -4126
- 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/media.py +2 -2
- 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/dashscope/dashscope.py +14 -5
- agno/models/google/gemini.py +123 -53
- 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 +135 -27
- agno/models/openai/responses.py +233 -115
- 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 +2967 -4243
- 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 +71 -18
- 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 +62 -62
- 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 +46 -62
- 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 +134 -0
- 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/location.py +2 -2
- 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 +356 -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 -698
- 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.0.dist-info/METADATA +0 -979
- agno-1.8.0.dist-info/RECORD +0 -565
- agno-1.8.0.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.0.dist-info → agno-2.0.0a1.dist-info}/WHEEL +0 -0
- {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/licenses/LICENSE +0 -0
- {agno-1.8.0.dist-info → agno-2.0.0a1.dist-info}/top_level.txt +0 -0
agno/storage/dynamodb.py
DELETED
|
@@ -1,673 +0,0 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from dataclasses import asdict
|
|
3
|
-
from decimal import Decimal
|
|
4
|
-
from typing import Any, Dict, List, Literal, Optional
|
|
5
|
-
|
|
6
|
-
from agno.storage.base import Storage
|
|
7
|
-
from agno.storage.session import Session
|
|
8
|
-
from agno.storage.session.agent import AgentSession
|
|
9
|
-
from agno.storage.session.team import TeamSession
|
|
10
|
-
from agno.storage.session.v2.workflow import WorkflowSession as WorkflowSessionV2
|
|
11
|
-
from agno.storage.session.workflow import WorkflowSession
|
|
12
|
-
from agno.utils.log import log_debug, log_info, logger
|
|
13
|
-
|
|
14
|
-
try:
|
|
15
|
-
import boto3
|
|
16
|
-
from boto3.dynamodb.conditions import Key
|
|
17
|
-
from botocore.exceptions import ClientError
|
|
18
|
-
except ImportError:
|
|
19
|
-
raise ImportError("`boto3` not installed. Please install using `pip install boto3`.")
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class DynamoDbStorage(Storage):
|
|
23
|
-
def __init__(
|
|
24
|
-
self,
|
|
25
|
-
table_name: str,
|
|
26
|
-
profile_name: Optional[str] = None,
|
|
27
|
-
region_name: Optional[str] = None,
|
|
28
|
-
aws_access_key_id: Optional[str] = None,
|
|
29
|
-
aws_secret_access_key: Optional[str] = None,
|
|
30
|
-
endpoint_url: Optional[str] = None,
|
|
31
|
-
create_table_if_not_exists: bool = True,
|
|
32
|
-
mode: Optional[Literal["agent", "team", "workflow", "workflow_v2"]] = "agent",
|
|
33
|
-
create_table_read_capacity_units: int = 5,
|
|
34
|
-
create_table_write_capacity_units: int = 5,
|
|
35
|
-
):
|
|
36
|
-
"""
|
|
37
|
-
Initialize the DynamoDbStorage.
|
|
38
|
-
|
|
39
|
-
Args:
|
|
40
|
-
table_name (str): The name of the DynamoDB table.
|
|
41
|
-
profile_name (Optional[str]): AWS profile name to use for credentials.
|
|
42
|
-
region_name (Optional[str]): AWS region name.
|
|
43
|
-
aws_access_key_id (Optional[str]): AWS access key ID.
|
|
44
|
-
aws_secret_access_key (Optional[str]): AWS secret access key.
|
|
45
|
-
endpoint_url (Optional[str]): The complete URL to use for the constructed client.
|
|
46
|
-
create_table_if_not_exists (bool): Whether to create the table if it does not exist.
|
|
47
|
-
mode (Optional[Literal["agent", "team", "workflow", "workflow_v2"]]): The mode of the storage.
|
|
48
|
-
create_table_read_capacity_units Optional[int]: Read capacity units for created table (default: 5).
|
|
49
|
-
create_table_write_capacity_units Optional[int]: Write capacity units for created table (default: 5).
|
|
50
|
-
"""
|
|
51
|
-
super().__init__(mode)
|
|
52
|
-
self.table_name = table_name
|
|
53
|
-
self.profile_name = profile_name
|
|
54
|
-
self.region_name = region_name
|
|
55
|
-
self.endpoint_url = endpoint_url
|
|
56
|
-
self.aws_access_key_id = aws_access_key_id
|
|
57
|
-
self.aws_secret_access_key = aws_secret_access_key
|
|
58
|
-
self.create_table_if_not_exists = create_table_if_not_exists
|
|
59
|
-
self.create_table_read_capacity_units = create_table_read_capacity_units
|
|
60
|
-
self.create_table_write_capacity_units = create_table_write_capacity_units
|
|
61
|
-
|
|
62
|
-
# Create session using profile name if provided
|
|
63
|
-
if self.profile_name:
|
|
64
|
-
session = boto3.Session(profile_name=self.profile_name)
|
|
65
|
-
self.dynamodb = session.resource(
|
|
66
|
-
"dynamodb",
|
|
67
|
-
region_name=self.region_name,
|
|
68
|
-
endpoint_url=self.endpoint_url,
|
|
69
|
-
)
|
|
70
|
-
else:
|
|
71
|
-
# Initialize DynamoDB resource with default credentials
|
|
72
|
-
self.dynamodb = boto3.resource(
|
|
73
|
-
"dynamodb",
|
|
74
|
-
aws_access_key_id=self.aws_access_key_id,
|
|
75
|
-
aws_secret_access_key=self.aws_secret_access_key,
|
|
76
|
-
region_name=self.region_name,
|
|
77
|
-
endpoint_url=self.endpoint_url,
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
# Initialize table
|
|
81
|
-
self.table = self.dynamodb.Table(self.table_name)
|
|
82
|
-
|
|
83
|
-
# Optionally create table if it does not exist
|
|
84
|
-
if self.create_table_if_not_exists:
|
|
85
|
-
self.create()
|
|
86
|
-
log_debug(f"Initialized DynamoDbStorage with table '{self.table_name}'")
|
|
87
|
-
|
|
88
|
-
@property
|
|
89
|
-
def mode(self) -> Literal["agent", "team", "workflow", "workflow_v2"]:
|
|
90
|
-
"""Get the mode of the storage."""
|
|
91
|
-
return super().mode
|
|
92
|
-
|
|
93
|
-
@mode.setter
|
|
94
|
-
def mode(self, value: Optional[Literal["agent", "team", "workflow", "workflow_v2"]]) -> None:
|
|
95
|
-
"""Set the mode and refresh the table if mode changes."""
|
|
96
|
-
super(DynamoDbStorage, type(self)).mode.fset(self, value) # type: ignore
|
|
97
|
-
if value is not None:
|
|
98
|
-
if self.create_table_if_not_exists:
|
|
99
|
-
self.create()
|
|
100
|
-
|
|
101
|
-
def create(self) -> None:
|
|
102
|
-
"""
|
|
103
|
-
Create the DynamoDB table if it does not exist.
|
|
104
|
-
"""
|
|
105
|
-
provisioned_throughput = {
|
|
106
|
-
"ReadCapacityUnits": self.create_table_read_capacity_units,
|
|
107
|
-
"WriteCapacityUnits": self.create_table_write_capacity_units,
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
try:
|
|
111
|
-
# Check if table exists
|
|
112
|
-
self.dynamodb.meta.client.describe_table(TableName=self.table_name)
|
|
113
|
-
log_debug(f"Table '{self.table_name}' already exists.")
|
|
114
|
-
except ClientError as e:
|
|
115
|
-
if e.response["Error"]["Code"] == "ResourceNotFoundException":
|
|
116
|
-
log_debug(f"Creating table '{self.table_name}'.")
|
|
117
|
-
|
|
118
|
-
attribute_definitions = []
|
|
119
|
-
if self.mode == "agent":
|
|
120
|
-
attribute_definitions = [
|
|
121
|
-
{"AttributeName": "session_id", "AttributeType": "S"},
|
|
122
|
-
{"AttributeName": "user_id", "AttributeType": "S"},
|
|
123
|
-
{"AttributeName": "agent_id", "AttributeType": "S"},
|
|
124
|
-
{"AttributeName": "created_at", "AttributeType": "N"},
|
|
125
|
-
]
|
|
126
|
-
elif self.mode == "team":
|
|
127
|
-
attribute_definitions = [
|
|
128
|
-
{"AttributeName": "session_id", "AttributeType": "S"},
|
|
129
|
-
{"AttributeName": "user_id", "AttributeType": "S"},
|
|
130
|
-
{"AttributeName": "team_id", "AttributeType": "S"},
|
|
131
|
-
{"AttributeName": "created_at", "AttributeType": "N"},
|
|
132
|
-
]
|
|
133
|
-
elif self.mode == "workflow":
|
|
134
|
-
attribute_definitions = [
|
|
135
|
-
{"AttributeName": "session_id", "AttributeType": "S"},
|
|
136
|
-
{"AttributeName": "user_id", "AttributeType": "S"},
|
|
137
|
-
{"AttributeName": "workflow_id", "AttributeType": "S"},
|
|
138
|
-
{"AttributeName": "created_at", "AttributeType": "N"},
|
|
139
|
-
]
|
|
140
|
-
elif self.mode == "workflow_v2":
|
|
141
|
-
attribute_definitions = [
|
|
142
|
-
{"AttributeName": "session_id", "AttributeType": "S"},
|
|
143
|
-
{"AttributeName": "user_id", "AttributeType": "S"},
|
|
144
|
-
{"AttributeName": "workflow_id", "AttributeType": "S"},
|
|
145
|
-
{"AttributeName": "created_at", "AttributeType": "N"},
|
|
146
|
-
]
|
|
147
|
-
secondary_indexes = [
|
|
148
|
-
{
|
|
149
|
-
"IndexName": "user_id-index",
|
|
150
|
-
"KeySchema": [
|
|
151
|
-
{"AttributeName": "user_id", "KeyType": "HASH"},
|
|
152
|
-
{"AttributeName": "created_at", "KeyType": "RANGE"},
|
|
153
|
-
],
|
|
154
|
-
"Projection": {"ProjectionType": "ALL"},
|
|
155
|
-
"ProvisionedThroughput": provisioned_throughput,
|
|
156
|
-
}
|
|
157
|
-
]
|
|
158
|
-
if self.mode == "agent":
|
|
159
|
-
secondary_indexes.append(
|
|
160
|
-
{
|
|
161
|
-
"IndexName": "agent_id-index",
|
|
162
|
-
"KeySchema": [
|
|
163
|
-
{"AttributeName": "agent_id", "KeyType": "HASH"},
|
|
164
|
-
{"AttributeName": "created_at", "KeyType": "RANGE"},
|
|
165
|
-
],
|
|
166
|
-
"Projection": {"ProjectionType": "ALL"},
|
|
167
|
-
"ProvisionedThroughput": provisioned_throughput,
|
|
168
|
-
}
|
|
169
|
-
)
|
|
170
|
-
elif self.mode == "team":
|
|
171
|
-
secondary_indexes.append(
|
|
172
|
-
{
|
|
173
|
-
"IndexName": "team_id-index",
|
|
174
|
-
"KeySchema": [
|
|
175
|
-
{"AttributeName": "team_id", "KeyType": "HASH"},
|
|
176
|
-
{"AttributeName": "created_at", "KeyType": "RANGE"},
|
|
177
|
-
],
|
|
178
|
-
"Projection": {"ProjectionType": "ALL"},
|
|
179
|
-
"ProvisionedThroughput": provisioned_throughput,
|
|
180
|
-
}
|
|
181
|
-
)
|
|
182
|
-
elif self.mode == "workflow":
|
|
183
|
-
secondary_indexes.append(
|
|
184
|
-
{
|
|
185
|
-
"IndexName": "workflow_id-index",
|
|
186
|
-
"KeySchema": [
|
|
187
|
-
{"AttributeName": "workflow_id", "KeyType": "HASH"},
|
|
188
|
-
{"AttributeName": "created_at", "KeyType": "RANGE"},
|
|
189
|
-
],
|
|
190
|
-
"Projection": {"ProjectionType": "ALL"},
|
|
191
|
-
"ProvisionedThroughput": provisioned_throughput,
|
|
192
|
-
}
|
|
193
|
-
)
|
|
194
|
-
elif self.mode == "workflow_v2":
|
|
195
|
-
secondary_indexes.append(
|
|
196
|
-
{
|
|
197
|
-
"IndexName": "workflow_id-index",
|
|
198
|
-
"KeySchema": [
|
|
199
|
-
{"AttributeName": "workflow_id", "KeyType": "HASH"},
|
|
200
|
-
{"AttributeName": "created_at", "KeyType": "RANGE"},
|
|
201
|
-
],
|
|
202
|
-
"Projection": {"ProjectionType": "ALL"},
|
|
203
|
-
"ProvisionedThroughput": provisioned_throughput,
|
|
204
|
-
}
|
|
205
|
-
)
|
|
206
|
-
# Create the table
|
|
207
|
-
self.table = self.dynamodb.create_table(
|
|
208
|
-
TableName=self.table_name,
|
|
209
|
-
KeySchema=[{"AttributeName": "session_id", "KeyType": "HASH"}],
|
|
210
|
-
AttributeDefinitions=attribute_definitions,
|
|
211
|
-
GlobalSecondaryIndexes=secondary_indexes,
|
|
212
|
-
ProvisionedThroughput=provisioned_throughput,
|
|
213
|
-
)
|
|
214
|
-
# Wait until the table exists.
|
|
215
|
-
self.table.wait_until_exists()
|
|
216
|
-
log_debug(f"Table '{self.table_name}' created successfully.")
|
|
217
|
-
else:
|
|
218
|
-
logger.error(f"Unable to create table '{self.table_name}': {e.response['Error']['Message']}")
|
|
219
|
-
except Exception as e:
|
|
220
|
-
logger.error(f"Exception during table creation: {e}")
|
|
221
|
-
|
|
222
|
-
def read(self, session_id: str, user_id: Optional[str] = None) -> Optional[Session]:
|
|
223
|
-
"""
|
|
224
|
-
Read and return a Session from the database.
|
|
225
|
-
|
|
226
|
-
Args:
|
|
227
|
-
session_id (str): ID of the session to read.
|
|
228
|
-
user_id (Optional[str]): User ID to filter by. Defaults to None.
|
|
229
|
-
|
|
230
|
-
Returns:
|
|
231
|
-
Optional[Session]: Session object if found, None otherwise.
|
|
232
|
-
"""
|
|
233
|
-
try:
|
|
234
|
-
key = {"session_id": session_id}
|
|
235
|
-
if user_id is not None:
|
|
236
|
-
key["user_id"] = user_id
|
|
237
|
-
|
|
238
|
-
response = self.table.get_item(Key=key)
|
|
239
|
-
item = response.get("Item", None)
|
|
240
|
-
if item is not None:
|
|
241
|
-
# Convert Decimal to int or float
|
|
242
|
-
item = self._deserialize_item(item)
|
|
243
|
-
if self.mode == "agent":
|
|
244
|
-
return AgentSession.from_dict(item)
|
|
245
|
-
elif self.mode == "team":
|
|
246
|
-
return TeamSession.from_dict(item)
|
|
247
|
-
elif self.mode == "workflow":
|
|
248
|
-
return WorkflowSession.from_dict(item)
|
|
249
|
-
elif self.mode == "workflow_v2":
|
|
250
|
-
return WorkflowSessionV2.from_dict(item)
|
|
251
|
-
except Exception as e:
|
|
252
|
-
logger.error(f"Error reading session_id '{session_id}' with user_id '{user_id}': {e}")
|
|
253
|
-
return None
|
|
254
|
-
|
|
255
|
-
def get_all_session_ids(self, user_id: Optional[str] = None, entity_id: Optional[str] = None) -> List[str]:
|
|
256
|
-
"""
|
|
257
|
-
Retrieve all session IDs, optionally filtered by user_id and/or entity_id.
|
|
258
|
-
|
|
259
|
-
Args:
|
|
260
|
-
user_id (Optional[str], optional): User ID to filter by. Defaults to None.
|
|
261
|
-
entity_id (Optional[str], optional): Entity ID to filter by. Defaults to None.
|
|
262
|
-
|
|
263
|
-
Returns:
|
|
264
|
-
List[str]: List of session IDs matching the criteria.
|
|
265
|
-
"""
|
|
266
|
-
session_ids: List[str] = []
|
|
267
|
-
try:
|
|
268
|
-
if user_id is not None:
|
|
269
|
-
# Query using user_id index
|
|
270
|
-
response = self.table.query(
|
|
271
|
-
IndexName="user_id-index",
|
|
272
|
-
KeyConditionExpression=Key("user_id").eq(user_id),
|
|
273
|
-
ProjectionExpression="session_id",
|
|
274
|
-
)
|
|
275
|
-
items = response.get("Items", [])
|
|
276
|
-
session_ids.extend([item["session_id"] for item in items if "session_id" in item])
|
|
277
|
-
elif entity_id is not None:
|
|
278
|
-
if self.mode == "agent":
|
|
279
|
-
# Query using agent_id index
|
|
280
|
-
response = self.table.query(
|
|
281
|
-
IndexName="agent_id-index",
|
|
282
|
-
KeyConditionExpression=Key("agent_id").eq(entity_id),
|
|
283
|
-
ProjectionExpression="session_id",
|
|
284
|
-
)
|
|
285
|
-
elif self.mode == "team":
|
|
286
|
-
# Query using team_id index
|
|
287
|
-
response = self.table.query(
|
|
288
|
-
IndexName="team_id-index",
|
|
289
|
-
KeyConditionExpression=Key("team_id").eq(entity_id),
|
|
290
|
-
ProjectionExpression="session_id",
|
|
291
|
-
)
|
|
292
|
-
elif self.mode == "workflow":
|
|
293
|
-
# Query using workflow_id index
|
|
294
|
-
response = self.table.query(
|
|
295
|
-
IndexName="workflow_id-index",
|
|
296
|
-
KeyConditionExpression=Key("workflow_id").eq(entity_id),
|
|
297
|
-
ProjectionExpression="session_id",
|
|
298
|
-
)
|
|
299
|
-
items = response.get("Items", []) # type: ignore
|
|
300
|
-
session_ids.extend([item["session_id"] for item in items if "session_id" in item])
|
|
301
|
-
else:
|
|
302
|
-
# Scan the whole table
|
|
303
|
-
response = self.table.scan(ProjectionExpression="session_id")
|
|
304
|
-
items = response.get("Items", [])
|
|
305
|
-
session_ids.extend([item["session_id"] for item in items if "session_id" in item])
|
|
306
|
-
except Exception as e:
|
|
307
|
-
logger.error(f"Error retrieving session IDs: {e}")
|
|
308
|
-
return session_ids
|
|
309
|
-
|
|
310
|
-
def get_all_sessions(self, user_id: Optional[str] = None, entity_id: Optional[str] = None) -> List[Session]:
|
|
311
|
-
"""
|
|
312
|
-
Retrieve all sessions, optionally filtered by user_id and/or entity_id.
|
|
313
|
-
|
|
314
|
-
Args:
|
|
315
|
-
user_id (Optional[str], optional): User ID to filter by. Defaults to None.
|
|
316
|
-
entity_id (Optional[str], optional): Entity ID to filter by. Defaults to None.
|
|
317
|
-
|
|
318
|
-
Returns:
|
|
319
|
-
List[Session]: List of AgentSession or WorkflowSession objects matching the criteria.
|
|
320
|
-
"""
|
|
321
|
-
sessions: List[Session] = []
|
|
322
|
-
try:
|
|
323
|
-
if user_id is not None:
|
|
324
|
-
if self.mode == "agent":
|
|
325
|
-
# Query using user_id index
|
|
326
|
-
response = self.table.query(
|
|
327
|
-
IndexName="user_id-index",
|
|
328
|
-
KeyConditionExpression=Key("user_id").eq(user_id),
|
|
329
|
-
ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
|
|
330
|
-
)
|
|
331
|
-
elif self.mode == "team":
|
|
332
|
-
# Query using user_id index
|
|
333
|
-
response = self.table.query(
|
|
334
|
-
IndexName="user_id-index",
|
|
335
|
-
KeyConditionExpression=Key("user_id").eq(user_id),
|
|
336
|
-
ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
|
|
337
|
-
)
|
|
338
|
-
elif self.mode == "workflow":
|
|
339
|
-
# Query using user_id index
|
|
340
|
-
response = self.table.query(
|
|
341
|
-
IndexName="user_id-index",
|
|
342
|
-
KeyConditionExpression=Key("user_id").eq(user_id),
|
|
343
|
-
ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
344
|
-
)
|
|
345
|
-
elif self.mode == "workflow_v2":
|
|
346
|
-
# Query using user_id index
|
|
347
|
-
response = self.table.query(
|
|
348
|
-
IndexName="user_id-index",
|
|
349
|
-
KeyConditionExpression=Key("user_id").eq(user_id),
|
|
350
|
-
ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
351
|
-
)
|
|
352
|
-
items = response.get("Items", []) # type: ignore
|
|
353
|
-
for item in items:
|
|
354
|
-
item = self._deserialize_item(item)
|
|
355
|
-
_session: Optional[Session] = None
|
|
356
|
-
if self.mode == "agent":
|
|
357
|
-
_session = AgentSession.from_dict(item)
|
|
358
|
-
else:
|
|
359
|
-
_session = WorkflowSession.from_dict(item) # type: ignore
|
|
360
|
-
if _session is not None:
|
|
361
|
-
sessions.append(_session)
|
|
362
|
-
elif entity_id is not None:
|
|
363
|
-
if self.mode == "agent":
|
|
364
|
-
# Query using agent_id index
|
|
365
|
-
response = self.table.query(
|
|
366
|
-
IndexName="agent_id-index",
|
|
367
|
-
KeyConditionExpression=Key("agent_id").eq(entity_id),
|
|
368
|
-
ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
|
|
369
|
-
)
|
|
370
|
-
elif self.mode == "team":
|
|
371
|
-
# Query using team_id index
|
|
372
|
-
response = self.table.query(
|
|
373
|
-
IndexName="team_id-index",
|
|
374
|
-
KeyConditionExpression=Key("team_id").eq(entity_id),
|
|
375
|
-
ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
|
|
376
|
-
)
|
|
377
|
-
elif self.mode == "workflow":
|
|
378
|
-
# Query using workflow_id index
|
|
379
|
-
response = self.table.query(
|
|
380
|
-
IndexName="workflow_id-index",
|
|
381
|
-
KeyConditionExpression=Key("workflow_id").eq(entity_id),
|
|
382
|
-
ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
383
|
-
)
|
|
384
|
-
elif self.mode == "workflow_v2":
|
|
385
|
-
# Query using workflow_id index
|
|
386
|
-
response = self.table.query(
|
|
387
|
-
IndexName="workflow_id-index",
|
|
388
|
-
KeyConditionExpression=Key("workflow_id").eq(entity_id),
|
|
389
|
-
ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
390
|
-
)
|
|
391
|
-
items = response.get("Items", []) # type: ignore
|
|
392
|
-
for item in items:
|
|
393
|
-
item = self._deserialize_item(item)
|
|
394
|
-
if self.mode == "agent":
|
|
395
|
-
_session = AgentSession.from_dict(item) # type: ignore
|
|
396
|
-
else:
|
|
397
|
-
_session = WorkflowSession.from_dict(item) # type: ignore
|
|
398
|
-
if _session is not None:
|
|
399
|
-
sessions.append(_session)
|
|
400
|
-
else:
|
|
401
|
-
# Scan the whole table
|
|
402
|
-
if self.mode == "agent":
|
|
403
|
-
response = self.table.scan(
|
|
404
|
-
ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at"
|
|
405
|
-
)
|
|
406
|
-
elif self.mode == "team":
|
|
407
|
-
response = self.table.scan(
|
|
408
|
-
ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at"
|
|
409
|
-
)
|
|
410
|
-
elif self.mode == "workflow":
|
|
411
|
-
response = self.table.scan(
|
|
412
|
-
ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at"
|
|
413
|
-
)
|
|
414
|
-
elif self.mode == "workflow_v2":
|
|
415
|
-
response = self.table.scan(
|
|
416
|
-
ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at"
|
|
417
|
-
)
|
|
418
|
-
items = response.get("Items", [])
|
|
419
|
-
for item in items:
|
|
420
|
-
item = self._deserialize_item(item)
|
|
421
|
-
if self.mode == "agent":
|
|
422
|
-
_session = AgentSession.from_dict(item) # type: ignore
|
|
423
|
-
elif self.mode == "team":
|
|
424
|
-
_session = TeamSession.from_dict(item) # type: ignore
|
|
425
|
-
else:
|
|
426
|
-
_session = WorkflowSession.from_dict(item) # type: ignore
|
|
427
|
-
if _session is not None:
|
|
428
|
-
sessions.append(_session)
|
|
429
|
-
except Exception as e:
|
|
430
|
-
logger.error(f"Error retrieving sessions: {e}")
|
|
431
|
-
return sessions
|
|
432
|
-
|
|
433
|
-
def get_recent_sessions(
|
|
434
|
-
self,
|
|
435
|
-
user_id: Optional[str] = None,
|
|
436
|
-
entity_id: Optional[str] = None,
|
|
437
|
-
limit: Optional[int] = 2,
|
|
438
|
-
) -> List[Session]:
|
|
439
|
-
"""Get the last N sessions, ordered by created_at descending.
|
|
440
|
-
|
|
441
|
-
Args:
|
|
442
|
-
num_history_sessions: Number of most recent sessions to return
|
|
443
|
-
user_id: Filter by user ID
|
|
444
|
-
entity_id: Filter by entity ID (agent_id, team_id, or workflow_id)
|
|
445
|
-
|
|
446
|
-
Returns:
|
|
447
|
-
List[Session]: List of most recent sessions
|
|
448
|
-
"""
|
|
449
|
-
sessions: List[Session] = []
|
|
450
|
-
try:
|
|
451
|
-
if user_id is not None:
|
|
452
|
-
if self.mode == "agent":
|
|
453
|
-
response = self.table.query(
|
|
454
|
-
IndexName="user_id-index",
|
|
455
|
-
KeyConditionExpression=Key("user_id").eq(user_id),
|
|
456
|
-
ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
|
|
457
|
-
ScanIndexForward=False,
|
|
458
|
-
Limit=limit if limit is not None else None,
|
|
459
|
-
)
|
|
460
|
-
elif self.mode == "team":
|
|
461
|
-
response = self.table.query(
|
|
462
|
-
IndexName="user_id-index",
|
|
463
|
-
KeyConditionExpression=Key("user_id").eq(user_id),
|
|
464
|
-
ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
|
|
465
|
-
ScanIndexForward=False,
|
|
466
|
-
Limit=limit if limit is not None else None,
|
|
467
|
-
)
|
|
468
|
-
elif self.mode == "workflow":
|
|
469
|
-
response = self.table.query(
|
|
470
|
-
IndexName="user_id-index",
|
|
471
|
-
KeyConditionExpression=Key("user_id").eq(user_id),
|
|
472
|
-
ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
473
|
-
ScanIndexForward=False,
|
|
474
|
-
Limit=limit if limit is not None else None,
|
|
475
|
-
)
|
|
476
|
-
elif self.mode == "workflow_v2":
|
|
477
|
-
response = self.table.query(
|
|
478
|
-
IndexName="user_id-index",
|
|
479
|
-
KeyConditionExpression=Key("user_id").eq(user_id),
|
|
480
|
-
ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
481
|
-
ScanIndexForward=False,
|
|
482
|
-
Limit=limit if limit is not None else None,
|
|
483
|
-
)
|
|
484
|
-
elif entity_id is not None:
|
|
485
|
-
if self.mode == "agent":
|
|
486
|
-
response = self.table.query(
|
|
487
|
-
IndexName="agent_id-index",
|
|
488
|
-
KeyConditionExpression=Key("agent_id").eq(entity_id),
|
|
489
|
-
ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
|
|
490
|
-
ScanIndexForward=False,
|
|
491
|
-
Limit=limit if limit is not None else None,
|
|
492
|
-
)
|
|
493
|
-
elif self.mode == "team":
|
|
494
|
-
response = self.table.query(
|
|
495
|
-
IndexName="team_id-index",
|
|
496
|
-
KeyConditionExpression=Key("team_id").eq(entity_id),
|
|
497
|
-
ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
|
|
498
|
-
ScanIndexForward=False,
|
|
499
|
-
Limit=limit if limit is not None else None,
|
|
500
|
-
)
|
|
501
|
-
elif self.mode == "workflow":
|
|
502
|
-
response = self.table.query(
|
|
503
|
-
IndexName="workflow_id-index",
|
|
504
|
-
KeyConditionExpression=Key("workflow_id").eq(entity_id),
|
|
505
|
-
ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
506
|
-
ScanIndexForward=False,
|
|
507
|
-
Limit=limit if limit is not None else None,
|
|
508
|
-
)
|
|
509
|
-
elif self.mode == "workflow_v2":
|
|
510
|
-
response = self.table.query(
|
|
511
|
-
IndexName="workflow_id-index",
|
|
512
|
-
KeyConditionExpression=Key("workflow_id").eq(entity_id),
|
|
513
|
-
ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
514
|
-
ScanIndexForward=False,
|
|
515
|
-
Limit=limit if limit is not None else None,
|
|
516
|
-
)
|
|
517
|
-
else:
|
|
518
|
-
# If no filters, scan the table and sort by created_at
|
|
519
|
-
if self.mode == "agent":
|
|
520
|
-
response = self.table.scan(
|
|
521
|
-
ProjectionExpression="session_id, agent_id, user_id, team_session_id, memory, agent_data, session_data, extra_data, created_at, updated_at",
|
|
522
|
-
Limit=limit if limit is not None else None,
|
|
523
|
-
)
|
|
524
|
-
elif self.mode == "team":
|
|
525
|
-
response = self.table.scan(
|
|
526
|
-
ProjectionExpression="session_id, team_id, user_id, team_session_id, memory, team_data, session_data, extra_data, created_at, updated_at",
|
|
527
|
-
Limit=limit if limit is not None else None,
|
|
528
|
-
)
|
|
529
|
-
elif self.mode == "workflow":
|
|
530
|
-
response = self.table.scan(
|
|
531
|
-
ProjectionExpression="session_id, workflow_id, user_id, memory, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
532
|
-
Limit=limit if limit is not None else None,
|
|
533
|
-
)
|
|
534
|
-
elif self.mode == "workflow_v2":
|
|
535
|
-
response = self.table.scan(
|
|
536
|
-
ProjectionExpression="session_id, workflow_id, user_id, workflow_name, runs, workflow_data, session_data, extra_data, created_at, updated_at",
|
|
537
|
-
Limit=limit if limit is not None else None,
|
|
538
|
-
)
|
|
539
|
-
items = response.get("Items", [])
|
|
540
|
-
for item in items:
|
|
541
|
-
item = self._deserialize_item(item)
|
|
542
|
-
session: Optional[Session] = None
|
|
543
|
-
|
|
544
|
-
if self.mode == "agent":
|
|
545
|
-
session = AgentSession.from_dict(item)
|
|
546
|
-
elif self.mode == "team":
|
|
547
|
-
session = TeamSession.from_dict(item)
|
|
548
|
-
elif self.mode == "workflow":
|
|
549
|
-
session = WorkflowSession.from_dict(item)
|
|
550
|
-
elif self.mode == "workflow_v2":
|
|
551
|
-
session = WorkflowSessionV2.from_dict(item)
|
|
552
|
-
if session is not None:
|
|
553
|
-
sessions.append(session)
|
|
554
|
-
|
|
555
|
-
except Exception as e:
|
|
556
|
-
logger.error(f"Error getting last {limit} sessions: {e}")
|
|
557
|
-
|
|
558
|
-
return sessions
|
|
559
|
-
|
|
560
|
-
def upsert(self, session: Session) -> Optional[Session]:
|
|
561
|
-
"""
|
|
562
|
-
Create or update a Session in the database.
|
|
563
|
-
|
|
564
|
-
Args:
|
|
565
|
-
session (Session): The session data to upsert.
|
|
566
|
-
|
|
567
|
-
Returns:
|
|
568
|
-
Optional[Session]: The upserted Session, or None if operation failed.
|
|
569
|
-
"""
|
|
570
|
-
try:
|
|
571
|
-
if self.mode == "workflow_v2":
|
|
572
|
-
item = session.to_dict()
|
|
573
|
-
else:
|
|
574
|
-
item = asdict(session)
|
|
575
|
-
|
|
576
|
-
# Add timestamps
|
|
577
|
-
current_time = int(time.time())
|
|
578
|
-
if "created_at" not in item or item["created_at"] is None:
|
|
579
|
-
item["created_at"] = current_time
|
|
580
|
-
item["updated_at"] = current_time
|
|
581
|
-
|
|
582
|
-
# Convert data to DynamoDB compatible format
|
|
583
|
-
item = self._serialize_item(item)
|
|
584
|
-
|
|
585
|
-
# Put item into DynamoDB
|
|
586
|
-
self.table.put_item(Item=item)
|
|
587
|
-
return self.read(session.session_id)
|
|
588
|
-
except Exception as e:
|
|
589
|
-
logger.error(f"Error upserting session: {e}")
|
|
590
|
-
return None
|
|
591
|
-
|
|
592
|
-
def delete_session(self, session_id: Optional[str] = None):
|
|
593
|
-
"""
|
|
594
|
-
Delete a session from the database.
|
|
595
|
-
|
|
596
|
-
Args:
|
|
597
|
-
session_id (Optional[str], optional): ID of the session to delete. Defaults to None.
|
|
598
|
-
"""
|
|
599
|
-
if session_id is None:
|
|
600
|
-
logger.warning("No session_id provided for deletion.")
|
|
601
|
-
return
|
|
602
|
-
try:
|
|
603
|
-
self.table.delete_item(Key={"session_id": session_id})
|
|
604
|
-
log_info(f"Successfully deleted session with session_id: {session_id}")
|
|
605
|
-
except Exception as e:
|
|
606
|
-
logger.error(f"Error deleting session: {e}")
|
|
607
|
-
|
|
608
|
-
def drop(self) -> None:
|
|
609
|
-
"""
|
|
610
|
-
Drop the table from the database if it exists.
|
|
611
|
-
"""
|
|
612
|
-
try:
|
|
613
|
-
self.table.delete()
|
|
614
|
-
self.table.wait_until_not_exists()
|
|
615
|
-
log_debug(f"Table '{self.table_name}' deleted successfully.")
|
|
616
|
-
except Exception as e:
|
|
617
|
-
logger.error(f"Error deleting table '{self.table_name}': {e}")
|
|
618
|
-
|
|
619
|
-
def upgrade_schema(self) -> None:
|
|
620
|
-
"""
|
|
621
|
-
Upgrade the schema to the latest version.
|
|
622
|
-
This method is currently a placeholder and does not perform any actions.
|
|
623
|
-
"""
|
|
624
|
-
pass
|
|
625
|
-
|
|
626
|
-
def _serialize_item(self, item: Dict[str, Any]) -> Dict[str, Any]:
|
|
627
|
-
"""
|
|
628
|
-
Serialize item to be compatible with DynamoDB.
|
|
629
|
-
|
|
630
|
-
Args:
|
|
631
|
-
item (Dict[str, Any]): The item to serialize.
|
|
632
|
-
|
|
633
|
-
Returns:
|
|
634
|
-
Dict[str, Any]: The serialized item.
|
|
635
|
-
"""
|
|
636
|
-
|
|
637
|
-
def serialize_value(value):
|
|
638
|
-
if isinstance(value, float):
|
|
639
|
-
return Decimal(str(value))
|
|
640
|
-
elif isinstance(value, dict):
|
|
641
|
-
return {k: serialize_value(v) for k, v in value.items()}
|
|
642
|
-
elif isinstance(value, list):
|
|
643
|
-
return [serialize_value(v) for v in value]
|
|
644
|
-
else:
|
|
645
|
-
return value
|
|
646
|
-
|
|
647
|
-
return {k: serialize_value(v) for k, v in item.items() if v is not None}
|
|
648
|
-
|
|
649
|
-
def _deserialize_item(self, item: Dict[str, Any]) -> Dict[str, Any]:
|
|
650
|
-
"""
|
|
651
|
-
Deserialize item from DynamoDB format.
|
|
652
|
-
|
|
653
|
-
Args:
|
|
654
|
-
item (Dict[str, Any]): The item to deserialize.
|
|
655
|
-
|
|
656
|
-
Returns:
|
|
657
|
-
Dict[str, Any]: The deserialized item.
|
|
658
|
-
"""
|
|
659
|
-
|
|
660
|
-
def deserialize_value(value):
|
|
661
|
-
if isinstance(value, Decimal):
|
|
662
|
-
if value % 1 == 0:
|
|
663
|
-
return int(value)
|
|
664
|
-
else:
|
|
665
|
-
return float(value)
|
|
666
|
-
elif isinstance(value, dict):
|
|
667
|
-
return {k: deserialize_value(v) for k, v in value.items()}
|
|
668
|
-
elif isinstance(value, list):
|
|
669
|
-
return [deserialize_value(v) for v in value]
|
|
670
|
-
else:
|
|
671
|
-
return value
|
|
672
|
-
|
|
673
|
-
return {k: deserialize_value(v) for k, v in item.items()}
|