agno 0.1.2__py3-none-any.whl → 2.3.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agno/__init__.py +8 -0
- agno/agent/__init__.py +44 -5
- agno/agent/agent.py +10531 -2975
- agno/api/agent.py +14 -53
- agno/api/api.py +7 -46
- agno/api/evals.py +22 -0
- agno/api/os.py +17 -0
- agno/api/routes.py +6 -25
- agno/api/schemas/__init__.py +9 -0
- agno/api/schemas/agent.py +6 -9
- agno/api/schemas/evals.py +16 -0
- agno/api/schemas/os.py +14 -0
- agno/api/schemas/team.py +10 -10
- agno/api/schemas/utils.py +21 -0
- agno/api/schemas/workflows.py +16 -0
- agno/api/settings.py +53 -0
- agno/api/team.py +22 -26
- agno/api/workflow.py +28 -0
- agno/cloud/aws/base.py +214 -0
- agno/cloud/aws/s3/__init__.py +2 -0
- agno/cloud/aws/s3/api_client.py +43 -0
- agno/cloud/aws/s3/bucket.py +195 -0
- agno/cloud/aws/s3/object.py +57 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/__init__.py +24 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +946 -0
- agno/db/dynamo/__init__.py +3 -0
- agno/db/dynamo/dynamo.py +2781 -0
- agno/db/dynamo/schemas.py +442 -0
- agno/db/dynamo/utils.py +743 -0
- agno/db/firestore/__init__.py +3 -0
- agno/db/firestore/firestore.py +2379 -0
- agno/db/firestore/schemas.py +181 -0
- agno/db/firestore/utils.py +376 -0
- agno/db/gcs_json/__init__.py +3 -0
- agno/db/gcs_json/gcs_json_db.py +1791 -0
- agno/db/gcs_json/utils.py +228 -0
- agno/db/in_memory/__init__.py +3 -0
- agno/db/in_memory/in_memory_db.py +1312 -0
- agno/db/in_memory/utils.py +230 -0
- agno/db/json/__init__.py +3 -0
- agno/db/json/json_db.py +1777 -0
- agno/db/json/utils.py +230 -0
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +635 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +17 -0
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +2597 -0
- agno/db/mongo/schemas.py +119 -0
- agno/db/mongo/utils.py +276 -0
- agno/db/mysql/__init__.py +4 -0
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +2923 -0
- agno/db/mysql/schemas.py +186 -0
- agno/db/mysql/utils.py +488 -0
- agno/db/postgres/__init__.py +4 -0
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +2870 -0
- agno/db/postgres/schemas.py +187 -0
- agno/db/postgres/utils.py +442 -0
- agno/db/redis/__init__.py +3 -0
- agno/db/redis/redis.py +2141 -0
- agno/db/redis/schemas.py +159 -0
- agno/db/redis/utils.py +346 -0
- agno/db/schemas/__init__.py +4 -0
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +34 -0
- agno/db/schemas/knowledge.py +40 -0
- agno/db/schemas/memory.py +61 -0
- agno/db/singlestore/__init__.py +3 -0
- agno/db/singlestore/schemas.py +179 -0
- agno/db/singlestore/singlestore.py +2877 -0
- agno/db/singlestore/utils.py +384 -0
- agno/db/sqlite/__init__.py +4 -0
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +181 -0
- agno/db/sqlite/sqlite.py +2908 -0
- agno/db/sqlite/utils.py +429 -0
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +334 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1908 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +118 -0
- agno/eval/__init__.py +24 -0
- agno/eval/accuracy.py +666 -276
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +779 -0
- agno/eval/reliability.py +241 -62
- agno/eval/utils.py +120 -0
- agno/exceptions.py +143 -1
- agno/filters.py +354 -0
- agno/guardrails/__init__.py +6 -0
- agno/guardrails/base.py +19 -0
- agno/guardrails/openai.py +144 -0
- agno/guardrails/pii.py +94 -0
- agno/guardrails/prompt_injection.py +52 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/__init__.py +3 -0
- agno/integrations/discord/client.py +203 -0
- agno/knowledge/__init__.py +5 -1
- agno/{document → knowledge}/chunking/agentic.py +22 -14
- agno/{document → knowledge}/chunking/document.py +2 -2
- agno/{document → knowledge}/chunking/fixed.py +7 -6
- agno/knowledge/chunking/markdown.py +151 -0
- agno/{document → knowledge}/chunking/recursive.py +15 -3
- agno/knowledge/chunking/row.py +39 -0
- agno/knowledge/chunking/semantic.py +91 -0
- agno/knowledge/chunking/strategy.py +165 -0
- agno/knowledge/content.py +74 -0
- agno/knowledge/document/__init__.py +5 -0
- agno/{document → knowledge/document}/base.py +12 -2
- agno/knowledge/embedder/__init__.py +5 -0
- agno/knowledge/embedder/aws_bedrock.py +343 -0
- agno/knowledge/embedder/azure_openai.py +210 -0
- agno/{embedder → knowledge/embedder}/base.py +8 -0
- agno/knowledge/embedder/cohere.py +323 -0
- agno/knowledge/embedder/fastembed.py +62 -0
- agno/{embedder → knowledge/embedder}/fireworks.py +1 -1
- agno/knowledge/embedder/google.py +258 -0
- agno/knowledge/embedder/huggingface.py +94 -0
- agno/knowledge/embedder/jina.py +182 -0
- agno/knowledge/embedder/langdb.py +22 -0
- agno/knowledge/embedder/mistral.py +206 -0
- agno/knowledge/embedder/nebius.py +13 -0
- agno/knowledge/embedder/ollama.py +154 -0
- agno/knowledge/embedder/openai.py +195 -0
- agno/knowledge/embedder/sentence_transformer.py +63 -0
- agno/{embedder → knowledge/embedder}/together.py +1 -1
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +165 -0
- agno/knowledge/knowledge.py +3006 -0
- agno/knowledge/reader/__init__.py +7 -0
- agno/knowledge/reader/arxiv_reader.py +81 -0
- agno/knowledge/reader/base.py +95 -0
- agno/knowledge/reader/csv_reader.py +164 -0
- agno/knowledge/reader/docx_reader.py +82 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +290 -0
- agno/knowledge/reader/firecrawl_reader.py +201 -0
- agno/knowledge/reader/json_reader.py +88 -0
- agno/knowledge/reader/markdown_reader.py +137 -0
- agno/knowledge/reader/pdf_reader.py +431 -0
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +313 -0
- agno/knowledge/reader/s3_reader.py +89 -0
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +127 -0
- agno/knowledge/reader/web_search_reader.py +325 -0
- agno/knowledge/reader/website_reader.py +455 -0
- agno/knowledge/reader/wikipedia_reader.py +91 -0
- agno/knowledge/reader/youtube_reader.py +78 -0
- agno/knowledge/remote_content/remote_content.py +88 -0
- agno/knowledge/reranker/__init__.py +3 -0
- agno/{reranker → knowledge/reranker}/base.py +1 -1
- agno/{reranker → knowledge/reranker}/cohere.py +2 -2
- agno/knowledge/reranker/infinity.py +195 -0
- agno/knowledge/reranker/sentence_transformer.py +54 -0
- agno/knowledge/types.py +39 -0
- agno/knowledge/utils.py +234 -0
- agno/media.py +439 -95
- agno/memory/__init__.py +16 -3
- agno/memory/manager.py +1474 -123
- agno/memory/strategies/__init__.py +15 -0
- agno/memory/strategies/base.py +66 -0
- agno/memory/strategies/summarize.py +196 -0
- agno/memory/strategies/types.py +37 -0
- agno/models/aimlapi/__init__.py +5 -0
- agno/models/aimlapi/aimlapi.py +62 -0
- agno/models/anthropic/__init__.py +4 -0
- agno/models/anthropic/claude.py +960 -496
- agno/models/aws/__init__.py +15 -0
- agno/models/aws/bedrock.py +686 -451
- agno/models/aws/claude.py +190 -183
- agno/models/azure/__init__.py +18 -1
- agno/models/azure/ai_foundry.py +489 -0
- agno/models/azure/openai_chat.py +89 -40
- agno/models/base.py +2477 -550
- agno/models/cerebras/__init__.py +12 -0
- agno/models/cerebras/cerebras.py +565 -0
- agno/models/cerebras/cerebras_openai.py +131 -0
- agno/models/cohere/__init__.py +4 -0
- agno/models/cohere/chat.py +306 -492
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +74 -0
- agno/models/dashscope/__init__.py +5 -0
- agno/models/dashscope/dashscope.py +90 -0
- agno/models/deepinfra/__init__.py +5 -0
- agno/models/deepinfra/deepinfra.py +45 -0
- agno/models/deepseek/__init__.py +4 -0
- agno/models/deepseek/deepseek.py +110 -9
- agno/models/fireworks/__init__.py +4 -0
- agno/models/fireworks/fireworks.py +19 -22
- agno/models/google/__init__.py +3 -7
- agno/models/google/gemini.py +1717 -662
- agno/models/google/utils.py +22 -0
- agno/models/groq/__init__.py +4 -0
- agno/models/groq/groq.py +391 -666
- agno/models/huggingface/__init__.py +4 -0
- agno/models/huggingface/huggingface.py +266 -538
- agno/models/ibm/__init__.py +5 -0
- agno/models/ibm/watsonx.py +432 -0
- agno/models/internlm/__init__.py +3 -0
- agno/models/internlm/internlm.py +20 -3
- agno/models/langdb/__init__.py +1 -0
- agno/models/langdb/langdb.py +60 -0
- agno/models/litellm/__init__.py +14 -0
- agno/models/litellm/chat.py +503 -0
- agno/models/litellm/litellm_openai.py +42 -0
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/lmstudio/__init__.py +5 -0
- agno/models/lmstudio/lmstudio.py +25 -0
- agno/models/message.py +361 -39
- agno/models/meta/__init__.py +12 -0
- agno/models/meta/llama.py +502 -0
- agno/models/meta/llama_openai.py +79 -0
- agno/models/metrics.py +120 -0
- agno/models/mistral/__init__.py +4 -0
- agno/models/mistral/mistral.py +293 -393
- agno/models/nebius/__init__.py +3 -0
- agno/models/nebius/nebius.py +53 -0
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/__init__.py +4 -0
- agno/models/nvidia/nvidia.py +22 -3
- agno/models/ollama/__init__.py +4 -2
- agno/models/ollama/chat.py +257 -492
- agno/models/openai/__init__.py +7 -0
- agno/models/openai/chat.py +725 -770
- agno/models/openai/like.py +16 -2
- agno/models/openai/responses.py +1121 -0
- agno/models/openrouter/__init__.py +4 -0
- agno/models/openrouter/openrouter.py +62 -5
- agno/models/perplexity/__init__.py +5 -0
- agno/models/perplexity/perplexity.py +203 -0
- agno/models/portkey/__init__.py +3 -0
- agno/models/portkey/portkey.py +82 -0
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +69 -0
- agno/models/response.py +177 -7
- agno/models/sambanova/__init__.py +4 -0
- agno/models/sambanova/sambanova.py +23 -4
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +42 -0
- agno/models/together/__init__.py +4 -0
- agno/models/together/together.py +21 -164
- agno/models/utils.py +266 -0
- agno/models/vercel/__init__.py +3 -0
- agno/models/vercel/v0.py +43 -0
- agno/models/vertexai/__init__.py +0 -1
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/__init__.py +3 -0
- agno/models/vllm/vllm.py +83 -0
- agno/models/xai/__init__.py +2 -0
- agno/models/xai/xai.py +111 -7
- agno/os/__init__.py +3 -0
- agno/os/app.py +1027 -0
- agno/os/auth.py +244 -0
- agno/os/config.py +126 -0
- agno/os/interfaces/__init__.py +1 -0
- agno/os/interfaces/a2a/__init__.py +3 -0
- agno/os/interfaces/a2a/a2a.py +42 -0
- agno/os/interfaces/a2a/router.py +249 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/__init__.py +3 -0
- agno/os/interfaces/agui/agui.py +47 -0
- agno/os/interfaces/agui/router.py +147 -0
- agno/os/interfaces/agui/utils.py +574 -0
- agno/os/interfaces/base.py +25 -0
- agno/os/interfaces/slack/__init__.py +3 -0
- agno/os/interfaces/slack/router.py +148 -0
- agno/os/interfaces/slack/security.py +30 -0
- agno/os/interfaces/slack/slack.py +47 -0
- agno/os/interfaces/whatsapp/__init__.py +3 -0
- agno/os/interfaces/whatsapp/router.py +210 -0
- agno/os/interfaces/whatsapp/security.py +55 -0
- agno/os/interfaces/whatsapp/whatsapp.py +36 -0
- agno/os/mcp.py +293 -0
- agno/os/middleware/__init__.py +9 -0
- agno/os/middleware/jwt.py +797 -0
- agno/os/router.py +258 -0
- agno/os/routers/__init__.py +3 -0
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +599 -0
- agno/os/routers/agents/schema.py +261 -0
- agno/os/routers/evals/__init__.py +3 -0
- agno/os/routers/evals/evals.py +450 -0
- agno/os/routers/evals/schemas.py +174 -0
- agno/os/routers/evals/utils.py +231 -0
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/__init__.py +3 -0
- agno/os/routers/knowledge/knowledge.py +1008 -0
- agno/os/routers/knowledge/schemas.py +178 -0
- agno/os/routers/memory/__init__.py +3 -0
- agno/os/routers/memory/memory.py +661 -0
- agno/os/routers/memory/schemas.py +88 -0
- agno/os/routers/metrics/__init__.py +3 -0
- agno/os/routers/metrics/metrics.py +190 -0
- agno/os/routers/metrics/schemas.py +47 -0
- agno/os/routers/session/__init__.py +3 -0
- agno/os/routers/session/session.py +997 -0
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +512 -0
- agno/os/routers/teams/schema.py +257 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +499 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +624 -0
- agno/os/routers/workflows/schema.py +75 -0
- agno/os/schema.py +534 -0
- agno/os/scopes.py +469 -0
- agno/{playground → os}/settings.py +7 -15
- agno/os/utils.py +973 -0
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +67 -0
- agno/reasoning/deepseek.py +63 -0
- agno/reasoning/default.py +97 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +71 -0
- agno/reasoning/helpers.py +24 -1
- agno/reasoning/ollama.py +67 -0
- agno/reasoning/openai.py +86 -0
- agno/reasoning/step.py +2 -1
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +822 -0
- agno/run/base.py +247 -0
- agno/run/cancel.py +81 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +767 -0
- agno/run/workflow.py +708 -0
- agno/session/__init__.py +10 -0
- agno/session/agent.py +260 -0
- agno/session/summary.py +265 -0
- agno/session/team.py +342 -0
- agno/session/workflow.py +501 -0
- agno/table.py +10 -0
- agno/team/__init__.py +37 -0
- agno/team/team.py +9536 -0
- agno/tools/__init__.py +7 -0
- agno/tools/agentql.py +120 -0
- agno/tools/airflow.py +22 -12
- agno/tools/api.py +122 -0
- agno/tools/apify.py +276 -83
- agno/tools/{arxiv_toolkit.py → arxiv.py} +20 -12
- agno/tools/aws_lambda.py +28 -7
- agno/tools/aws_ses.py +66 -0
- agno/tools/baidusearch.py +11 -4
- agno/tools/bitbucket.py +292 -0
- agno/tools/brandfetch.py +213 -0
- agno/tools/bravesearch.py +106 -0
- agno/tools/brightdata.py +367 -0
- agno/tools/browserbase.py +209 -0
- agno/tools/calcom.py +32 -23
- agno/tools/calculator.py +24 -37
- agno/tools/cartesia.py +187 -0
- agno/tools/{clickup_tool.py → clickup.py} +17 -28
- agno/tools/confluence.py +91 -26
- agno/tools/crawl4ai.py +139 -43
- agno/tools/csv_toolkit.py +28 -22
- agno/tools/dalle.py +36 -22
- agno/tools/daytona.py +475 -0
- agno/tools/decorator.py +169 -14
- agno/tools/desi_vocal.py +23 -11
- agno/tools/discord.py +32 -29
- agno/tools/docker.py +716 -0
- agno/tools/duckdb.py +76 -81
- agno/tools/duckduckgo.py +43 -40
- agno/tools/e2b.py +703 -0
- agno/tools/eleven_labs.py +65 -54
- agno/tools/email.py +13 -5
- agno/tools/evm.py +129 -0
- agno/tools/exa.py +324 -42
- agno/tools/fal.py +39 -35
- agno/tools/file.py +196 -30
- agno/tools/file_generation.py +356 -0
- agno/tools/financial_datasets.py +288 -0
- agno/tools/firecrawl.py +108 -33
- agno/tools/function.py +960 -122
- agno/tools/giphy.py +34 -12
- agno/tools/github.py +1294 -97
- agno/tools/gmail.py +922 -0
- agno/tools/google_bigquery.py +117 -0
- agno/tools/google_drive.py +271 -0
- agno/tools/google_maps.py +253 -0
- agno/tools/googlecalendar.py +607 -107
- agno/tools/googlesheets.py +377 -0
- agno/tools/hackernews.py +20 -12
- agno/tools/jina.py +24 -14
- agno/tools/jira.py +48 -19
- agno/tools/knowledge.py +218 -0
- agno/tools/linear.py +82 -43
- agno/tools/linkup.py +58 -0
- agno/tools/local_file_system.py +15 -7
- agno/tools/lumalab.py +41 -26
- agno/tools/mcp/__init__.py +10 -0
- agno/tools/mcp/mcp.py +331 -0
- agno/tools/mcp/multi_mcp.py +347 -0
- agno/tools/mcp/params.py +24 -0
- agno/tools/mcp_toolbox.py +284 -0
- agno/tools/mem0.py +193 -0
- agno/tools/memory.py +419 -0
- agno/tools/mlx_transcribe.py +11 -9
- agno/tools/models/azure_openai.py +190 -0
- agno/tools/models/gemini.py +203 -0
- agno/tools/models/groq.py +158 -0
- agno/tools/models/morph.py +186 -0
- agno/tools/models/nebius.py +124 -0
- agno/tools/models_labs.py +163 -82
- agno/tools/moviepy_video.py +18 -13
- agno/tools/nano_banana.py +151 -0
- agno/tools/neo4j.py +134 -0
- agno/tools/newspaper.py +15 -4
- agno/tools/newspaper4k.py +19 -6
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +181 -17
- agno/tools/openbb.py +27 -20
- agno/tools/opencv.py +321 -0
- agno/tools/openweather.py +233 -0
- agno/tools/oxylabs.py +385 -0
- agno/tools/pandas.py +25 -15
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +238 -185
- agno/tools/pubmed.py +125 -13
- agno/tools/python.py +48 -35
- agno/tools/reasoning.py +283 -0
- agno/tools/reddit.py +207 -29
- agno/tools/redshift.py +406 -0
- agno/tools/replicate.py +69 -26
- agno/tools/resend.py +11 -6
- agno/tools/scrapegraph.py +179 -19
- agno/tools/searxng.py +23 -31
- agno/tools/serpapi.py +15 -10
- agno/tools/serper.py +255 -0
- agno/tools/shell.py +23 -12
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +56 -14
- agno/tools/sleep.py +8 -6
- agno/tools/spider.py +35 -11
- agno/tools/spotify.py +919 -0
- agno/tools/sql.py +34 -19
- agno/tools/tavily.py +158 -8
- agno/tools/telegram.py +18 -8
- agno/tools/todoist.py +218 -0
- agno/tools/toolkit.py +134 -9
- agno/tools/trafilatura.py +388 -0
- agno/tools/trello.py +25 -28
- agno/tools/twilio.py +18 -9
- agno/tools/user_control_flow.py +78 -0
- agno/tools/valyu.py +228 -0
- agno/tools/visualization.py +467 -0
- agno/tools/webbrowser.py +28 -0
- agno/tools/webex.py +76 -0
- agno/tools/website.py +23 -19
- agno/tools/webtools.py +45 -0
- agno/tools/whatsapp.py +286 -0
- agno/tools/wikipedia.py +28 -19
- agno/tools/workflow.py +285 -0
- agno/tools/{twitter.py → x.py} +142 -46
- agno/tools/yfinance.py +41 -39
- agno/tools/youtube.py +34 -17
- agno/tools/zendesk.py +15 -5
- agno/tools/zep.py +454 -0
- agno/tools/zoom.py +86 -37
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +157 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +111 -0
- agno/utils/agent.py +938 -0
- agno/utils/audio.py +37 -1
- agno/utils/certs.py +27 -0
- agno/utils/code_execution.py +11 -0
- agno/utils/common.py +103 -20
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +700 -0
- agno/utils/functions.py +107 -37
- agno/utils/gemini.py +426 -0
- agno/utils/hooks.py +171 -0
- agno/utils/http.py +185 -0
- agno/utils/json_schema.py +159 -37
- agno/utils/knowledge.py +36 -0
- agno/utils/location.py +19 -0
- agno/utils/log.py +221 -8
- agno/utils/mcp.py +214 -0
- agno/utils/media.py +335 -14
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +77 -2
- agno/utils/models/ai_foundry.py +50 -0
- agno/utils/models/claude.py +373 -0
- agno/utils/models/cohere.py +94 -0
- agno/utils/models/llama.py +85 -0
- agno/utils/models/mistral.py +100 -0
- agno/utils/models/openai_responses.py +140 -0
- agno/utils/models/schema_utils.py +153 -0
- agno/utils/models/watsonx.py +41 -0
- agno/utils/openai.py +257 -0
- agno/utils/pickle.py +1 -1
- agno/utils/pprint.py +124 -8
- agno/utils/print_response/agent.py +930 -0
- agno/utils/print_response/team.py +1914 -0
- agno/utils/print_response/workflow.py +1668 -0
- agno/utils/prompts.py +111 -0
- agno/utils/reasoning.py +108 -0
- agno/utils/response.py +163 -0
- agno/utils/serialize.py +32 -0
- agno/utils/shell.py +4 -4
- agno/utils/streamlit.py +487 -0
- agno/utils/string.py +204 -51
- agno/utils/team.py +139 -0
- agno/utils/timer.py +9 -2
- agno/utils/tokens.py +657 -0
- agno/utils/tools.py +19 -1
- agno/utils/whatsapp.py +305 -0
- agno/utils/yaml_io.py +3 -3
- agno/vectordb/__init__.py +2 -0
- agno/vectordb/base.py +87 -9
- agno/vectordb/cassandra/__init__.py +5 -1
- agno/vectordb/cassandra/cassandra.py +383 -27
- agno/vectordb/chroma/__init__.py +4 -0
- agno/vectordb/chroma/chromadb.py +748 -83
- agno/vectordb/clickhouse/__init__.py +7 -1
- agno/vectordb/clickhouse/clickhousedb.py +554 -53
- agno/vectordb/couchbase/__init__.py +3 -0
- agno/vectordb/couchbase/couchbase.py +1446 -0
- agno/vectordb/lancedb/__init__.py +5 -0
- agno/vectordb/lancedb/lance_db.py +730 -98
- agno/vectordb/langchaindb/__init__.py +5 -0
- agno/vectordb/langchaindb/langchaindb.py +163 -0
- agno/vectordb/lightrag/__init__.py +5 -0
- agno/vectordb/lightrag/lightrag.py +388 -0
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +166 -0
- agno/vectordb/milvus/__init__.py +3 -0
- agno/vectordb/milvus/milvus.py +966 -78
- agno/vectordb/mongodb/__init__.py +9 -1
- agno/vectordb/mongodb/mongodb.py +1175 -172
- agno/vectordb/pgvector/__init__.py +8 -0
- agno/vectordb/pgvector/pgvector.py +599 -115
- agno/vectordb/pineconedb/__init__.py +5 -1
- agno/vectordb/pineconedb/pineconedb.py +406 -43
- agno/vectordb/qdrant/__init__.py +4 -0
- agno/vectordb/qdrant/qdrant.py +914 -61
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/__init__.py +8 -1
- agno/vectordb/singlestore/singlestore.py +771 -0
- agno/vectordb/surrealdb/__init__.py +3 -0
- agno/vectordb/surrealdb/surrealdb.py +663 -0
- agno/vectordb/upstashdb/__init__.py +5 -0
- agno/vectordb/upstashdb/upstashdb.py +718 -0
- agno/vectordb/weaviate/__init__.py +8 -0
- agno/vectordb/weaviate/index.py +15 -0
- agno/vectordb/weaviate/weaviate.py +1009 -0
- agno/workflow/__init__.py +23 -1
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +759 -0
- agno/workflow/loop.py +756 -0
- agno/workflow/parallel.py +853 -0
- agno/workflow/router.py +723 -0
- agno/workflow/step.py +1564 -0
- agno/workflow/steps.py +613 -0
- agno/workflow/types.py +556 -0
- agno/workflow/workflow.py +4327 -514
- agno-2.3.13.dist-info/METADATA +639 -0
- agno-2.3.13.dist-info/RECORD +613 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +1 -1
- agno-2.3.13.dist-info/licenses/LICENSE +201 -0
- agno/api/playground.py +0 -91
- agno/api/schemas/playground.py +0 -22
- agno/api/schemas/user.py +0 -22
- agno/api/schemas/workspace.py +0 -46
- agno/api/user.py +0 -160
- agno/api/workspace.py +0 -151
- agno/cli/auth_server.py +0 -118
- agno/cli/config.py +0 -275
- agno/cli/console.py +0 -88
- agno/cli/credentials.py +0 -23
- agno/cli/entrypoint.py +0 -571
- agno/cli/operator.py +0 -355
- agno/cli/settings.py +0 -85
- agno/cli/ws/ws_cli.py +0 -817
- agno/constants.py +0 -13
- agno/document/__init__.py +0 -1
- agno/document/chunking/semantic.py +0 -47
- agno/document/chunking/strategy.py +0 -31
- agno/document/reader/__init__.py +0 -1
- agno/document/reader/arxiv_reader.py +0 -41
- agno/document/reader/base.py +0 -22
- agno/document/reader/csv_reader.py +0 -84
- agno/document/reader/docx_reader.py +0 -46
- agno/document/reader/firecrawl_reader.py +0 -99
- agno/document/reader/json_reader.py +0 -43
- agno/document/reader/pdf_reader.py +0 -219
- agno/document/reader/s3/pdf_reader.py +0 -46
- agno/document/reader/s3/text_reader.py +0 -51
- agno/document/reader/text_reader.py +0 -41
- agno/document/reader/website_reader.py +0 -175
- agno/document/reader/youtube_reader.py +0 -50
- agno/embedder/__init__.py +0 -1
- agno/embedder/azure_openai.py +0 -86
- agno/embedder/cohere.py +0 -72
- agno/embedder/fastembed.py +0 -37
- agno/embedder/google.py +0 -73
- agno/embedder/huggingface.py +0 -54
- agno/embedder/mistral.py +0 -80
- agno/embedder/ollama.py +0 -57
- agno/embedder/openai.py +0 -74
- agno/embedder/sentence_transformer.py +0 -38
- agno/embedder/voyageai.py +0 -64
- agno/eval/perf.py +0 -201
- agno/file/__init__.py +0 -1
- agno/file/file.py +0 -16
- agno/file/local/csv.py +0 -32
- agno/file/local/txt.py +0 -19
- agno/infra/app.py +0 -240
- agno/infra/base.py +0 -144
- agno/infra/context.py +0 -20
- agno/infra/db_app.py +0 -52
- agno/infra/resource.py +0 -205
- agno/infra/resources.py +0 -55
- agno/knowledge/agent.py +0 -230
- agno/knowledge/arxiv.py +0 -22
- agno/knowledge/combined.py +0 -22
- agno/knowledge/csv.py +0 -28
- agno/knowledge/csv_url.py +0 -19
- agno/knowledge/document.py +0 -20
- agno/knowledge/docx.py +0 -30
- agno/knowledge/json.py +0 -28
- agno/knowledge/langchain.py +0 -71
- agno/knowledge/llamaindex.py +0 -66
- agno/knowledge/pdf.py +0 -28
- agno/knowledge/pdf_url.py +0 -26
- agno/knowledge/s3/base.py +0 -60
- agno/knowledge/s3/pdf.py +0 -21
- agno/knowledge/s3/text.py +0 -23
- agno/knowledge/text.py +0 -30
- agno/knowledge/website.py +0 -88
- agno/knowledge/wikipedia.py +0 -31
- agno/knowledge/youtube.py +0 -22
- agno/memory/agent.py +0 -392
- agno/memory/classifier.py +0 -104
- agno/memory/db/__init__.py +0 -1
- agno/memory/db/base.py +0 -42
- agno/memory/db/mongodb.py +0 -189
- agno/memory/db/postgres.py +0 -203
- agno/memory/db/sqlite.py +0 -193
- agno/memory/memory.py +0 -15
- agno/memory/row.py +0 -36
- agno/memory/summarizer.py +0 -192
- agno/memory/summary.py +0 -19
- agno/memory/workflow.py +0 -38
- agno/models/google/gemini_openai.py +0 -26
- agno/models/ollama/hermes.py +0 -221
- agno/models/ollama/tools.py +0 -362
- agno/models/vertexai/gemini.py +0 -595
- agno/playground/__init__.py +0 -3
- agno/playground/async_router.py +0 -421
- agno/playground/deploy.py +0 -249
- agno/playground/operator.py +0 -92
- agno/playground/playground.py +0 -91
- agno/playground/schemas.py +0 -76
- agno/playground/serve.py +0 -55
- agno/playground/sync_router.py +0 -405
- agno/reasoning/agent.py +0 -68
- agno/run/response.py +0 -112
- agno/storage/agent/__init__.py +0 -0
- agno/storage/agent/base.py +0 -38
- agno/storage/agent/dynamodb.py +0 -350
- agno/storage/agent/json.py +0 -92
- agno/storage/agent/mongodb.py +0 -228
- agno/storage/agent/postgres.py +0 -367
- agno/storage/agent/session.py +0 -79
- agno/storage/agent/singlestore.py +0 -303
- agno/storage/agent/sqlite.py +0 -357
- agno/storage/agent/yaml.py +0 -93
- agno/storage/workflow/__init__.py +0 -0
- agno/storage/workflow/base.py +0 -40
- agno/storage/workflow/mongodb.py +0 -233
- agno/storage/workflow/postgres.py +0 -366
- agno/storage/workflow/session.py +0 -60
- agno/storage/workflow/sqlite.py +0 -359
- agno/tools/googlesearch.py +0 -88
- agno/utils/defaults.py +0 -57
- agno/utils/filesystem.py +0 -39
- agno/utils/git.py +0 -52
- agno/utils/json_io.py +0 -30
- agno/utils/load_env.py +0 -19
- agno/utils/py_io.py +0 -19
- agno/utils/pyproject.py +0 -18
- agno/utils/resource_filter.py +0 -31
- agno/vectordb/singlestore/s2vectordb.py +0 -390
- agno/vectordb/singlestore/s2vectordb2.py +0 -355
- agno/workspace/__init__.py +0 -0
- agno/workspace/config.py +0 -325
- agno/workspace/enums.py +0 -6
- agno/workspace/helpers.py +0 -48
- agno/workspace/operator.py +0 -758
- agno/workspace/settings.py +0 -63
- agno-0.1.2.dist-info/LICENSE +0 -375
- agno-0.1.2.dist-info/METADATA +0 -502
- agno-0.1.2.dist-info/RECORD +0 -352
- agno-0.1.2.dist-info/entry_points.txt +0 -3
- /agno/{cli → db/migrations}/__init__.py +0 -0
- /agno/{cli/ws → db/migrations/versions}/__init__.py +0 -0
- /agno/{document/chunking/__init__.py → db/schemas/metrics.py} +0 -0
- /agno/{document/reader/s3 → integrations}/__init__.py +0 -0
- /agno/{file/local → knowledge/chunking}/__init__.py +0 -0
- /agno/{infra → knowledge/remote_content}/__init__.py +0 -0
- /agno/{knowledge/s3 → tools/models}/__init__.py +0 -0
- /agno/{reranker → utils/models}/__init__.py +0 -0
- /agno/{storage → utils/print_response}/__init__.py +0 -0
- {agno-0.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/session/__init__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from typing import Union
|
|
2
|
+
|
|
3
|
+
from agno.session.agent import AgentSession
|
|
4
|
+
from agno.session.summary import SessionSummaryManager
|
|
5
|
+
from agno.session.team import TeamSession
|
|
6
|
+
from agno.session.workflow import WorkflowSession
|
|
7
|
+
|
|
8
|
+
Session = Union[AgentSession, TeamSession, WorkflowSession]
|
|
9
|
+
|
|
10
|
+
__all__ = ["AgentSession", "TeamSession", "WorkflowSession", "Session", "SessionSummaryManager"]
|
agno/session/agent.py
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import asdict, dataclass
|
|
4
|
+
from typing import Any, Dict, List, Mapping, Optional, Union
|
|
5
|
+
|
|
6
|
+
from agno.models.message import Message
|
|
7
|
+
from agno.run.agent import RunOutput
|
|
8
|
+
from agno.run.base import RunStatus
|
|
9
|
+
from agno.run.team import TeamRunOutput
|
|
10
|
+
from agno.session.summary import SessionSummary
|
|
11
|
+
from agno.utils.log import log_debug, log_warning
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class AgentSession:
|
|
16
|
+
"""Agent Session that is stored in the database"""
|
|
17
|
+
|
|
18
|
+
# Session UUID
|
|
19
|
+
session_id: str
|
|
20
|
+
|
|
21
|
+
# ID of the agent that this session is associated with
|
|
22
|
+
agent_id: Optional[str] = None
|
|
23
|
+
# ID of the team that this session is associated with
|
|
24
|
+
team_id: Optional[str] = None
|
|
25
|
+
# # ID of the user interacting with this agent
|
|
26
|
+
user_id: Optional[str] = None
|
|
27
|
+
# ID of the workflow that this session is associated with
|
|
28
|
+
workflow_id: Optional[str] = None
|
|
29
|
+
|
|
30
|
+
# Session Data: session_name, session_state, images, videos, audio
|
|
31
|
+
session_data: Optional[Dict[str, Any]] = None
|
|
32
|
+
# Metadata stored with this agent
|
|
33
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
34
|
+
# Agent Data: agent_id, name and model
|
|
35
|
+
agent_data: Optional[Dict[str, Any]] = None
|
|
36
|
+
# List of all runs in the session
|
|
37
|
+
runs: Optional[List[Union[RunOutput, TeamRunOutput]]] = None
|
|
38
|
+
# Summary of the session
|
|
39
|
+
summary: Optional["SessionSummary"] = None
|
|
40
|
+
|
|
41
|
+
# The unix timestamp when this session was created
|
|
42
|
+
created_at: Optional[int] = None
|
|
43
|
+
# The unix timestamp when this session was last updated
|
|
44
|
+
updated_at: Optional[int] = None
|
|
45
|
+
|
|
46
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
47
|
+
session_dict = asdict(self)
|
|
48
|
+
|
|
49
|
+
session_dict["runs"] = [run.to_dict() for run in self.runs] if self.runs else None
|
|
50
|
+
session_dict["summary"] = self.summary.to_dict() if self.summary else None
|
|
51
|
+
|
|
52
|
+
return session_dict
|
|
53
|
+
|
|
54
|
+
@classmethod
|
|
55
|
+
def from_dict(cls, data: Mapping[str, Any]) -> Optional[AgentSession]:
|
|
56
|
+
if data is None or data.get("session_id") is None:
|
|
57
|
+
log_warning("AgentSession is missing session_id")
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
runs = data.get("runs")
|
|
61
|
+
serialized_runs: List[Union[RunOutput, TeamRunOutput]] = []
|
|
62
|
+
if runs is not None and isinstance(runs[0], dict):
|
|
63
|
+
for run in runs:
|
|
64
|
+
if "agent_id" in run:
|
|
65
|
+
serialized_runs.append(RunOutput.from_dict(run))
|
|
66
|
+
elif "team_id" in run:
|
|
67
|
+
serialized_runs.append(TeamRunOutput.from_dict(run))
|
|
68
|
+
|
|
69
|
+
summary = data.get("summary")
|
|
70
|
+
if summary is not None and isinstance(summary, dict):
|
|
71
|
+
summary = SessionSummary.from_dict(summary)
|
|
72
|
+
|
|
73
|
+
metadata = data.get("metadata")
|
|
74
|
+
|
|
75
|
+
return cls(
|
|
76
|
+
session_id=data.get("session_id"), # type: ignore
|
|
77
|
+
agent_id=data.get("agent_id"),
|
|
78
|
+
user_id=data.get("user_id"),
|
|
79
|
+
workflow_id=data.get("workflow_id"),
|
|
80
|
+
team_id=data.get("team_id"),
|
|
81
|
+
agent_data=data.get("agent_data"),
|
|
82
|
+
session_data=data.get("session_data"),
|
|
83
|
+
metadata=metadata,
|
|
84
|
+
created_at=data.get("created_at"),
|
|
85
|
+
updated_at=data.get("updated_at"),
|
|
86
|
+
runs=serialized_runs,
|
|
87
|
+
summary=summary,
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def upsert_run(self, run: RunOutput):
|
|
91
|
+
"""Adds a RunOutput, together with some calculated data, to the runs list."""
|
|
92
|
+
messages = run.messages
|
|
93
|
+
for m in messages or []:
|
|
94
|
+
if m.metrics is not None:
|
|
95
|
+
m.metrics.duration = None
|
|
96
|
+
|
|
97
|
+
if not self.runs:
|
|
98
|
+
self.runs = []
|
|
99
|
+
|
|
100
|
+
for i, existing_run in enumerate(self.runs or []):
|
|
101
|
+
if existing_run.run_id == run.run_id:
|
|
102
|
+
self.runs[i] = run
|
|
103
|
+
break
|
|
104
|
+
else:
|
|
105
|
+
self.runs.append(run)
|
|
106
|
+
|
|
107
|
+
log_debug("Added RunOutput to Agent Session")
|
|
108
|
+
|
|
109
|
+
def get_run(self, run_id: str) -> Optional[Union[RunOutput, TeamRunOutput]]:
|
|
110
|
+
for run in self.runs or []:
|
|
111
|
+
if run.run_id == run_id:
|
|
112
|
+
return run
|
|
113
|
+
return None
|
|
114
|
+
|
|
115
|
+
def get_messages(
|
|
116
|
+
self,
|
|
117
|
+
agent_id: Optional[str] = None,
|
|
118
|
+
team_id: Optional[str] = None,
|
|
119
|
+
last_n_runs: Optional[int] = None,
|
|
120
|
+
limit: Optional[int] = None,
|
|
121
|
+
skip_roles: Optional[List[str]] = None,
|
|
122
|
+
skip_statuses: Optional[List[RunStatus]] = None,
|
|
123
|
+
skip_history_messages: bool = True,
|
|
124
|
+
) -> List[Message]:
|
|
125
|
+
"""Returns the messages belonging to the session that fit the given criteria.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
agent_id: The id of the agent to get the messages from.
|
|
129
|
+
team_id: The id of the team to get the messages from.
|
|
130
|
+
last_n_runs: The number of runs to return messages from, counting from the latest. Defaults to all runs.
|
|
131
|
+
last_n_messages: The number of messages to return, counting from the latest. Defaults to all messages.
|
|
132
|
+
skip_roles: Skip messages with these roles.
|
|
133
|
+
skip_statuses: Skip messages with these statuses.
|
|
134
|
+
skip_history_messages: Skip messages that were tagged as history in previous runs.
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
A list of Messages belonging to the session.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
def _should_skip_message(
|
|
141
|
+
message: Message, skip_roles: Optional[List[str]] = None, skip_history_messages: bool = True
|
|
142
|
+
) -> bool:
|
|
143
|
+
"""Logic to determine if a message should be skipped"""
|
|
144
|
+
# Skip messages that were tagged as history in previous runs
|
|
145
|
+
if hasattr(message, "from_history") and message.from_history and skip_history_messages:
|
|
146
|
+
return True
|
|
147
|
+
|
|
148
|
+
# Skip messages with specified role
|
|
149
|
+
if skip_roles and message.role in skip_roles:
|
|
150
|
+
return True
|
|
151
|
+
|
|
152
|
+
return False
|
|
153
|
+
|
|
154
|
+
if not self.runs:
|
|
155
|
+
return []
|
|
156
|
+
|
|
157
|
+
if skip_statuses is None:
|
|
158
|
+
skip_statuses = [RunStatus.paused, RunStatus.cancelled, RunStatus.error]
|
|
159
|
+
|
|
160
|
+
runs = self.runs
|
|
161
|
+
|
|
162
|
+
# Filter by agent_id and team_id
|
|
163
|
+
if agent_id:
|
|
164
|
+
runs = [run for run in runs if hasattr(run, "agent_id") and run.agent_id == agent_id] # type: ignore
|
|
165
|
+
if team_id:
|
|
166
|
+
runs = [run for run in runs if hasattr(run, "team_id") and run.team_id == team_id] # type: ignore
|
|
167
|
+
|
|
168
|
+
# Skip any messages that might be part of members of teams (for session re-use)
|
|
169
|
+
runs = [run for run in runs if run.parent_run_id is None] # type: ignore
|
|
170
|
+
|
|
171
|
+
# Filter by status
|
|
172
|
+
runs = [run for run in runs if hasattr(run, "status") and run.status not in skip_statuses] # type: ignore
|
|
173
|
+
|
|
174
|
+
messages_from_history = []
|
|
175
|
+
system_message = None
|
|
176
|
+
|
|
177
|
+
# Limit the number of messages returned if limit is set
|
|
178
|
+
if limit is not None:
|
|
179
|
+
for run_response in runs:
|
|
180
|
+
if not run_response or not run_response.messages:
|
|
181
|
+
continue
|
|
182
|
+
|
|
183
|
+
for message in run_response.messages or []:
|
|
184
|
+
if _should_skip_message(message, skip_roles, skip_history_messages):
|
|
185
|
+
continue
|
|
186
|
+
|
|
187
|
+
if message.role == "system":
|
|
188
|
+
# Only add the system message once
|
|
189
|
+
if system_message is None:
|
|
190
|
+
system_message = message
|
|
191
|
+
else:
|
|
192
|
+
messages_from_history.append(message)
|
|
193
|
+
|
|
194
|
+
if system_message:
|
|
195
|
+
messages_from_history = [system_message] + messages_from_history[
|
|
196
|
+
-(limit - 1) :
|
|
197
|
+
] # Grab one less message then add the system message
|
|
198
|
+
else:
|
|
199
|
+
messages_from_history = messages_from_history[-limit:]
|
|
200
|
+
|
|
201
|
+
# Remove tool result messages that don't have an associated assistant message with tool calls
|
|
202
|
+
while len(messages_from_history) > 0 and messages_from_history[0].role == "tool":
|
|
203
|
+
messages_from_history.pop(0)
|
|
204
|
+
|
|
205
|
+
# If limit is not set, return all messages
|
|
206
|
+
else:
|
|
207
|
+
runs_to_process = runs[-last_n_runs:] if last_n_runs is not None else runs
|
|
208
|
+
for run_response in runs_to_process:
|
|
209
|
+
if not run_response or not run_response.messages:
|
|
210
|
+
continue
|
|
211
|
+
|
|
212
|
+
for message in run_response.messages or []:
|
|
213
|
+
if _should_skip_message(message, skip_roles, skip_history_messages):
|
|
214
|
+
continue
|
|
215
|
+
|
|
216
|
+
if message.role == "system":
|
|
217
|
+
# Only add the system message once
|
|
218
|
+
if system_message is None:
|
|
219
|
+
system_message = message
|
|
220
|
+
messages_from_history.append(system_message)
|
|
221
|
+
else:
|
|
222
|
+
messages_from_history.append(message)
|
|
223
|
+
|
|
224
|
+
log_debug(f"Getting messages from previous runs: {len(messages_from_history)}")
|
|
225
|
+
return messages_from_history
|
|
226
|
+
|
|
227
|
+
def get_chat_history(self, last_n_runs: Optional[int] = None) -> List[Message]:
|
|
228
|
+
"""Return the chat history (user and assistant messages) for the session.
|
|
229
|
+
Use get_messages() for more filtering options.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
last_n_runs: Number of recent runs to include. If None, all runs will be considered.
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
A list of user and assistant Messages belonging to the session.
|
|
236
|
+
"""
|
|
237
|
+
return self.get_messages(skip_roles=["system", "tool"], last_n_runs=last_n_runs)
|
|
238
|
+
|
|
239
|
+
def get_tool_calls(self, num_calls: Optional[int] = None) -> List[Dict[str, Any]]:
|
|
240
|
+
"""Returns a list of tool calls from the messages"""
|
|
241
|
+
|
|
242
|
+
tool_calls = []
|
|
243
|
+
if self.runs:
|
|
244
|
+
session_runs = self.runs
|
|
245
|
+
for run_response in session_runs[::-1]:
|
|
246
|
+
if run_response and run_response.messages:
|
|
247
|
+
for message in run_response.messages or []:
|
|
248
|
+
if message.tool_calls:
|
|
249
|
+
for tool_call in message.tool_calls:
|
|
250
|
+
tool_calls.append(tool_call)
|
|
251
|
+
if num_calls and len(tool_calls) >= num_calls:
|
|
252
|
+
return tool_calls
|
|
253
|
+
return tool_calls
|
|
254
|
+
|
|
255
|
+
def get_session_summary(self) -> Optional[SessionSummary]:
|
|
256
|
+
"""Get the session summary for the session"""
|
|
257
|
+
|
|
258
|
+
if self.summary is None:
|
|
259
|
+
return None
|
|
260
|
+
return self.summary
|
agno/session/summary.py
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
from textwrap import dedent
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Type, Union
|
|
5
|
+
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from agno.models.base import Model
|
|
9
|
+
from agno.models.utils import get_model
|
|
10
|
+
from agno.run.agent import Message
|
|
11
|
+
from agno.utils.log import log_debug, log_warning
|
|
12
|
+
|
|
13
|
+
# TODO: Look into moving all managers into a separate dir
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from agno.session import Session
|
|
16
|
+
from agno.session.agent import AgentSession
|
|
17
|
+
from agno.session.team import TeamSession
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class SessionSummary:
|
|
22
|
+
"""Model for Session Summary."""
|
|
23
|
+
|
|
24
|
+
summary: str
|
|
25
|
+
topics: Optional[List[str]] = None
|
|
26
|
+
updated_at: Optional[datetime] = None
|
|
27
|
+
|
|
28
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
29
|
+
_dict = {
|
|
30
|
+
"summary": self.summary,
|
|
31
|
+
"topics": self.topics,
|
|
32
|
+
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|
33
|
+
}
|
|
34
|
+
return {k: v for k, v in _dict.items() if v is not None}
|
|
35
|
+
|
|
36
|
+
@classmethod
|
|
37
|
+
def from_dict(cls, data: Dict[str, Any]) -> "SessionSummary":
|
|
38
|
+
updated_at = data.get("updated_at")
|
|
39
|
+
if updated_at:
|
|
40
|
+
data["updated_at"] = datetime.fromisoformat(updated_at)
|
|
41
|
+
return cls(**data)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class SessionSummaryResponse(BaseModel):
|
|
45
|
+
"""Model for Session Summary."""
|
|
46
|
+
|
|
47
|
+
summary: str = Field(
|
|
48
|
+
...,
|
|
49
|
+
description="Summary of the session. Be concise and focus on only important information. Do not make anything up.",
|
|
50
|
+
)
|
|
51
|
+
topics: Optional[List[str]] = Field(None, description="Topics discussed in the session.")
|
|
52
|
+
|
|
53
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
54
|
+
return self.model_dump(exclude_none=True)
|
|
55
|
+
|
|
56
|
+
def to_json(self) -> str:
|
|
57
|
+
return self.model_dump_json(exclude_none=True, indent=2)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class SessionSummaryManager:
|
|
62
|
+
"""Session Summary Manager"""
|
|
63
|
+
|
|
64
|
+
# Model used for session summary generation
|
|
65
|
+
model: Optional[Model] = None
|
|
66
|
+
|
|
67
|
+
# Prompt used for session summary generation
|
|
68
|
+
session_summary_prompt: Optional[str] = None
|
|
69
|
+
|
|
70
|
+
# User message prompt for requesting the summary
|
|
71
|
+
summary_request_message: str = "Provide the summary of the conversation."
|
|
72
|
+
|
|
73
|
+
# Whether session summaries were created in the last run
|
|
74
|
+
summaries_updated: bool = False
|
|
75
|
+
|
|
76
|
+
def get_response_format(self, model: "Model") -> Union[Dict[str, Any], Type[BaseModel]]: # type: ignore
|
|
77
|
+
if model.supports_native_structured_outputs:
|
|
78
|
+
return SessionSummaryResponse
|
|
79
|
+
|
|
80
|
+
elif model.supports_json_schema_outputs:
|
|
81
|
+
return {
|
|
82
|
+
"type": "json_schema",
|
|
83
|
+
"json_schema": {
|
|
84
|
+
"name": SessionSummaryResponse.__name__,
|
|
85
|
+
"schema": SessionSummaryResponse.model_json_schema(),
|
|
86
|
+
},
|
|
87
|
+
}
|
|
88
|
+
else:
|
|
89
|
+
return {"type": "json_object"}
|
|
90
|
+
|
|
91
|
+
def get_system_message(
|
|
92
|
+
self,
|
|
93
|
+
conversation: List[Message],
|
|
94
|
+
response_format: Union[Dict[str, Any], Type[BaseModel]],
|
|
95
|
+
) -> Message:
|
|
96
|
+
if self.session_summary_prompt is not None:
|
|
97
|
+
system_prompt = self.session_summary_prompt
|
|
98
|
+
else:
|
|
99
|
+
system_prompt = dedent("""\
|
|
100
|
+
Analyze the following conversation between a user and an assistant, and extract the following details:
|
|
101
|
+
- Summary (str): Provide a concise summary of the session, focusing on important information that would be helpful for future interactions.
|
|
102
|
+
- Topics (Optional[List[str]]): List the topics discussed in the session.
|
|
103
|
+
Keep the summary concise and to the point. Only include relevant information.
|
|
104
|
+
""")
|
|
105
|
+
conversation_messages = []
|
|
106
|
+
system_prompt += "<conversation>"
|
|
107
|
+
for message in conversation:
|
|
108
|
+
if message.role == "user":
|
|
109
|
+
# Handle empty user messages with media - note what media was provided
|
|
110
|
+
if not message.content or (isinstance(message.content, str) and message.content.strip() == ""):
|
|
111
|
+
media_types = []
|
|
112
|
+
if hasattr(message, "images") and message.images:
|
|
113
|
+
media_types.append(f"{len(message.images)} image(s)")
|
|
114
|
+
if hasattr(message, "videos") and message.videos:
|
|
115
|
+
media_types.append(f"{len(message.videos)} video(s)")
|
|
116
|
+
if hasattr(message, "audio") and message.audio:
|
|
117
|
+
media_types.append(f"{len(message.audio)} audio file(s)")
|
|
118
|
+
if hasattr(message, "files") and message.files:
|
|
119
|
+
media_types.append(f"{len(message.files)} file(s)")
|
|
120
|
+
|
|
121
|
+
if media_types:
|
|
122
|
+
conversation_messages.append(f"User: [Provided {', '.join(media_types)}]")
|
|
123
|
+
# Skip empty messages with no media
|
|
124
|
+
else:
|
|
125
|
+
conversation_messages.append(f"User: {message.content}")
|
|
126
|
+
elif message.role in ["assistant", "model"]:
|
|
127
|
+
conversation_messages.append(f"Assistant: {message.content}\n")
|
|
128
|
+
system_prompt += "\n".join(conversation_messages)
|
|
129
|
+
system_prompt += "</conversation>"
|
|
130
|
+
|
|
131
|
+
if response_format == {"type": "json_object"}:
|
|
132
|
+
from agno.utils.prompts import get_json_output_prompt
|
|
133
|
+
|
|
134
|
+
system_prompt += "\n" + get_json_output_prompt(SessionSummaryResponse) # type: ignore
|
|
135
|
+
|
|
136
|
+
return Message(role="system", content=system_prompt)
|
|
137
|
+
|
|
138
|
+
def _prepare_summary_messages(
|
|
139
|
+
self,
|
|
140
|
+
session: Optional["Session"] = None,
|
|
141
|
+
) -> Optional[List[Message]]:
|
|
142
|
+
"""Prepare messages for session summary generation. Returns None if no meaningful messages to summarize."""
|
|
143
|
+
if not session:
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
self.model = get_model(self.model)
|
|
147
|
+
if self.model is None:
|
|
148
|
+
return None
|
|
149
|
+
|
|
150
|
+
response_format = self.get_response_format(self.model)
|
|
151
|
+
|
|
152
|
+
system_message = self.get_system_message(
|
|
153
|
+
conversation=session.get_messages(), # type: ignore
|
|
154
|
+
response_format=response_format,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
if system_message is None:
|
|
158
|
+
return None
|
|
159
|
+
|
|
160
|
+
return [
|
|
161
|
+
system_message,
|
|
162
|
+
Message(role="user", content=self.summary_request_message),
|
|
163
|
+
]
|
|
164
|
+
|
|
165
|
+
def _process_summary_response(self, summary_response, session_summary_model: "Model") -> Optional[SessionSummary]: # type: ignore
|
|
166
|
+
"""Process the model response into a SessionSummary"""
|
|
167
|
+
from datetime import datetime
|
|
168
|
+
|
|
169
|
+
if summary_response is None:
|
|
170
|
+
return None
|
|
171
|
+
|
|
172
|
+
# Handle native structured outputs
|
|
173
|
+
if (
|
|
174
|
+
session_summary_model.supports_native_structured_outputs
|
|
175
|
+
and summary_response.parsed is not None
|
|
176
|
+
and isinstance(summary_response.parsed, SessionSummaryResponse)
|
|
177
|
+
):
|
|
178
|
+
session_summary = SessionSummary(
|
|
179
|
+
summary=summary_response.parsed.summary,
|
|
180
|
+
topics=summary_response.parsed.topics,
|
|
181
|
+
updated_at=datetime.now(),
|
|
182
|
+
)
|
|
183
|
+
self.summary = session_summary
|
|
184
|
+
log_debug("Session summary created", center=True)
|
|
185
|
+
return session_summary
|
|
186
|
+
|
|
187
|
+
# Handle string responses
|
|
188
|
+
if isinstance(summary_response.content, str):
|
|
189
|
+
try:
|
|
190
|
+
from agno.utils.string import parse_response_model_str
|
|
191
|
+
|
|
192
|
+
parsed_summary: SessionSummaryResponse = parse_response_model_str( # type: ignore
|
|
193
|
+
summary_response.content, SessionSummaryResponse
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
if parsed_summary is not None:
|
|
197
|
+
session_summary = SessionSummary(
|
|
198
|
+
summary=parsed_summary.summary, topics=parsed_summary.topics, updated_at=datetime.now()
|
|
199
|
+
)
|
|
200
|
+
self.summary = session_summary
|
|
201
|
+
log_debug("Session summary created", center=True)
|
|
202
|
+
return session_summary
|
|
203
|
+
else:
|
|
204
|
+
log_warning("Failed to parse session summary response")
|
|
205
|
+
|
|
206
|
+
except Exception as e:
|
|
207
|
+
log_warning(f"Failed to parse session summary response: {e}")
|
|
208
|
+
|
|
209
|
+
return None
|
|
210
|
+
|
|
211
|
+
def create_session_summary(
|
|
212
|
+
self,
|
|
213
|
+
session: Union["AgentSession", "TeamSession"],
|
|
214
|
+
) -> Optional[SessionSummary]:
|
|
215
|
+
"""Creates a summary of the session"""
|
|
216
|
+
log_debug("Creating session summary", center=True)
|
|
217
|
+
self.model = get_model(self.model)
|
|
218
|
+
if self.model is None:
|
|
219
|
+
return None
|
|
220
|
+
|
|
221
|
+
messages = self._prepare_summary_messages(session)
|
|
222
|
+
|
|
223
|
+
# Skip summary generation if there are no meaningful messages
|
|
224
|
+
if messages is None:
|
|
225
|
+
log_debug("No meaningful messages to summarize, skipping session summary")
|
|
226
|
+
return None
|
|
227
|
+
|
|
228
|
+
response_format = self.get_response_format(self.model)
|
|
229
|
+
|
|
230
|
+
summary_response = self.model.response(messages=messages, response_format=response_format)
|
|
231
|
+
session_summary = self._process_summary_response(summary_response, self.model)
|
|
232
|
+
|
|
233
|
+
if session is not None and session_summary is not None:
|
|
234
|
+
session.summary = session_summary
|
|
235
|
+
self.summaries_updated = True
|
|
236
|
+
|
|
237
|
+
return session_summary
|
|
238
|
+
|
|
239
|
+
async def acreate_session_summary(
|
|
240
|
+
self,
|
|
241
|
+
session: Union["AgentSession", "TeamSession"],
|
|
242
|
+
) -> Optional[SessionSummary]:
|
|
243
|
+
"""Creates a summary of the session"""
|
|
244
|
+
log_debug("Creating session summary", center=True)
|
|
245
|
+
self.model = get_model(self.model)
|
|
246
|
+
if self.model is None:
|
|
247
|
+
return None
|
|
248
|
+
|
|
249
|
+
messages = self._prepare_summary_messages(session)
|
|
250
|
+
|
|
251
|
+
# Skip summary generation if there are no meaningful messages
|
|
252
|
+
if messages is None:
|
|
253
|
+
log_debug("No meaningful messages to summarize, skipping session summary")
|
|
254
|
+
return None
|
|
255
|
+
|
|
256
|
+
response_format = self.get_response_format(self.model)
|
|
257
|
+
|
|
258
|
+
summary_response = await self.model.aresponse(messages=messages, response_format=response_format)
|
|
259
|
+
session_summary = self._process_summary_response(summary_response, self.model)
|
|
260
|
+
|
|
261
|
+
if session is not None and session_summary is not None:
|
|
262
|
+
session.summary = session_summary
|
|
263
|
+
self.summaries_updated = True
|
|
264
|
+
|
|
265
|
+
return session_summary
|