agno 2.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/agent/agent.py +5540 -2273
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- 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/async_postgres/__init__.py +3 -0
- agno/db/base.py +689 -6
- agno/db/dynamo/dynamo.py +933 -37
- agno/db/dynamo/schemas.py +174 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +831 -9
- agno/db/firestore/schemas.py +51 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +660 -12
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +287 -14
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +590 -14
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +43 -13
- agno/db/migrations/versions/__init__.py +0 -0
- agno/db/migrations/versions/v2_3_0.py +938 -0
- agno/db/mongo/__init__.py +15 -1
- agno/db/mongo/async_mongo.py +2760 -0
- agno/db/mongo/mongo.py +879 -11
- agno/db/mongo/schemas.py +42 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/__init__.py +2 -1
- agno/db/mysql/async_mysql.py +2912 -0
- agno/db/mysql/mysql.py +946 -68
- agno/db/mysql/schemas.py +72 -10
- agno/db/mysql/utils.py +198 -7
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2579 -0
- agno/db/postgres/postgres.py +942 -57
- agno/db/postgres/schemas.py +81 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +671 -7
- agno/db/redis/schemas.py +50 -0
- agno/db/redis/utils.py +65 -7
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/evals.py +1 -0
- agno/db/schemas/memory.py +17 -2
- agno/db/singlestore/schemas.py +63 -0
- agno/db/singlestore/singlestore.py +949 -83
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2911 -0
- agno/db/sqlite/schemas.py +62 -0
- agno/db/sqlite/sqlite.py +965 -46
- agno/db/sqlite/utils.py +169 -8
- 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 +2 -0
- agno/eval/__init__.py +10 -0
- agno/eval/accuracy.py +75 -55
- agno/eval/agent_as_judge.py +861 -0
- agno/eval/base.py +29 -0
- agno/eval/performance.py +16 -7
- agno/eval/reliability.py +28 -16
- agno/eval/utils.py +35 -17
- agno/exceptions.py +27 -2
- agno/filters.py +354 -0
- agno/guardrails/prompt_injection.py +1 -0
- agno/hooks/__init__.py +3 -0
- agno/hooks/decorator.py +164 -0
- agno/integrations/discord/client.py +1 -1
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +4 -1
- agno/knowledge/chunking/semantic.py +9 -4
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +8 -0
- agno/knowledge/embedder/openai.py +8 -8
- agno/knowledge/embedder/sentence_transformer.py +6 -2
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/knowledge.py +1618 -318
- agno/knowledge/reader/base.py +6 -2
- agno/knowledge/reader/csv_reader.py +8 -10
- agno/knowledge/reader/docx_reader.py +5 -6
- agno/knowledge/reader/field_labeled_csv_reader.py +16 -20
- agno/knowledge/reader/json_reader.py +5 -4
- agno/knowledge/reader/markdown_reader.py +8 -8
- agno/knowledge/reader/pdf_reader.py +17 -19
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +32 -3
- agno/knowledge/reader/s3_reader.py +3 -3
- agno/knowledge/reader/tavily_reader.py +193 -0
- agno/knowledge/reader/text_reader.py +22 -10
- agno/knowledge/reader/web_search_reader.py +1 -48
- agno/knowledge/reader/website_reader.py +10 -10
- agno/knowledge/reader/wikipedia_reader.py +33 -1
- agno/knowledge/types.py +1 -0
- agno/knowledge/utils.py +72 -7
- agno/media.py +22 -6
- agno/memory/__init__.py +14 -1
- agno/memory/manager.py +544 -83
- 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 +515 -40
- agno/models/aws/bedrock.py +102 -21
- agno/models/aws/claude.py +131 -274
- agno/models/azure/ai_foundry.py +41 -19
- agno/models/azure/openai_chat.py +39 -8
- agno/models/base.py +1249 -525
- agno/models/cerebras/cerebras.py +91 -21
- agno/models/cerebras/cerebras_openai.py +21 -2
- agno/models/cohere/chat.py +40 -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 +877 -80
- agno/models/google/utils.py +22 -0
- agno/models/groq/groq.py +51 -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 +44 -9
- agno/models/litellm/litellm_openai.py +18 -1
- agno/models/message.py +28 -5
- agno/models/meta/llama.py +47 -14
- agno/models/meta/llama_openai.py +22 -17
- agno/models/mistral/mistral.py +8 -4
- agno/models/nebius/nebius.py +6 -7
- agno/models/nvidia/nvidia.py +20 -3
- agno/models/ollama/chat.py +24 -8
- agno/models/openai/chat.py +104 -29
- agno/models/openai/responses.py +101 -81
- agno/models/openrouter/openrouter.py +60 -3
- agno/models/perplexity/perplexity.py +17 -1
- agno/models/portkey/portkey.py +7 -6
- agno/models/requesty/requesty.py +24 -4
- agno/models/response.py +73 -2
- agno/models/sambanova/sambanova.py +20 -3
- agno/models/siliconflow/siliconflow.py +19 -2
- agno/models/together/together.py +20 -3
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +20 -3
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +190 -0
- agno/models/vllm/vllm.py +19 -14
- agno/models/xai/xai.py +19 -2
- agno/os/app.py +549 -152
- agno/os/auth.py +190 -3
- agno/os/config.py +23 -0
- agno/os/interfaces/a2a/router.py +8 -11
- agno/os/interfaces/a2a/utils.py +1 -1
- agno/os/interfaces/agui/router.py +18 -3
- agno/os/interfaces/agui/utils.py +152 -39
- agno/os/interfaces/slack/router.py +55 -37
- agno/os/interfaces/slack/slack.py +9 -1
- agno/os/interfaces/whatsapp/router.py +0 -1
- agno/os/interfaces/whatsapp/security.py +3 -1
- agno/os/mcp.py +110 -52
- agno/os/middleware/__init__.py +2 -0
- agno/os/middleware/jwt.py +676 -112
- agno/os/router.py +40 -1478
- 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/evals.py +96 -39
- agno/os/routers/evals/schemas.py +65 -33
- agno/os/routers/evals/utils.py +80 -10
- agno/os/routers/health.py +10 -4
- agno/os/routers/knowledge/knowledge.py +196 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +279 -52
- agno/os/routers/memory/schemas.py +46 -17
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +462 -34
- 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 +256 -693
- agno/os/scopes.py +469 -0
- agno/os/utils.py +514 -36
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/openai.py +5 -0
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +155 -32
- agno/run/base.py +55 -3
- agno/run/requirement.py +181 -0
- agno/run/team.py +125 -38
- agno/run/workflow.py +72 -18
- agno/session/agent.py +102 -89
- agno/session/summary.py +56 -15
- agno/session/team.py +164 -90
- agno/session/workflow.py +405 -40
- agno/table.py +10 -0
- agno/team/team.py +3974 -1903
- agno/tools/dalle.py +2 -4
- agno/tools/eleven_labs.py +23 -25
- agno/tools/exa.py +21 -16
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +16 -10
- agno/tools/firecrawl.py +15 -7
- agno/tools/function.py +193 -38
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +271 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- 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 +3 -3
- agno/tools/models/nebius.py +5 -5
- agno/tools/models_labs.py +20 -10
- agno/tools/nano_banana.py +151 -0
- agno/tools/notion.py +204 -0
- agno/tools/parallel.py +314 -0
- agno/tools/postgres.py +76 -36
- agno/tools/redshift.py +406 -0
- agno/tools/scrapegraph.py +1 -1
- agno/tools/shopify.py +1519 -0
- agno/tools/slack.py +18 -3
- agno/tools/spotify.py +919 -0
- agno/tools/tavily.py +146 -0
- agno/tools/toolkit.py +25 -0
- agno/tools/workflow.py +8 -1
- agno/tools/yfinance.py +12 -11
- 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/cryptography.py +22 -0
- agno/utils/dttm.py +33 -0
- agno/utils/events.py +151 -3
- agno/utils/gemini.py +15 -5
- agno/utils/hooks.py +118 -4
- agno/utils/http.py +113 -2
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +92 -2
- agno/utils/media.py +187 -1
- agno/utils/merge_dict.py +3 -3
- agno/utils/message.py +60 -0
- agno/utils/models/ai_foundry.py +9 -2
- agno/utils/models/claude.py +49 -14
- agno/utils/models/cohere.py +9 -2
- agno/utils/models/llama.py +9 -2
- agno/utils/models/mistral.py +4 -2
- agno/utils/print_response/agent.py +109 -16
- agno/utils/print_response/team.py +223 -30
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/streamlit.py +1 -1
- agno/utils/team.py +98 -9
- agno/utils/tokens.py +657 -0
- agno/vectordb/base.py +39 -7
- agno/vectordb/cassandra/cassandra.py +21 -5
- agno/vectordb/chroma/chromadb.py +43 -12
- agno/vectordb/clickhouse/clickhousedb.py +21 -5
- agno/vectordb/couchbase/couchbase.py +29 -5
- agno/vectordb/lancedb/lance_db.py +92 -181
- agno/vectordb/langchaindb/langchaindb.py +24 -4
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/llamaindexdb.py +25 -5
- agno/vectordb/milvus/milvus.py +50 -37
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +36 -30
- agno/vectordb/pgvector/pgvector.py +201 -77
- agno/vectordb/pineconedb/pineconedb.py +41 -23
- agno/vectordb/qdrant/qdrant.py +67 -54
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +682 -0
- agno/vectordb/singlestore/singlestore.py +50 -29
- agno/vectordb/surrealdb/surrealdb.py +31 -41
- agno/vectordb/upstashdb/upstashdb.py +34 -6
- agno/vectordb/weaviate/weaviate.py +53 -14
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +120 -18
- agno/workflow/loop.py +77 -10
- agno/workflow/parallel.py +231 -143
- agno/workflow/router.py +118 -17
- agno/workflow/step.py +609 -170
- agno/workflow/steps.py +73 -6
- agno/workflow/types.py +96 -21
- agno/workflow/workflow.py +2039 -262
- {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/METADATA +201 -66
- agno-2.3.13.dist-info/RECORD +613 -0
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -679
- agno/tools/memori.py +0 -339
- agno-2.1.2.dist-info/RECORD +0 -543
- {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/WHEEL +0 -0
- {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/licenses/LICENSE +0 -0
- {agno-2.1.2.dist-info → agno-2.3.13.dist-info}/top_level.txt +0 -0
agno/run/base.py
CHANGED
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
from dataclasses import asdict, dataclass
|
|
2
2
|
from enum import Enum
|
|
3
|
-
from typing import Any, Dict, Optional
|
|
3
|
+
from typing import Any, Dict, List, Optional, Type, Union
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel
|
|
6
6
|
|
|
7
|
+
from agno.filters import FilterExpr
|
|
7
8
|
from agno.media import Audio, Image, Video
|
|
8
9
|
from agno.models.message import Citations, Message, MessageReferences
|
|
9
10
|
from agno.models.metrics import Metrics
|
|
10
|
-
from agno.models.response import ToolExecution
|
|
11
11
|
from agno.reasoning.step import ReasoningStep
|
|
12
12
|
from agno.utils.log import log_error
|
|
13
13
|
|
|
14
14
|
|
|
15
|
+
@dataclass
|
|
16
|
+
class RunContext:
|
|
17
|
+
run_id: str
|
|
18
|
+
session_id: str
|
|
19
|
+
user_id: Optional[str] = None
|
|
20
|
+
|
|
21
|
+
dependencies: Optional[Dict[str, Any]] = None
|
|
22
|
+
knowledge_filters: Optional[Union[Dict[str, Any], List[FilterExpr]]] = None
|
|
23
|
+
metadata: Optional[Dict[str, Any]] = None
|
|
24
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
25
|
+
output_schema: Optional[Type[BaseModel]] = None
|
|
26
|
+
|
|
27
|
+
|
|
15
28
|
@dataclass
|
|
16
29
|
class BaseRunOutputEvent:
|
|
17
30
|
def to_dict(self) -> Dict[str, Any]:
|
|
@@ -35,7 +48,9 @@ class BaseRunOutputEvent:
|
|
|
35
48
|
"reasoning_steps",
|
|
36
49
|
"references",
|
|
37
50
|
"additional_input",
|
|
51
|
+
"session_summary",
|
|
38
52
|
"metrics",
|
|
53
|
+
"run_input",
|
|
39
54
|
]
|
|
40
55
|
}
|
|
41
56
|
|
|
@@ -97,6 +112,8 @@ class BaseRunOutputEvent:
|
|
|
97
112
|
_dict["content"] = self.content.model_dump(exclude_none=True)
|
|
98
113
|
|
|
99
114
|
if hasattr(self, "tools") and self.tools is not None:
|
|
115
|
+
from agno.models.response import ToolExecution
|
|
116
|
+
|
|
100
117
|
_dict["tools"] = []
|
|
101
118
|
for tool in self.tools:
|
|
102
119
|
if isinstance(tool, ToolExecution):
|
|
@@ -105,6 +122,8 @@ class BaseRunOutputEvent:
|
|
|
105
122
|
_dict["tools"].append(tool)
|
|
106
123
|
|
|
107
124
|
if hasattr(self, "tool") and self.tool is not None:
|
|
125
|
+
from agno.models.response import ToolExecution
|
|
126
|
+
|
|
108
127
|
if isinstance(self.tool, ToolExecution):
|
|
109
128
|
_dict["tool"] = self.tool.to_dict()
|
|
110
129
|
else:
|
|
@@ -113,6 +132,12 @@ class BaseRunOutputEvent:
|
|
|
113
132
|
if hasattr(self, "metrics") and self.metrics is not None:
|
|
114
133
|
_dict["metrics"] = self.metrics.to_dict()
|
|
115
134
|
|
|
135
|
+
if hasattr(self, "session_summary") and self.session_summary is not None:
|
|
136
|
+
_dict["session_summary"] = self.session_summary.to_dict()
|
|
137
|
+
|
|
138
|
+
if hasattr(self, "run_input") and self.run_input is not None:
|
|
139
|
+
_dict["run_input"] = self.run_input.to_dict()
|
|
140
|
+
|
|
116
141
|
return _dict
|
|
117
142
|
|
|
118
143
|
def to_json(self, separators=(", ", ": "), indent: Optional[int] = 2) -> str:
|
|
@@ -135,6 +160,8 @@ class BaseRunOutputEvent:
|
|
|
135
160
|
def from_dict(cls, data: Dict[str, Any]):
|
|
136
161
|
tool = data.pop("tool", None)
|
|
137
162
|
if tool:
|
|
163
|
+
from agno.models.response import ToolExecution
|
|
164
|
+
|
|
138
165
|
data["tool"] = ToolExecution.from_dict(tool)
|
|
139
166
|
|
|
140
167
|
images = data.pop("images", None)
|
|
@@ -173,7 +200,32 @@ class BaseRunOutputEvent:
|
|
|
173
200
|
if metrics:
|
|
174
201
|
data["metrics"] = Metrics(**metrics)
|
|
175
202
|
|
|
176
|
-
|
|
203
|
+
session_summary = data.pop("session_summary", None)
|
|
204
|
+
if session_summary:
|
|
205
|
+
from agno.session.summary import SessionSummary
|
|
206
|
+
|
|
207
|
+
data["session_summary"] = SessionSummary.from_dict(session_summary)
|
|
208
|
+
|
|
209
|
+
run_input = data.pop("run_input", None)
|
|
210
|
+
if run_input:
|
|
211
|
+
from agno.run.team import BaseTeamRunEvent
|
|
212
|
+
|
|
213
|
+
if issubclass(cls, BaseTeamRunEvent):
|
|
214
|
+
from agno.run.team import TeamRunInput
|
|
215
|
+
|
|
216
|
+
data["run_input"] = TeamRunInput.from_dict(run_input)
|
|
217
|
+
else:
|
|
218
|
+
from agno.run.agent import RunInput
|
|
219
|
+
|
|
220
|
+
data["run_input"] = RunInput.from_dict(run_input)
|
|
221
|
+
|
|
222
|
+
# Filter data to only include fields that are actually defined in the target class
|
|
223
|
+
from dataclasses import fields
|
|
224
|
+
|
|
225
|
+
supported_fields = {f.name for f in fields(cls)}
|
|
226
|
+
filtered_data = {k: v for k, v in data.items() if k in supported_fields}
|
|
227
|
+
|
|
228
|
+
return cls(**filtered_data)
|
|
177
229
|
|
|
178
230
|
@property
|
|
179
231
|
def is_paused(self):
|
agno/run/requirement.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from datetime import datetime, timezone
|
|
3
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional
|
|
4
|
+
from uuid import uuid4
|
|
5
|
+
|
|
6
|
+
from agno.models.response import ToolExecution, UserInputField
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class RunRequirement:
|
|
14
|
+
"""Requirement to complete a paused run (used in HITL flows)"""
|
|
15
|
+
|
|
16
|
+
tool_execution: Optional[ToolExecution] = None
|
|
17
|
+
created_at: datetime = field(default_factory=lambda: datetime.now(timezone.utc))
|
|
18
|
+
|
|
19
|
+
# User confirmation
|
|
20
|
+
confirmation: Optional[bool] = None
|
|
21
|
+
confirmation_note: Optional[str] = None
|
|
22
|
+
|
|
23
|
+
# User input
|
|
24
|
+
user_input_schema: Optional[List[UserInputField]] = None
|
|
25
|
+
|
|
26
|
+
# External execution
|
|
27
|
+
external_execution_result: Optional[str] = None
|
|
28
|
+
|
|
29
|
+
def __init__(
|
|
30
|
+
self,
|
|
31
|
+
tool_execution: ToolExecution,
|
|
32
|
+
id: Optional[str] = None,
|
|
33
|
+
created_at: Optional[datetime] = None,
|
|
34
|
+
):
|
|
35
|
+
self.id = id or str(uuid4())
|
|
36
|
+
self.tool_execution = tool_execution
|
|
37
|
+
self.user_input_schema = tool_execution.user_input_schema if tool_execution else None
|
|
38
|
+
self.created_at = created_at or datetime.now(timezone.utc)
|
|
39
|
+
self.confirmation = None
|
|
40
|
+
self.confirmation_note = None
|
|
41
|
+
self.external_execution_result = None
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def needs_confirmation(self) -> bool:
|
|
45
|
+
if self.confirmation is not None:
|
|
46
|
+
return False
|
|
47
|
+
if not self.tool_execution:
|
|
48
|
+
return False
|
|
49
|
+
if self.tool_execution.confirmed is True:
|
|
50
|
+
return True
|
|
51
|
+
|
|
52
|
+
return self.tool_execution.requires_confirmation or False
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def needs_user_input(self) -> bool:
|
|
56
|
+
if not self.tool_execution:
|
|
57
|
+
return False
|
|
58
|
+
if self.tool_execution.answered is True:
|
|
59
|
+
return False
|
|
60
|
+
if self.user_input_schema and not all(field.value is not None for field in self.user_input_schema):
|
|
61
|
+
return True
|
|
62
|
+
|
|
63
|
+
return self.tool_execution.requires_user_input or False
|
|
64
|
+
|
|
65
|
+
@property
|
|
66
|
+
def needs_external_execution(self) -> bool:
|
|
67
|
+
if not self.tool_execution:
|
|
68
|
+
return False
|
|
69
|
+
if self.external_execution_result is not None:
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
return self.tool_execution.external_execution_required or False
|
|
73
|
+
|
|
74
|
+
def confirm(self):
|
|
75
|
+
if not self.needs_confirmation:
|
|
76
|
+
raise ValueError("This requirement does not require confirmation")
|
|
77
|
+
self.confirmation = True
|
|
78
|
+
if self.tool_execution:
|
|
79
|
+
self.tool_execution.confirmed = True
|
|
80
|
+
|
|
81
|
+
def reject(self):
|
|
82
|
+
if not self.needs_confirmation:
|
|
83
|
+
raise ValueError("This requirement does not require confirmation")
|
|
84
|
+
self.confirmation = False
|
|
85
|
+
if self.tool_execution:
|
|
86
|
+
self.tool_execution.confirmed = False
|
|
87
|
+
|
|
88
|
+
def set_external_execution_result(self, result: str):
|
|
89
|
+
if not self.needs_external_execution:
|
|
90
|
+
raise ValueError("This requirement does not require external execution")
|
|
91
|
+
self.external_execution_result = result
|
|
92
|
+
if self.tool_execution:
|
|
93
|
+
self.tool_execution.result = result
|
|
94
|
+
|
|
95
|
+
def update_tool(self):
|
|
96
|
+
if not self.tool_execution:
|
|
97
|
+
return
|
|
98
|
+
if self.confirmation is True:
|
|
99
|
+
self.tool_execution.confirmed = True
|
|
100
|
+
elif self.confirmation is False:
|
|
101
|
+
self.tool_execution.confirmed = False
|
|
102
|
+
else:
|
|
103
|
+
raise ValueError("This requirement does not require confirmation or user input")
|
|
104
|
+
|
|
105
|
+
def is_resolved(self) -> bool:
|
|
106
|
+
"""Return True if the requirement has been resolved"""
|
|
107
|
+
return not self.needs_confirmation and not self.needs_user_input and not self.needs_external_execution
|
|
108
|
+
|
|
109
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
110
|
+
"""Convert to JSON-serializable dictionary for storage."""
|
|
111
|
+
_dict: Dict[str, Any] = {
|
|
112
|
+
"id": self.id,
|
|
113
|
+
"created_at": self.created_at.isoformat() if isinstance(self.created_at, datetime) else self.created_at,
|
|
114
|
+
"confirmation": self.confirmation,
|
|
115
|
+
"confirmation_note": self.confirmation_note,
|
|
116
|
+
"external_execution_result": self.external_execution_result,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if self.tool_execution is not None:
|
|
120
|
+
_dict["tool_execution"] = (
|
|
121
|
+
self.tool_execution.to_dict() if isinstance(self.tool_execution, ToolExecution) else self.tool_execution
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
if self.user_input_schema is not None:
|
|
125
|
+
_dict["user_input_schema"] = [f.to_dict() if hasattr(f, "to_dict") else f for f in self.user_input_schema]
|
|
126
|
+
|
|
127
|
+
return {k: v for k, v in _dict.items() if v is not None}
|
|
128
|
+
|
|
129
|
+
@classmethod
|
|
130
|
+
def from_dict(cls, data: Dict[str, Any]) -> "RunRequirement":
|
|
131
|
+
"""Reconstruct from stored dictionary."""
|
|
132
|
+
if data is None:
|
|
133
|
+
raise ValueError("RunRequirement.from_dict() requires a non-None dict")
|
|
134
|
+
|
|
135
|
+
# Handle tool_execution
|
|
136
|
+
tool_data = data.get("tool_execution")
|
|
137
|
+
tool_execution: Optional[ToolExecution] = None
|
|
138
|
+
if isinstance(tool_data, ToolExecution):
|
|
139
|
+
tool_execution = tool_data
|
|
140
|
+
elif isinstance(tool_data, dict):
|
|
141
|
+
tool_execution = ToolExecution.from_dict(tool_data)
|
|
142
|
+
|
|
143
|
+
# Handle created_at (ISO string or datetime)
|
|
144
|
+
created_at_raw = data.get("created_at")
|
|
145
|
+
created_at: Optional[datetime] = None
|
|
146
|
+
if isinstance(created_at_raw, datetime):
|
|
147
|
+
created_at = created_at_raw
|
|
148
|
+
elif isinstance(created_at_raw, str):
|
|
149
|
+
try:
|
|
150
|
+
created_at = datetime.fromisoformat(created_at_raw)
|
|
151
|
+
except ValueError:
|
|
152
|
+
created_at = None
|
|
153
|
+
|
|
154
|
+
# Build requirement - tool_execution is required by __init__
|
|
155
|
+
# For legacy data without tool_execution, create a minimal placeholder
|
|
156
|
+
if tool_execution is None:
|
|
157
|
+
tool_execution = ToolExecution(tool_name="unknown", tool_args={})
|
|
158
|
+
|
|
159
|
+
requirement = cls(
|
|
160
|
+
tool_execution=tool_execution,
|
|
161
|
+
id=data.get("id"),
|
|
162
|
+
created_at=created_at,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Set optional fields
|
|
166
|
+
requirement.confirmation = data.get("confirmation")
|
|
167
|
+
requirement.confirmation_note = data.get("confirmation_note")
|
|
168
|
+
requirement.external_execution_result = data.get("external_execution_result")
|
|
169
|
+
|
|
170
|
+
# Handle user_input_schema
|
|
171
|
+
schema_raw = data.get("user_input_schema")
|
|
172
|
+
if schema_raw is not None:
|
|
173
|
+
rebuilt_schema: List[UserInputField] = []
|
|
174
|
+
for item in schema_raw:
|
|
175
|
+
if isinstance(item, UserInputField):
|
|
176
|
+
rebuilt_schema.append(item)
|
|
177
|
+
elif isinstance(item, dict):
|
|
178
|
+
rebuilt_schema.append(UserInputField.from_dict(item))
|
|
179
|
+
requirement.user_input_schema = rebuilt_schema if rebuilt_schema else None
|
|
180
|
+
|
|
181
|
+
return requirement
|
agno/run/team.py
CHANGED
|
@@ -12,7 +12,15 @@ 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
|
|
17
|
+
from agno.utils.media import (
|
|
18
|
+
reconstruct_audio_list,
|
|
19
|
+
reconstruct_files,
|
|
20
|
+
reconstruct_images,
|
|
21
|
+
reconstruct_response_audio,
|
|
22
|
+
reconstruct_videos,
|
|
23
|
+
)
|
|
16
24
|
|
|
17
25
|
|
|
18
26
|
@dataclass
|
|
@@ -59,12 +67,39 @@ class TeamRunInput:
|
|
|
59
67
|
result["input_content"] = self.input_content.model_dump(exclude_none=True)
|
|
60
68
|
elif isinstance(self.input_content, Message):
|
|
61
69
|
result["input_content"] = self.input_content.to_dict()
|
|
70
|
+
|
|
71
|
+
# Handle input_content provided as a list of Message objects
|
|
62
72
|
elif (
|
|
63
73
|
isinstance(self.input_content, list)
|
|
64
74
|
and self.input_content
|
|
65
75
|
and isinstance(self.input_content[0], Message)
|
|
66
76
|
):
|
|
67
77
|
result["input_content"] = [m.to_dict() for m in self.input_content]
|
|
78
|
+
|
|
79
|
+
# Handle input_content provided as a list of dicts
|
|
80
|
+
elif (
|
|
81
|
+
isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], dict)
|
|
82
|
+
):
|
|
83
|
+
for content in self.input_content:
|
|
84
|
+
# Handle media input
|
|
85
|
+
if isinstance(content, dict):
|
|
86
|
+
if content.get("images"):
|
|
87
|
+
content["images"] = [
|
|
88
|
+
img.to_dict() if isinstance(img, Image) else img for img in content["images"]
|
|
89
|
+
]
|
|
90
|
+
if content.get("videos"):
|
|
91
|
+
content["videos"] = [
|
|
92
|
+
vid.to_dict() if isinstance(vid, Video) else vid for vid in content["videos"]
|
|
93
|
+
]
|
|
94
|
+
if content.get("audios"):
|
|
95
|
+
content["audios"] = [
|
|
96
|
+
aud.to_dict() if isinstance(aud, Audio) else aud for aud in content["audios"]
|
|
97
|
+
]
|
|
98
|
+
if content.get("files"):
|
|
99
|
+
content["files"] = [
|
|
100
|
+
file.to_dict() if isinstance(file, File) else file for file in content["files"]
|
|
101
|
+
]
|
|
102
|
+
result["input_content"] = self.input_content
|
|
68
103
|
else:
|
|
69
104
|
result["input_content"] = self.input_content
|
|
70
105
|
|
|
@@ -82,21 +117,10 @@ class TeamRunInput:
|
|
|
82
117
|
@classmethod
|
|
83
118
|
def from_dict(cls, data: Dict[str, Any]) -> "TeamRunInput":
|
|
84
119
|
"""Create TeamRunInput from dictionary"""
|
|
85
|
-
images =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
videos = None
|
|
90
|
-
if data.get("videos"):
|
|
91
|
-
videos = [Video.model_validate(vid_data) for vid_data in data["videos"]]
|
|
92
|
-
|
|
93
|
-
audios = None
|
|
94
|
-
if data.get("audios"):
|
|
95
|
-
audios = [Audio.model_validate(aud_data) for aud_data in data["audios"]]
|
|
96
|
-
|
|
97
|
-
files = None
|
|
98
|
-
if data.get("files"):
|
|
99
|
-
files = [File.model_validate(file_data) for file_data in data["files"]]
|
|
120
|
+
images = reconstruct_images(data.get("images"))
|
|
121
|
+
videos = reconstruct_videos(data.get("videos"))
|
|
122
|
+
audios = reconstruct_audio_list(data.get("audios"))
|
|
123
|
+
files = reconstruct_files(data.get("files"))
|
|
100
124
|
|
|
101
125
|
return cls(
|
|
102
126
|
input_content=data.get("input_content", ""), images=images, videos=videos, audios=audios, files=files
|
|
@@ -109,6 +133,7 @@ class TeamRunEvent(str, Enum):
|
|
|
109
133
|
run_started = "TeamRunStarted"
|
|
110
134
|
run_content = "TeamRunContent"
|
|
111
135
|
run_intermediate_content = "TeamRunIntermediateContent"
|
|
136
|
+
run_content_completed = "TeamRunContentCompleted"
|
|
112
137
|
run_completed = "TeamRunCompleted"
|
|
113
138
|
run_error = "TeamRunError"
|
|
114
139
|
run_cancelled = "TeamRunCancelled"
|
|
@@ -116,6 +141,9 @@ class TeamRunEvent(str, Enum):
|
|
|
116
141
|
pre_hook_started = "TeamPreHookStarted"
|
|
117
142
|
pre_hook_completed = "TeamPreHookCompleted"
|
|
118
143
|
|
|
144
|
+
post_hook_started = "TeamPostHookStarted"
|
|
145
|
+
post_hook_completed = "TeamPostHookCompleted"
|
|
146
|
+
|
|
119
147
|
tool_call_started = "TeamToolCallStarted"
|
|
120
148
|
tool_call_completed = "TeamToolCallCompleted"
|
|
121
149
|
|
|
@@ -126,6 +154,9 @@ class TeamRunEvent(str, Enum):
|
|
|
126
154
|
memory_update_started = "TeamMemoryUpdateStarted"
|
|
127
155
|
memory_update_completed = "TeamMemoryUpdateCompleted"
|
|
128
156
|
|
|
157
|
+
session_summary_started = "TeamSessionSummaryStarted"
|
|
158
|
+
session_summary_completed = "TeamSessionSummaryCompleted"
|
|
159
|
+
|
|
129
160
|
parser_model_response_started = "TeamParserModelResponseStarted"
|
|
130
161
|
parser_model_response_completed = "TeamParserModelResponseCompleted"
|
|
131
162
|
|
|
@@ -207,6 +238,11 @@ class IntermediateRunContentEvent(BaseTeamRunEvent):
|
|
|
207
238
|
content_type: str = "str"
|
|
208
239
|
|
|
209
240
|
|
|
241
|
+
@dataclass
|
|
242
|
+
class RunContentCompletedEvent(BaseTeamRunEvent):
|
|
243
|
+
event: str = TeamRunEvent.run_content_completed.value
|
|
244
|
+
|
|
245
|
+
|
|
210
246
|
@dataclass
|
|
211
247
|
class RunCompletedEvent(BaseTeamRunEvent):
|
|
212
248
|
event: str = TeamRunEvent.run_completed.value
|
|
@@ -226,6 +262,7 @@ class RunCompletedEvent(BaseTeamRunEvent):
|
|
|
226
262
|
member_responses: List[Union["TeamRunOutput", RunOutput]] = field(default_factory=list)
|
|
227
263
|
metadata: Optional[Dict[str, Any]] = None
|
|
228
264
|
metrics: Optional[Metrics] = None
|
|
265
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
229
266
|
|
|
230
267
|
|
|
231
268
|
@dataclass
|
|
@@ -263,6 +300,18 @@ class PreHookCompletedEvent(BaseTeamRunEvent):
|
|
|
263
300
|
run_input: Optional[TeamRunInput] = None
|
|
264
301
|
|
|
265
302
|
|
|
303
|
+
@dataclass
|
|
304
|
+
class PostHookStartedEvent(BaseTeamRunEvent):
|
|
305
|
+
event: str = TeamRunEvent.post_hook_started.value
|
|
306
|
+
post_hook_name: Optional[str] = None
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
@dataclass
|
|
310
|
+
class PostHookCompletedEvent(BaseTeamRunEvent):
|
|
311
|
+
event: str = TeamRunEvent.post_hook_completed.value
|
|
312
|
+
post_hook_name: Optional[str] = None
|
|
313
|
+
|
|
314
|
+
|
|
266
315
|
@dataclass
|
|
267
316
|
class MemoryUpdateStartedEvent(BaseTeamRunEvent):
|
|
268
317
|
event: str = TeamRunEvent.memory_update_started.value
|
|
@@ -273,6 +322,17 @@ class MemoryUpdateCompletedEvent(BaseTeamRunEvent):
|
|
|
273
322
|
event: str = TeamRunEvent.memory_update_completed.value
|
|
274
323
|
|
|
275
324
|
|
|
325
|
+
@dataclass
|
|
326
|
+
class SessionSummaryStartedEvent(BaseTeamRunEvent):
|
|
327
|
+
event: str = TeamRunEvent.session_summary_started.value
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
@dataclass
|
|
331
|
+
class SessionSummaryCompletedEvent(BaseTeamRunEvent):
|
|
332
|
+
event: str = TeamRunEvent.session_summary_completed.value
|
|
333
|
+
session_summary: Optional[Any] = None
|
|
334
|
+
|
|
335
|
+
|
|
276
336
|
@dataclass
|
|
277
337
|
class ReasoningStartedEvent(BaseTeamRunEvent):
|
|
278
338
|
event: str = TeamRunEvent.reasoning_started.value
|
|
@@ -333,11 +393,17 @@ class OutputModelResponseCompletedEvent(BaseTeamRunEvent):
|
|
|
333
393
|
class CustomEvent(BaseTeamRunEvent):
|
|
334
394
|
event: str = TeamRunEvent.custom_event.value
|
|
335
395
|
|
|
396
|
+
def __init__(self, **kwargs):
|
|
397
|
+
# Store arbitrary attributes directly on the instance
|
|
398
|
+
for key, value in kwargs.items():
|
|
399
|
+
setattr(self, key, value)
|
|
400
|
+
|
|
336
401
|
|
|
337
402
|
TeamRunOutputEvent = Union[
|
|
338
403
|
RunStartedEvent,
|
|
339
404
|
RunContentEvent,
|
|
340
405
|
IntermediateRunContentEvent,
|
|
406
|
+
RunContentCompletedEvent,
|
|
341
407
|
RunCompletedEvent,
|
|
342
408
|
RunErrorEvent,
|
|
343
409
|
RunCancelledEvent,
|
|
@@ -348,6 +414,8 @@ TeamRunOutputEvent = Union[
|
|
|
348
414
|
ReasoningCompletedEvent,
|
|
349
415
|
MemoryUpdateStartedEvent,
|
|
350
416
|
MemoryUpdateCompletedEvent,
|
|
417
|
+
SessionSummaryStartedEvent,
|
|
418
|
+
SessionSummaryCompletedEvent,
|
|
351
419
|
ToolCallStartedEvent,
|
|
352
420
|
ToolCallCompletedEvent,
|
|
353
421
|
ParserModelResponseStartedEvent,
|
|
@@ -362,16 +430,21 @@ TEAM_RUN_EVENT_TYPE_REGISTRY = {
|
|
|
362
430
|
TeamRunEvent.run_started.value: RunStartedEvent,
|
|
363
431
|
TeamRunEvent.run_content.value: RunContentEvent,
|
|
364
432
|
TeamRunEvent.run_intermediate_content.value: IntermediateRunContentEvent,
|
|
433
|
+
TeamRunEvent.run_content_completed.value: RunContentCompletedEvent,
|
|
365
434
|
TeamRunEvent.run_completed.value: RunCompletedEvent,
|
|
366
435
|
TeamRunEvent.run_error.value: RunErrorEvent,
|
|
367
436
|
TeamRunEvent.run_cancelled.value: RunCancelledEvent,
|
|
368
437
|
TeamRunEvent.pre_hook_started.value: PreHookStartedEvent,
|
|
369
438
|
TeamRunEvent.pre_hook_completed.value: PreHookCompletedEvent,
|
|
439
|
+
TeamRunEvent.post_hook_started.value: PostHookStartedEvent,
|
|
440
|
+
TeamRunEvent.post_hook_completed.value: PostHookCompletedEvent,
|
|
370
441
|
TeamRunEvent.reasoning_started.value: ReasoningStartedEvent,
|
|
371
442
|
TeamRunEvent.reasoning_step.value: ReasoningStepEvent,
|
|
372
443
|
TeamRunEvent.reasoning_completed.value: ReasoningCompletedEvent,
|
|
373
444
|
TeamRunEvent.memory_update_started.value: MemoryUpdateStartedEvent,
|
|
374
445
|
TeamRunEvent.memory_update_completed.value: MemoryUpdateCompletedEvent,
|
|
446
|
+
TeamRunEvent.session_summary_started.value: SessionSummaryStartedEvent,
|
|
447
|
+
TeamRunEvent.session_summary_completed.value: SessionSummaryCompletedEvent,
|
|
375
448
|
TeamRunEvent.tool_call_started.value: ToolCallStartedEvent,
|
|
376
449
|
TeamRunEvent.tool_call_completed.value: ToolCallCompletedEvent,
|
|
377
450
|
TeamRunEvent.parser_model_response_started.value: ParserModelResponseStartedEvent,
|
|
@@ -397,8 +470,19 @@ def team_run_output_event_from_dict(data: dict) -> BaseTeamRunEvent:
|
|
|
397
470
|
class TeamRunOutput:
|
|
398
471
|
"""Response returned by Team.run() functions"""
|
|
399
472
|
|
|
473
|
+
run_id: Optional[str] = None
|
|
474
|
+
team_id: Optional[str] = None
|
|
475
|
+
team_name: Optional[str] = None
|
|
476
|
+
session_id: Optional[str] = None
|
|
477
|
+
parent_run_id: Optional[str] = None
|
|
478
|
+
user_id: Optional[str] = None
|
|
479
|
+
|
|
480
|
+
# Input media and messages from user
|
|
481
|
+
input: Optional[TeamRunInput] = None
|
|
482
|
+
|
|
400
483
|
content: Optional[Any] = None
|
|
401
484
|
content_type: str = "str"
|
|
485
|
+
|
|
402
486
|
messages: Optional[List[Message]] = None
|
|
403
487
|
metrics: Optional[Metrics] = None
|
|
404
488
|
model: Optional[str] = None
|
|
@@ -406,12 +490,6 @@ class TeamRunOutput:
|
|
|
406
490
|
|
|
407
491
|
member_responses: List[Union["TeamRunOutput", RunOutput]] = field(default_factory=list)
|
|
408
492
|
|
|
409
|
-
run_id: Optional[str] = None
|
|
410
|
-
team_id: Optional[str] = None
|
|
411
|
-
team_name: Optional[str] = None
|
|
412
|
-
session_id: Optional[str] = None
|
|
413
|
-
parent_run_id: Optional[str] = None
|
|
414
|
-
|
|
415
493
|
tools: Optional[List[ToolExecution]] = None
|
|
416
494
|
|
|
417
495
|
images: Optional[List[Image]] = None # Images from member runs
|
|
@@ -421,14 +499,12 @@ class TeamRunOutput:
|
|
|
421
499
|
|
|
422
500
|
response_audio: Optional[Audio] = None # Model audio response
|
|
423
501
|
|
|
424
|
-
# Input media and messages from user
|
|
425
|
-
input: Optional[TeamRunInput] = None
|
|
426
|
-
|
|
427
502
|
reasoning_content: Optional[str] = None
|
|
428
503
|
|
|
429
504
|
citations: Optional[Citations] = None
|
|
430
505
|
model_provider_data: Optional[Dict[str, Any]] = None
|
|
431
506
|
metadata: Optional[Dict[str, Any]] = None
|
|
507
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
432
508
|
|
|
433
509
|
references: Optional[List[MessageReferences]] = None
|
|
434
510
|
additional_input: Optional[List[Message]] = None
|
|
@@ -440,11 +516,20 @@ class TeamRunOutput:
|
|
|
440
516
|
|
|
441
517
|
status: RunStatus = RunStatus.running
|
|
442
518
|
|
|
519
|
+
# User control flow (HITL) requirements to continue a run when paused, in order of arrival
|
|
520
|
+
requirements: Optional[list[RunRequirement]] = None
|
|
521
|
+
|
|
443
522
|
# === FOREIGN KEY RELATIONSHIPS ===
|
|
444
523
|
# These fields establish relationships to parent workflow/step structures
|
|
445
524
|
# and should be treated as foreign keys for data integrity
|
|
446
525
|
workflow_step_id: Optional[str] = None # FK: Points to StepOutput.step_id
|
|
447
526
|
|
|
527
|
+
@property
|
|
528
|
+
def active_requirements(self) -> list[RunRequirement]:
|
|
529
|
+
if not self.requirements:
|
|
530
|
+
return []
|
|
531
|
+
return [requirement for requirement in self.requirements if not requirement.is_resolved()]
|
|
532
|
+
|
|
448
533
|
@property
|
|
449
534
|
def is_paused(self):
|
|
450
535
|
return self.status == RunStatus.paused
|
|
@@ -461,6 +546,7 @@ class TeamRunOutput:
|
|
|
461
546
|
and k
|
|
462
547
|
not in [
|
|
463
548
|
"messages",
|
|
549
|
+
"metrics",
|
|
464
550
|
"status",
|
|
465
551
|
"tools",
|
|
466
552
|
"metadata",
|
|
@@ -480,6 +566,9 @@ class TeamRunOutput:
|
|
|
480
566
|
if self.events is not None:
|
|
481
567
|
_dict["events"] = [e.to_dict() for e in self.events]
|
|
482
568
|
|
|
569
|
+
if self.metrics is not None:
|
|
570
|
+
_dict["metrics"] = self.metrics.to_dict() if isinstance(self.metrics, Metrics) else self.metrics
|
|
571
|
+
|
|
483
572
|
if self.status is not None:
|
|
484
573
|
_dict["status"] = self.status.value if isinstance(self.status, RunStatus) else self.status
|
|
485
574
|
|
|
@@ -598,23 +687,15 @@ class TeamRunOutput:
|
|
|
598
687
|
if references is not None:
|
|
599
688
|
references = [MessageReferences.model_validate(reference) for reference in references]
|
|
600
689
|
|
|
601
|
-
images = data.pop("images", [])
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
videos = [Video.model_validate(video) for video in videos] if videos else None
|
|
606
|
-
|
|
607
|
-
audio = data.pop("audio", [])
|
|
608
|
-
audio = [Audio.model_validate(audio) for audio in audio] if audio else None
|
|
609
|
-
|
|
610
|
-
files = data.pop("files", [])
|
|
611
|
-
files = [File.model_validate(file) for file in files] if files else None
|
|
690
|
+
images = reconstruct_images(data.pop("images", []))
|
|
691
|
+
videos = reconstruct_videos(data.pop("videos", []))
|
|
692
|
+
audio = reconstruct_audio_list(data.pop("audio", []))
|
|
693
|
+
files = reconstruct_files(data.pop("files", []))
|
|
612
694
|
|
|
613
695
|
tools = data.pop("tools", [])
|
|
614
696
|
tools = [ToolExecution.from_dict(tool) for tool in tools] if tools else None
|
|
615
697
|
|
|
616
|
-
response_audio = data.pop("response_audio", None)
|
|
617
|
-
response_audio = Audio.model_validate(response_audio) if response_audio else None
|
|
698
|
+
response_audio = reconstruct_response_audio(data.pop("response_audio", None))
|
|
618
699
|
|
|
619
700
|
input_data = data.pop("input", None)
|
|
620
701
|
input_obj = None
|
|
@@ -628,6 +709,12 @@ class TeamRunOutput:
|
|
|
628
709
|
citations = data.pop("citations", None)
|
|
629
710
|
citations = Citations.model_validate(citations) if citations else None
|
|
630
711
|
|
|
712
|
+
# Filter data to only include fields that are actually defined in the TeamRunOutput dataclass
|
|
713
|
+
from dataclasses import fields
|
|
714
|
+
|
|
715
|
+
supported_fields = {f.name for f in fields(cls)}
|
|
716
|
+
filtered_data = {k: v for k, v in data.items() if k in supported_fields}
|
|
717
|
+
|
|
631
718
|
return cls(
|
|
632
719
|
messages=messages,
|
|
633
720
|
metrics=metrics,
|
|
@@ -645,7 +732,7 @@ class TeamRunOutput:
|
|
|
645
732
|
citations=citations,
|
|
646
733
|
tools=tools,
|
|
647
734
|
events=events,
|
|
648
|
-
**
|
|
735
|
+
**filtered_data,
|
|
649
736
|
)
|
|
650
737
|
|
|
651
738
|
def get_content_as_string(self, **kwargs) -> str:
|