agno 2.2.13__py3-none-any.whl → 2.4.3__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/agent/__init__.py +6 -0
- agno/agent/agent.py +5252 -3145
- agno/agent/remote.py +525 -0
- agno/api/api.py +2 -0
- agno/client/__init__.py +3 -0
- agno/client/a2a/__init__.py +10 -0
- agno/client/a2a/client.py +554 -0
- agno/client/a2a/schemas.py +112 -0
- agno/client/a2a/utils.py +369 -0
- agno/client/os.py +2669 -0
- agno/compression/__init__.py +3 -0
- agno/compression/manager.py +247 -0
- agno/culture/manager.py +2 -2
- agno/db/base.py +927 -6
- agno/db/dynamo/dynamo.py +788 -2
- agno/db/dynamo/schemas.py +128 -0
- agno/db/dynamo/utils.py +26 -3
- agno/db/firestore/firestore.py +674 -50
- agno/db/firestore/schemas.py +41 -0
- agno/db/firestore/utils.py +25 -10
- agno/db/gcs_json/gcs_json_db.py +506 -3
- agno/db/gcs_json/utils.py +14 -2
- agno/db/in_memory/in_memory_db.py +203 -4
- agno/db/in_memory/utils.py +14 -2
- agno/db/json/json_db.py +498 -2
- agno/db/json/utils.py +14 -2
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/utils.py +19 -0
- agno/db/migrations/v1_to_v2.py +54 -16
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +977 -0
- agno/db/mongo/async_mongo.py +1013 -39
- agno/db/mongo/mongo.py +684 -4
- agno/db/mongo/schemas.py +48 -0
- agno/db/mongo/utils.py +17 -0
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2958 -0
- agno/db/mysql/mysql.py +722 -53
- agno/db/mysql/schemas.py +77 -11
- agno/db/mysql/utils.py +151 -8
- agno/db/postgres/async_postgres.py +1254 -137
- agno/db/postgres/postgres.py +2316 -93
- agno/db/postgres/schemas.py +153 -21
- agno/db/postgres/utils.py +22 -7
- agno/db/redis/redis.py +531 -3
- agno/db/redis/schemas.py +36 -0
- agno/db/redis/utils.py +31 -15
- agno/db/schemas/evals.py +1 -0
- agno/db/schemas/memory.py +20 -9
- agno/db/singlestore/schemas.py +70 -1
- agno/db/singlestore/singlestore.py +737 -74
- agno/db/singlestore/utils.py +13 -3
- agno/db/sqlite/async_sqlite.py +1069 -89
- agno/db/sqlite/schemas.py +133 -1
- agno/db/sqlite/sqlite.py +2203 -165
- agno/db/sqlite/utils.py +21 -11
- agno/db/surrealdb/models.py +25 -0
- agno/db/surrealdb/surrealdb.py +603 -1
- agno/db/utils.py +60 -0
- agno/eval/__init__.py +26 -3
- agno/eval/accuracy.py +25 -12
- agno/eval/agent_as_judge.py +871 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +10 -4
- agno/eval/reliability.py +22 -13
- agno/eval/utils.py +2 -1
- agno/exceptions.py +42 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +13 -2
- agno/knowledge/__init__.py +4 -0
- agno/knowledge/chunking/code.py +90 -0
- agno/knowledge/chunking/document.py +65 -4
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/chunking/markdown.py +102 -11
- agno/knowledge/chunking/recursive.py +2 -2
- agno/knowledge/chunking/semantic.py +130 -48
- agno/knowledge/chunking/strategy.py +18 -0
- agno/knowledge/embedder/azure_openai.py +0 -1
- agno/knowledge/embedder/google.py +1 -1
- agno/knowledge/embedder/mistral.py +1 -1
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/openai.py +16 -12
- agno/knowledge/filesystem.py +412 -0
- agno/knowledge/knowledge.py +4261 -1199
- agno/knowledge/protocol.py +134 -0
- agno/knowledge/reader/arxiv_reader.py +3 -2
- agno/knowledge/reader/base.py +9 -7
- agno/knowledge/reader/csv_reader.py +91 -42
- agno/knowledge/reader/docx_reader.py +9 -10
- agno/knowledge/reader/excel_reader.py +225 -0
- agno/knowledge/reader/field_labeled_csv_reader.py +38 -48
- agno/knowledge/reader/firecrawl_reader.py +3 -2
- agno/knowledge/reader/json_reader.py +16 -22
- agno/knowledge/reader/markdown_reader.py +15 -14
- agno/knowledge/reader/pdf_reader.py +33 -28
- agno/knowledge/reader/pptx_reader.py +9 -10
- agno/knowledge/reader/reader_factory.py +135 -1
- agno/knowledge/reader/s3_reader.py +8 -16
- agno/knowledge/reader/tavily_reader.py +3 -3
- agno/knowledge/reader/text_reader.py +15 -14
- agno/knowledge/reader/utils/__init__.py +17 -0
- agno/knowledge/reader/utils/spreadsheet.py +114 -0
- agno/knowledge/reader/web_search_reader.py +8 -65
- agno/knowledge/reader/website_reader.py +16 -13
- agno/knowledge/reader/wikipedia_reader.py +36 -3
- agno/knowledge/reader/youtube_reader.py +3 -2
- agno/knowledge/remote_content/__init__.py +33 -0
- agno/knowledge/remote_content/config.py +266 -0
- agno/knowledge/remote_content/remote_content.py +105 -17
- agno/knowledge/utils.py +76 -22
- agno/learn/__init__.py +71 -0
- agno/learn/config.py +463 -0
- agno/learn/curate.py +185 -0
- agno/learn/machine.py +725 -0
- agno/learn/schemas.py +1114 -0
- agno/learn/stores/__init__.py +38 -0
- agno/learn/stores/decision_log.py +1156 -0
- agno/learn/stores/entity_memory.py +3275 -0
- agno/learn/stores/learned_knowledge.py +1583 -0
- agno/learn/stores/protocol.py +117 -0
- agno/learn/stores/session_context.py +1217 -0
- agno/learn/stores/user_memory.py +1495 -0
- agno/learn/stores/user_profile.py +1220 -0
- agno/learn/utils.py +209 -0
- agno/media.py +22 -6
- agno/memory/__init__.py +14 -1
- agno/memory/manager.py +223 -8
- 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/aimlapi.py +17 -0
- agno/models/anthropic/claude.py +434 -59
- agno/models/aws/bedrock.py +121 -20
- agno/models/aws/claude.py +131 -274
- agno/models/azure/ai_foundry.py +10 -6
- agno/models/azure/openai_chat.py +33 -10
- agno/models/base.py +1162 -561
- agno/models/cerebras/cerebras.py +120 -24
- agno/models/cerebras/cerebras_openai.py +21 -2
- agno/models/cohere/chat.py +65 -6
- agno/models/cometapi/cometapi.py +18 -1
- agno/models/dashscope/dashscope.py +2 -3
- agno/models/deepinfra/deepinfra.py +18 -1
- agno/models/deepseek/deepseek.py +69 -3
- agno/models/fireworks/fireworks.py +18 -1
- agno/models/google/gemini.py +959 -89
- agno/models/google/utils.py +22 -0
- agno/models/groq/groq.py +48 -18
- agno/models/huggingface/huggingface.py +17 -6
- agno/models/ibm/watsonx.py +16 -6
- agno/models/internlm/internlm.py +18 -1
- agno/models/langdb/langdb.py +13 -1
- agno/models/litellm/chat.py +88 -9
- agno/models/litellm/litellm_openai.py +18 -1
- agno/models/message.py +24 -5
- agno/models/meta/llama.py +40 -13
- agno/models/meta/llama_openai.py +22 -21
- agno/models/metrics.py +12 -0
- agno/models/mistral/mistral.py +8 -4
- agno/models/n1n/__init__.py +3 -0
- agno/models/n1n/n1n.py +57 -0
- agno/models/nebius/nebius.py +6 -7
- agno/models/nvidia/nvidia.py +20 -3
- agno/models/ollama/__init__.py +2 -0
- agno/models/ollama/chat.py +17 -6
- agno/models/ollama/responses.py +100 -0
- agno/models/openai/__init__.py +2 -0
- agno/models/openai/chat.py +117 -26
- agno/models/openai/open_responses.py +46 -0
- agno/models/openai/responses.py +110 -32
- agno/models/openrouter/__init__.py +2 -0
- agno/models/openrouter/openrouter.py +67 -2
- agno/models/openrouter/responses.py +146 -0
- agno/models/perplexity/perplexity.py +19 -1
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +19 -2
- agno/models/response.py +20 -2
- agno/models/sambanova/sambanova.py +20 -3
- agno/models/siliconflow/siliconflow.py +19 -2
- agno/models/together/together.py +20 -3
- agno/models/vercel/v0.py +20 -3
- agno/models/vertexai/claude.py +124 -4
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +19 -2
- agno/os/app.py +467 -137
- agno/os/auth.py +253 -5
- agno/os/config.py +22 -0
- agno/os/interfaces/a2a/a2a.py +7 -6
- agno/os/interfaces/a2a/router.py +635 -26
- agno/os/interfaces/a2a/utils.py +32 -33
- agno/os/interfaces/agui/agui.py +5 -3
- agno/os/interfaces/agui/router.py +26 -16
- agno/os/interfaces/agui/utils.py +97 -57
- agno/os/interfaces/base.py +7 -7
- agno/os/interfaces/slack/router.py +16 -7
- agno/os/interfaces/slack/slack.py +7 -7
- agno/os/interfaces/whatsapp/router.py +35 -7
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/interfaces/whatsapp/whatsapp.py +11 -8
- agno/os/managers.py +326 -0
- agno/os/mcp.py +652 -79
- agno/os/middleware/__init__.py +4 -0
- agno/os/middleware/jwt.py +718 -115
- agno/os/middleware/trailing_slash.py +27 -0
- agno/os/router.py +105 -1558
- agno/os/routers/agents/__init__.py +3 -0
- agno/os/routers/agents/router.py +655 -0
- agno/os/routers/agents/schema.py +288 -0
- agno/os/routers/components/__init__.py +3 -0
- agno/os/routers/components/components.py +475 -0
- agno/os/routers/database.py +155 -0
- agno/os/routers/evals/evals.py +111 -18
- agno/os/routers/evals/schemas.py +38 -5
- agno/os/routers/evals/utils.py +80 -11
- agno/os/routers/health.py +3 -3
- agno/os/routers/knowledge/knowledge.py +284 -35
- agno/os/routers/knowledge/schemas.py +14 -2
- agno/os/routers/memory/memory.py +274 -11
- agno/os/routers/memory/schemas.py +44 -3
- agno/os/routers/metrics/metrics.py +30 -15
- agno/os/routers/metrics/schemas.py +10 -6
- agno/os/routers/registry/__init__.py +3 -0
- agno/os/routers/registry/registry.py +337 -0
- agno/os/routers/session/session.py +143 -14
- agno/os/routers/teams/__init__.py +3 -0
- agno/os/routers/teams/router.py +550 -0
- agno/os/routers/teams/schema.py +280 -0
- agno/os/routers/traces/__init__.py +3 -0
- agno/os/routers/traces/schemas.py +414 -0
- agno/os/routers/traces/traces.py +549 -0
- agno/os/routers/workflows/__init__.py +3 -0
- agno/os/routers/workflows/router.py +757 -0
- agno/os/routers/workflows/schema.py +139 -0
- agno/os/schema.py +157 -584
- agno/os/scopes.py +469 -0
- agno/os/settings.py +3 -0
- agno/os/utils.py +574 -185
- agno/reasoning/anthropic.py +85 -1
- agno/reasoning/azure_ai_foundry.py +93 -1
- agno/reasoning/deepseek.py +102 -2
- agno/reasoning/default.py +6 -7
- agno/reasoning/gemini.py +87 -3
- agno/reasoning/groq.py +109 -2
- agno/reasoning/helpers.py +6 -7
- agno/reasoning/manager.py +1238 -0
- agno/reasoning/ollama.py +93 -1
- agno/reasoning/openai.py +115 -1
- agno/reasoning/vertexai.py +85 -1
- agno/registry/__init__.py +3 -0
- agno/registry/registry.py +68 -0
- agno/remote/__init__.py +3 -0
- agno/remote/base.py +581 -0
- agno/run/__init__.py +2 -4
- agno/run/agent.py +134 -19
- agno/run/base.py +49 -1
- agno/run/cancel.py +65 -52
- agno/run/cancellation_management/__init__.py +9 -0
- agno/run/cancellation_management/base.py +78 -0
- agno/run/cancellation_management/in_memory_cancellation_manager.py +100 -0
- agno/run/cancellation_management/redis_cancellation_manager.py +236 -0
- agno/run/requirement.py +181 -0
- agno/run/team.py +111 -19
- agno/run/workflow.py +2 -1
- agno/session/agent.py +57 -92
- agno/session/summary.py +1 -1
- agno/session/team.py +62 -115
- agno/session/workflow.py +353 -57
- agno/skills/__init__.py +17 -0
- agno/skills/agent_skills.py +377 -0
- agno/skills/errors.py +32 -0
- agno/skills/loaders/__init__.py +4 -0
- agno/skills/loaders/base.py +27 -0
- agno/skills/loaders/local.py +216 -0
- agno/skills/skill.py +65 -0
- agno/skills/utils.py +107 -0
- agno/skills/validator.py +277 -0
- agno/table.py +10 -0
- agno/team/__init__.py +5 -1
- agno/team/remote.py +447 -0
- agno/team/team.py +3769 -2202
- agno/tools/brandfetch.py +27 -18
- agno/tools/browserbase.py +225 -16
- agno/tools/crawl4ai.py +3 -0
- agno/tools/duckduckgo.py +25 -71
- agno/tools/exa.py +0 -21
- agno/tools/file.py +14 -13
- agno/tools/file_generation.py +12 -6
- agno/tools/firecrawl.py +15 -7
- agno/tools/function.py +94 -113
- agno/tools/google_bigquery.py +11 -2
- agno/tools/google_drive.py +4 -3
- agno/tools/knowledge.py +9 -4
- agno/tools/mcp/mcp.py +301 -18
- agno/tools/mcp/multi_mcp.py +269 -14
- agno/tools/mem0.py +11 -10
- agno/tools/memory.py +47 -46
- agno/tools/mlx_transcribe.py +10 -7
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/parallel.py +0 -7
- agno/tools/postgres.py +76 -36
- agno/tools/python.py +14 -6
- agno/tools/reasoning.py +30 -23
- agno/tools/redshift.py +406 -0
- agno/tools/shopify.py +1519 -0
- agno/tools/spotify.py +919 -0
- agno/tools/tavily.py +4 -1
- agno/tools/toolkit.py +253 -18
- agno/tools/websearch.py +93 -0
- agno/tools/website.py +1 -1
- agno/tools/wikipedia.py +1 -1
- agno/tools/workflow.py +56 -48
- agno/tools/yfinance.py +12 -11
- agno/tracing/__init__.py +12 -0
- agno/tracing/exporter.py +161 -0
- agno/tracing/schemas.py +276 -0
- agno/tracing/setup.py +112 -0
- agno/utils/agent.py +251 -10
- agno/utils/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +264 -7
- agno/utils/hooks.py +111 -3
- agno/utils/http.py +161 -2
- agno/utils/mcp.py +49 -8
- agno/utils/media.py +22 -1
- agno/utils/models/ai_foundry.py +9 -2
- agno/utils/models/claude.py +20 -5
- agno/utils/models/cohere.py +9 -2
- agno/utils/models/llama.py +9 -2
- agno/utils/models/mistral.py +4 -2
- agno/utils/os.py +0 -0
- agno/utils/print_response/agent.py +99 -16
- agno/utils/print_response/team.py +223 -24
- agno/utils/print_response/workflow.py +0 -2
- agno/utils/prompts.py +8 -6
- agno/utils/remote.py +23 -0
- agno/utils/response.py +1 -13
- agno/utils/string.py +91 -2
- agno/utils/team.py +62 -12
- agno/utils/tokens.py +657 -0
- agno/vectordb/base.py +15 -2
- agno/vectordb/cassandra/cassandra.py +1 -1
- agno/vectordb/chroma/__init__.py +2 -1
- agno/vectordb/chroma/chromadb.py +468 -23
- agno/vectordb/clickhouse/clickhousedb.py +1 -1
- agno/vectordb/couchbase/couchbase.py +6 -2
- agno/vectordb/lancedb/lance_db.py +7 -38
- agno/vectordb/lightrag/lightrag.py +7 -6
- agno/vectordb/milvus/milvus.py +118 -84
- agno/vectordb/mongodb/__init__.py +2 -1
- agno/vectordb/mongodb/mongodb.py +14 -31
- agno/vectordb/pgvector/pgvector.py +120 -66
- agno/vectordb/pineconedb/pineconedb.py +2 -19
- agno/vectordb/qdrant/__init__.py +2 -1
- agno/vectordb/qdrant/qdrant.py +33 -56
- agno/vectordb/redis/__init__.py +2 -1
- agno/vectordb/redis/redisdb.py +19 -31
- agno/vectordb/singlestore/singlestore.py +17 -9
- agno/vectordb/surrealdb/surrealdb.py +2 -38
- agno/vectordb/weaviate/__init__.py +2 -1
- agno/vectordb/weaviate/weaviate.py +7 -3
- agno/workflow/__init__.py +5 -1
- agno/workflow/agent.py +2 -2
- agno/workflow/condition.py +12 -10
- agno/workflow/loop.py +28 -9
- agno/workflow/parallel.py +21 -13
- agno/workflow/remote.py +362 -0
- agno/workflow/router.py +12 -9
- agno/workflow/step.py +261 -36
- agno/workflow/steps.py +12 -8
- agno/workflow/types.py +40 -77
- agno/workflow/workflow.py +939 -213
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/METADATA +134 -181
- agno-2.4.3.dist-info/RECORD +677 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/WHEEL +1 -1
- agno/tools/googlesearch.py +0 -98
- agno/tools/memori.py +0 -339
- agno-2.2.13.dist-info/RECORD +0 -575
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/licenses/LICENSE +0 -0
- {agno-2.2.13.dist-info → agno-2.4.3.dist-info}/top_level.txt +0 -0
agno/run/team.py
CHANGED
|
@@ -12,6 +12,7 @@ from agno.models.response import ToolExecution
|
|
|
12
12
|
from agno.reasoning.step import ReasoningStep
|
|
13
13
|
from agno.run.agent import RunEvent, RunOutput, RunOutputEvent, run_output_event_from_dict
|
|
14
14
|
from agno.run.base import BaseRunOutputEvent, MessageReferences, RunStatus
|
|
15
|
+
from agno.run.requirement import RunRequirement
|
|
15
16
|
from agno.utils.log import log_error
|
|
16
17
|
from agno.utils.media import (
|
|
17
18
|
reconstruct_audio_list,
|
|
@@ -50,8 +51,11 @@ class TeamRunInput:
|
|
|
50
51
|
return self.input_content.model_dump_json(exclude_none=True)
|
|
51
52
|
elif isinstance(self.input_content, Message):
|
|
52
53
|
return json.dumps(self.input_content.to_dict())
|
|
53
|
-
elif isinstance(self.input_content, list)
|
|
54
|
-
|
|
54
|
+
elif isinstance(self.input_content, list):
|
|
55
|
+
try:
|
|
56
|
+
return json.dumps(self.to_dict().get("input_content"))
|
|
57
|
+
except Exception:
|
|
58
|
+
return str(self.input_content)
|
|
55
59
|
else:
|
|
56
60
|
return str(self.input_content)
|
|
57
61
|
|
|
@@ -66,22 +70,15 @@ class TeamRunInput:
|
|
|
66
70
|
result["input_content"] = self.input_content.model_dump(exclude_none=True)
|
|
67
71
|
elif isinstance(self.input_content, Message):
|
|
68
72
|
result["input_content"] = self.input_content.to_dict()
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
# Handle input_content provided as a list of dicts
|
|
79
|
-
elif (
|
|
80
|
-
isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], dict)
|
|
81
|
-
):
|
|
82
|
-
for content in self.input_content:
|
|
83
|
-
# Handle media input
|
|
84
|
-
if isinstance(content, dict):
|
|
73
|
+
elif isinstance(self.input_content, list):
|
|
74
|
+
serialized_items: List[Any] = []
|
|
75
|
+
for item in self.input_content:
|
|
76
|
+
if isinstance(item, Message):
|
|
77
|
+
serialized_items.append(item.to_dict())
|
|
78
|
+
elif isinstance(item, BaseModel):
|
|
79
|
+
serialized_items.append(item.model_dump(exclude_none=True))
|
|
80
|
+
elif isinstance(item, dict):
|
|
81
|
+
content = dict(item)
|
|
85
82
|
if content.get("images"):
|
|
86
83
|
content["images"] = [
|
|
87
84
|
img.to_dict() if isinstance(img, Image) else img for img in content["images"]
|
|
@@ -98,7 +95,11 @@ class TeamRunInput:
|
|
|
98
95
|
content["files"] = [
|
|
99
96
|
file.to_dict() if isinstance(file, File) else file for file in content["files"]
|
|
100
97
|
]
|
|
101
|
-
|
|
98
|
+
serialized_items.append(content)
|
|
99
|
+
else:
|
|
100
|
+
serialized_items.append(item)
|
|
101
|
+
|
|
102
|
+
result["input_content"] = serialized_items
|
|
102
103
|
else:
|
|
103
104
|
result["input_content"] = self.input_content
|
|
104
105
|
|
|
@@ -145,9 +146,11 @@ class TeamRunEvent(str, Enum):
|
|
|
145
146
|
|
|
146
147
|
tool_call_started = "TeamToolCallStarted"
|
|
147
148
|
tool_call_completed = "TeamToolCallCompleted"
|
|
149
|
+
tool_call_error = "TeamToolCallError"
|
|
148
150
|
|
|
149
151
|
reasoning_started = "TeamReasoningStarted"
|
|
150
152
|
reasoning_step = "TeamReasoningStep"
|
|
153
|
+
reasoning_content_delta = "TeamReasoningContentDelta"
|
|
151
154
|
reasoning_completed = "TeamReasoningCompleted"
|
|
152
155
|
|
|
153
156
|
memory_update_started = "TeamMemoryUpdateStarted"
|
|
@@ -162,6 +165,12 @@ class TeamRunEvent(str, Enum):
|
|
|
162
165
|
output_model_response_started = "TeamOutputModelResponseStarted"
|
|
163
166
|
output_model_response_completed = "TeamOutputModelResponseCompleted"
|
|
164
167
|
|
|
168
|
+
model_request_started = "TeamModelRequestStarted"
|
|
169
|
+
model_request_completed = "TeamModelRequestCompleted"
|
|
170
|
+
|
|
171
|
+
compression_started = "TeamCompressionStarted"
|
|
172
|
+
compression_completed = "TeamCompressionCompleted"
|
|
173
|
+
|
|
165
174
|
custom_event = "CustomEvent"
|
|
166
175
|
|
|
167
176
|
|
|
@@ -319,6 +328,7 @@ class MemoryUpdateStartedEvent(BaseTeamRunEvent):
|
|
|
319
328
|
@dataclass
|
|
320
329
|
class MemoryUpdateCompletedEvent(BaseTeamRunEvent):
|
|
321
330
|
event: str = TeamRunEvent.memory_update_completed.value
|
|
331
|
+
memories: Optional[List[Any]] = None
|
|
322
332
|
|
|
323
333
|
|
|
324
334
|
@dataclass
|
|
@@ -345,6 +355,14 @@ class ReasoningStepEvent(BaseTeamRunEvent):
|
|
|
345
355
|
reasoning_content: str = ""
|
|
346
356
|
|
|
347
357
|
|
|
358
|
+
@dataclass
|
|
359
|
+
class ReasoningContentDeltaEvent(BaseTeamRunEvent):
|
|
360
|
+
"""Event for streaming reasoning content chunks as they arrive."""
|
|
361
|
+
|
|
362
|
+
event: str = TeamRunEvent.reasoning_content_delta.value
|
|
363
|
+
reasoning_content: str = "" # The delta/chunk of reasoning content
|
|
364
|
+
|
|
365
|
+
|
|
348
366
|
@dataclass
|
|
349
367
|
class ReasoningCompletedEvent(BaseTeamRunEvent):
|
|
350
368
|
event: str = TeamRunEvent.reasoning_completed.value
|
|
@@ -368,6 +386,13 @@ class ToolCallCompletedEvent(BaseTeamRunEvent):
|
|
|
368
386
|
audio: Optional[List[Audio]] = None # Audio produced by the tool call
|
|
369
387
|
|
|
370
388
|
|
|
389
|
+
@dataclass
|
|
390
|
+
class ToolCallErrorEvent(BaseTeamRunEvent):
|
|
391
|
+
event: str = TeamRunEvent.tool_call_error.value
|
|
392
|
+
tool: Optional[ToolExecution] = None
|
|
393
|
+
error: Optional[str] = None
|
|
394
|
+
|
|
395
|
+
|
|
371
396
|
@dataclass
|
|
372
397
|
class ParserModelResponseStartedEvent(BaseTeamRunEvent):
|
|
373
398
|
event: str = TeamRunEvent.parser_model_response_started.value
|
|
@@ -388,6 +413,48 @@ class OutputModelResponseCompletedEvent(BaseTeamRunEvent):
|
|
|
388
413
|
event: str = TeamRunEvent.output_model_response_completed.value
|
|
389
414
|
|
|
390
415
|
|
|
416
|
+
@dataclass
|
|
417
|
+
class ModelRequestStartedEvent(BaseTeamRunEvent):
|
|
418
|
+
"""Event sent when a model request is about to be made"""
|
|
419
|
+
|
|
420
|
+
event: str = TeamRunEvent.model_request_started.value
|
|
421
|
+
model: Optional[str] = None
|
|
422
|
+
model_provider: Optional[str] = None
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
@dataclass
|
|
426
|
+
class ModelRequestCompletedEvent(BaseTeamRunEvent):
|
|
427
|
+
"""Event sent when a model request has completed"""
|
|
428
|
+
|
|
429
|
+
event: str = TeamRunEvent.model_request_completed.value
|
|
430
|
+
model: Optional[str] = None
|
|
431
|
+
model_provider: Optional[str] = None
|
|
432
|
+
input_tokens: Optional[int] = None
|
|
433
|
+
output_tokens: Optional[int] = None
|
|
434
|
+
total_tokens: Optional[int] = None
|
|
435
|
+
time_to_first_token: Optional[float] = None
|
|
436
|
+
reasoning_tokens: Optional[int] = None
|
|
437
|
+
cache_read_tokens: Optional[int] = None
|
|
438
|
+
cache_write_tokens: Optional[int] = None
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
@dataclass
|
|
442
|
+
class CompressionStartedEvent(BaseTeamRunEvent):
|
|
443
|
+
"""Event sent when tool result compression is about to start"""
|
|
444
|
+
|
|
445
|
+
event: str = TeamRunEvent.compression_started.value
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
@dataclass
|
|
449
|
+
class CompressionCompletedEvent(BaseTeamRunEvent):
|
|
450
|
+
"""Event sent when tool result compression has completed"""
|
|
451
|
+
|
|
452
|
+
event: str = TeamRunEvent.compression_completed.value
|
|
453
|
+
tool_results_compressed: Optional[int] = None
|
|
454
|
+
original_size: Optional[int] = None
|
|
455
|
+
compressed_size: Optional[int] = None
|
|
456
|
+
|
|
457
|
+
|
|
391
458
|
@dataclass
|
|
392
459
|
class CustomEvent(BaseTeamRunEvent):
|
|
393
460
|
event: str = TeamRunEvent.custom_event.value
|
|
@@ -410,6 +477,7 @@ TeamRunOutputEvent = Union[
|
|
|
410
477
|
PreHookCompletedEvent,
|
|
411
478
|
ReasoningStartedEvent,
|
|
412
479
|
ReasoningStepEvent,
|
|
480
|
+
ReasoningContentDeltaEvent,
|
|
413
481
|
ReasoningCompletedEvent,
|
|
414
482
|
MemoryUpdateStartedEvent,
|
|
415
483
|
MemoryUpdateCompletedEvent,
|
|
@@ -417,10 +485,15 @@ TeamRunOutputEvent = Union[
|
|
|
417
485
|
SessionSummaryCompletedEvent,
|
|
418
486
|
ToolCallStartedEvent,
|
|
419
487
|
ToolCallCompletedEvent,
|
|
488
|
+
ToolCallErrorEvent,
|
|
420
489
|
ParserModelResponseStartedEvent,
|
|
421
490
|
ParserModelResponseCompletedEvent,
|
|
422
491
|
OutputModelResponseStartedEvent,
|
|
423
492
|
OutputModelResponseCompletedEvent,
|
|
493
|
+
ModelRequestStartedEvent,
|
|
494
|
+
ModelRequestCompletedEvent,
|
|
495
|
+
CompressionStartedEvent,
|
|
496
|
+
CompressionCompletedEvent,
|
|
424
497
|
CustomEvent,
|
|
425
498
|
]
|
|
426
499
|
|
|
@@ -439,6 +512,7 @@ TEAM_RUN_EVENT_TYPE_REGISTRY = {
|
|
|
439
512
|
TeamRunEvent.post_hook_completed.value: PostHookCompletedEvent,
|
|
440
513
|
TeamRunEvent.reasoning_started.value: ReasoningStartedEvent,
|
|
441
514
|
TeamRunEvent.reasoning_step.value: ReasoningStepEvent,
|
|
515
|
+
TeamRunEvent.reasoning_content_delta.value: ReasoningContentDeltaEvent,
|
|
442
516
|
TeamRunEvent.reasoning_completed.value: ReasoningCompletedEvent,
|
|
443
517
|
TeamRunEvent.memory_update_started.value: MemoryUpdateStartedEvent,
|
|
444
518
|
TeamRunEvent.memory_update_completed.value: MemoryUpdateCompletedEvent,
|
|
@@ -446,10 +520,15 @@ TEAM_RUN_EVENT_TYPE_REGISTRY = {
|
|
|
446
520
|
TeamRunEvent.session_summary_completed.value: SessionSummaryCompletedEvent,
|
|
447
521
|
TeamRunEvent.tool_call_started.value: ToolCallStartedEvent,
|
|
448
522
|
TeamRunEvent.tool_call_completed.value: ToolCallCompletedEvent,
|
|
523
|
+
TeamRunEvent.tool_call_error.value: ToolCallErrorEvent,
|
|
449
524
|
TeamRunEvent.parser_model_response_started.value: ParserModelResponseStartedEvent,
|
|
450
525
|
TeamRunEvent.parser_model_response_completed.value: ParserModelResponseCompletedEvent,
|
|
451
526
|
TeamRunEvent.output_model_response_started.value: OutputModelResponseStartedEvent,
|
|
452
527
|
TeamRunEvent.output_model_response_completed.value: OutputModelResponseCompletedEvent,
|
|
528
|
+
TeamRunEvent.model_request_started.value: ModelRequestStartedEvent,
|
|
529
|
+
TeamRunEvent.model_request_completed.value: ModelRequestCompletedEvent,
|
|
530
|
+
TeamRunEvent.compression_started.value: CompressionStartedEvent,
|
|
531
|
+
TeamRunEvent.compression_completed.value: CompressionCompletedEvent,
|
|
453
532
|
TeamRunEvent.custom_event.value: CustomEvent,
|
|
454
533
|
}
|
|
455
534
|
|
|
@@ -515,11 +594,20 @@ class TeamRunOutput:
|
|
|
515
594
|
|
|
516
595
|
status: RunStatus = RunStatus.running
|
|
517
596
|
|
|
597
|
+
# User control flow (HITL) requirements to continue a run when paused, in order of arrival
|
|
598
|
+
requirements: Optional[list[RunRequirement]] = None
|
|
599
|
+
|
|
518
600
|
# === FOREIGN KEY RELATIONSHIPS ===
|
|
519
601
|
# These fields establish relationships to parent workflow/step structures
|
|
520
602
|
# and should be treated as foreign keys for data integrity
|
|
521
603
|
workflow_step_id: Optional[str] = None # FK: Points to StepOutput.step_id
|
|
522
604
|
|
|
605
|
+
@property
|
|
606
|
+
def active_requirements(self) -> list[RunRequirement]:
|
|
607
|
+
if not self.requirements:
|
|
608
|
+
return []
|
|
609
|
+
return [requirement for requirement in self.requirements if not requirement.is_resolved()]
|
|
610
|
+
|
|
523
611
|
@property
|
|
524
612
|
def is_paused(self):
|
|
525
613
|
return self.status == RunStatus.paused
|
|
@@ -536,6 +624,7 @@ class TeamRunOutput:
|
|
|
536
624
|
and k
|
|
537
625
|
not in [
|
|
538
626
|
"messages",
|
|
627
|
+
"metrics",
|
|
539
628
|
"status",
|
|
540
629
|
"tools",
|
|
541
630
|
"metadata",
|
|
@@ -555,6 +644,9 @@ class TeamRunOutput:
|
|
|
555
644
|
if self.events is not None:
|
|
556
645
|
_dict["events"] = [e.to_dict() for e in self.events]
|
|
557
646
|
|
|
647
|
+
if self.metrics is not None:
|
|
648
|
+
_dict["metrics"] = self.metrics.to_dict() if isinstance(self.metrics, Metrics) else self.metrics
|
|
649
|
+
|
|
558
650
|
if self.status is not None:
|
|
559
651
|
_dict["status"] = self.status.value if isinstance(self.status, RunStatus) else self.status
|
|
560
652
|
|
agno/run/workflow.py
CHANGED
|
@@ -500,6 +500,7 @@ class WorkflowRunOutput:
|
|
|
500
500
|
|
|
501
501
|
run_id: Optional[str] = None
|
|
502
502
|
session_id: Optional[str] = None
|
|
503
|
+
user_id: Optional[str] = None
|
|
503
504
|
|
|
504
505
|
# Media content fields
|
|
505
506
|
images: Optional[List[Image]] = None
|
|
@@ -597,7 +598,7 @@ class WorkflowRunOutput:
|
|
|
597
598
|
_dict["input"] = self.input
|
|
598
599
|
|
|
599
600
|
if self.content and isinstance(self.content, BaseModel):
|
|
600
|
-
_dict["content"] = self.content.model_dump(exclude_none=True)
|
|
601
|
+
_dict["content"] = self.content.model_dump(exclude_none=True, mode="json")
|
|
601
602
|
|
|
602
603
|
if self.events is not None:
|
|
603
604
|
_dict["events"] = [e.to_dict() for e in self.events]
|
agno/session/agent.py
CHANGED
|
@@ -112,71 +112,76 @@ class AgentSession:
|
|
|
112
112
|
return run
|
|
113
113
|
return None
|
|
114
114
|
|
|
115
|
-
def
|
|
116
|
-
self, message: Message, skip_role: Optional[str] = None, skip_history_messages: bool = True
|
|
117
|
-
) -> bool:
|
|
118
|
-
"""Processes a message for history"""
|
|
119
|
-
# Skip messages that were tagged as history in previous runs
|
|
120
|
-
if hasattr(message, "from_history") and message.from_history and skip_history_messages:
|
|
121
|
-
return True
|
|
122
|
-
|
|
123
|
-
# Skip messages with specified role
|
|
124
|
-
if skip_role and message.role == skip_role:
|
|
125
|
-
return True
|
|
126
|
-
return False
|
|
127
|
-
|
|
128
|
-
def get_messages_from_last_n_runs(
|
|
115
|
+
def get_messages(
|
|
129
116
|
self,
|
|
130
117
|
agent_id: Optional[str] = None,
|
|
131
118
|
team_id: Optional[str] = None,
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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,
|
|
136
123
|
skip_history_messages: bool = True,
|
|
137
124
|
) -> List[Message]:
|
|
138
|
-
"""Returns the messages
|
|
125
|
+
"""Returns the messages belonging to the session that fit the given criteria.
|
|
126
|
+
|
|
139
127
|
Args:
|
|
140
128
|
agent_id: The id of the agent to get the messages from.
|
|
141
129
|
team_id: The id of the team to get the messages from.
|
|
142
|
-
|
|
143
|
-
last_n_messages: The number of messages to return from the
|
|
144
|
-
|
|
145
|
-
|
|
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.
|
|
146
134
|
skip_history_messages: Skip messages that were tagged as history in previous runs.
|
|
135
|
+
|
|
147
136
|
Returns:
|
|
148
|
-
A list of Messages
|
|
137
|
+
A list of Messages belonging to the session.
|
|
149
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
|
+
|
|
150
154
|
if not self.runs:
|
|
151
155
|
return []
|
|
152
156
|
|
|
153
|
-
if
|
|
154
|
-
|
|
157
|
+
if skip_statuses is None:
|
|
158
|
+
skip_statuses = [RunStatus.paused, RunStatus.cancelled, RunStatus.error]
|
|
159
|
+
|
|
160
|
+
runs = self.runs
|
|
155
161
|
|
|
156
|
-
session_runs = self.runs
|
|
157
162
|
# Filter by agent_id and team_id
|
|
158
163
|
if agent_id:
|
|
159
|
-
|
|
164
|
+
runs = [run for run in runs if hasattr(run, "agent_id") and run.agent_id == agent_id] # type: ignore
|
|
160
165
|
if team_id:
|
|
161
|
-
|
|
166
|
+
runs = [run for run in runs if hasattr(run, "team_id") and run.team_id == team_id] # type: ignore
|
|
162
167
|
|
|
163
168
|
# Skip any messages that might be part of members of teams (for session re-use)
|
|
164
|
-
|
|
169
|
+
runs = [run for run in runs if run.parent_run_id is None] # type: ignore
|
|
165
170
|
|
|
166
171
|
# Filter by status
|
|
167
|
-
|
|
172
|
+
runs = [run for run in runs if hasattr(run, "status") and run.status not in skip_statuses] # type: ignore
|
|
168
173
|
|
|
169
174
|
messages_from_history = []
|
|
170
175
|
system_message = None
|
|
171
176
|
|
|
172
|
-
#
|
|
173
|
-
if
|
|
174
|
-
for run_response in
|
|
177
|
+
# Limit the number of messages returned if limit is set
|
|
178
|
+
if limit is not None:
|
|
179
|
+
for run_response in runs:
|
|
175
180
|
if not run_response or not run_response.messages:
|
|
176
181
|
continue
|
|
177
182
|
|
|
178
183
|
for message in run_response.messages or []:
|
|
179
|
-
if
|
|
184
|
+
if _should_skip_message(message, skip_roles, skip_history_messages):
|
|
180
185
|
continue
|
|
181
186
|
|
|
182
187
|
if message.role == "system":
|
|
@@ -188,24 +193,24 @@ class AgentSession:
|
|
|
188
193
|
|
|
189
194
|
if system_message:
|
|
190
195
|
messages_from_history = [system_message] + messages_from_history[
|
|
191
|
-
-(
|
|
196
|
+
-(limit - 1) :
|
|
192
197
|
] # Grab one less message then add the system message
|
|
193
198
|
else:
|
|
194
|
-
messages_from_history = messages_from_history[-
|
|
199
|
+
messages_from_history = messages_from_history[-limit:]
|
|
195
200
|
|
|
196
201
|
# Remove tool result messages that don't have an associated assistant message with tool calls
|
|
197
202
|
while len(messages_from_history) > 0 and messages_from_history[0].role == "tool":
|
|
198
203
|
messages_from_history.pop(0)
|
|
199
204
|
|
|
205
|
+
# If limit is not set, return all messages
|
|
200
206
|
else:
|
|
201
|
-
|
|
202
|
-
runs_to_process = session_runs[-last_n:] if last_n is not None else session_runs
|
|
207
|
+
runs_to_process = runs[-last_n_runs:] if last_n_runs is not None else runs
|
|
203
208
|
for run_response in runs_to_process:
|
|
204
209
|
if not run_response or not run_response.messages:
|
|
205
210
|
continue
|
|
206
211
|
|
|
207
212
|
for message in run_response.messages or []:
|
|
208
|
-
if
|
|
213
|
+
if _should_skip_message(message, skip_roles, skip_history_messages):
|
|
209
214
|
continue
|
|
210
215
|
|
|
211
216
|
if message.role == "system":
|
|
@@ -219,6 +224,18 @@ class AgentSession:
|
|
|
219
224
|
log_debug(f"Getting messages from previous runs: {len(messages_from_history)}")
|
|
220
225
|
return messages_from_history
|
|
221
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
|
+
|
|
222
239
|
def get_tool_calls(self, num_calls: Optional[int] = None) -> List[Dict[str, Any]]:
|
|
223
240
|
"""Returns a list of tool calls from the messages"""
|
|
224
241
|
|
|
@@ -235,61 +252,9 @@ class AgentSession:
|
|
|
235
252
|
return tool_calls
|
|
236
253
|
return tool_calls
|
|
237
254
|
|
|
238
|
-
def get_messages_for_session(
|
|
239
|
-
self,
|
|
240
|
-
user_role: str = "user",
|
|
241
|
-
assistant_role: Optional[List[str]] = None,
|
|
242
|
-
skip_history_messages: bool = True,
|
|
243
|
-
) -> List[Message]:
|
|
244
|
-
"""Returns a list of messages for the session that iterate through user message and assistant response."""
|
|
245
|
-
|
|
246
|
-
if assistant_role is None:
|
|
247
|
-
# TODO: Check if we still need CHATBOT as a role
|
|
248
|
-
assistant_role = ["assistant", "model", "CHATBOT"]
|
|
249
|
-
|
|
250
|
-
final_messages: List[Message] = []
|
|
251
|
-
session_runs = self.runs
|
|
252
|
-
if not session_runs:
|
|
253
|
-
return []
|
|
254
|
-
|
|
255
|
-
for run_response in session_runs:
|
|
256
|
-
if run_response and run_response.messages:
|
|
257
|
-
user_message_from_run = None
|
|
258
|
-
assistant_message_from_run = None
|
|
259
|
-
|
|
260
|
-
# Start from the beginning to look for the user message
|
|
261
|
-
for message in run_response.messages or []:
|
|
262
|
-
if hasattr(message, "from_history") and message.from_history and skip_history_messages:
|
|
263
|
-
continue
|
|
264
|
-
if message.role == user_role:
|
|
265
|
-
user_message_from_run = message
|
|
266
|
-
break
|
|
267
|
-
|
|
268
|
-
# Start from the end to look for the assistant response
|
|
269
|
-
for message in run_response.messages[::-1]:
|
|
270
|
-
if hasattr(message, "from_history") and message.from_history and skip_history_messages:
|
|
271
|
-
continue
|
|
272
|
-
if message.role in assistant_role:
|
|
273
|
-
assistant_message_from_run = message
|
|
274
|
-
break
|
|
275
|
-
|
|
276
|
-
if user_message_from_run and assistant_message_from_run:
|
|
277
|
-
final_messages.append(user_message_from_run)
|
|
278
|
-
final_messages.append(assistant_message_from_run)
|
|
279
|
-
return final_messages
|
|
280
|
-
|
|
281
255
|
def get_session_summary(self) -> Optional[SessionSummary]:
|
|
282
256
|
"""Get the session summary for the session"""
|
|
283
257
|
|
|
284
258
|
if self.summary is None:
|
|
285
259
|
return None
|
|
286
260
|
return self.summary
|
|
287
|
-
|
|
288
|
-
# Chat History functions
|
|
289
|
-
def get_chat_history(self) -> List[Message]:
|
|
290
|
-
"""Get the chat history for the session"""
|
|
291
|
-
|
|
292
|
-
messages = []
|
|
293
|
-
for run in self.runs or []:
|
|
294
|
-
messages.extend([msg for msg in run.messages or [] if not msg.from_history])
|
|
295
|
-
return messages
|
agno/session/summary.py
CHANGED
|
@@ -150,7 +150,7 @@ class SessionSummaryManager:
|
|
|
150
150
|
response_format = self.get_response_format(self.model)
|
|
151
151
|
|
|
152
152
|
system_message = self.get_system_message(
|
|
153
|
-
conversation=session.
|
|
153
|
+
conversation=session.get_messages(), # type: ignore
|
|
154
154
|
response_format=response_format,
|
|
155
155
|
)
|
|
156
156
|
|