agno 2.0.0rc2__py3-none-any.whl → 2.3.0__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 +6009 -2874
- agno/api/api.py +2 -0
- agno/api/os.py +1 -1
- agno/culture/__init__.py +3 -0
- agno/culture/manager.py +956 -0
- agno/db/async_postgres/__init__.py +3 -0
- agno/db/base.py +385 -6
- agno/db/dynamo/dynamo.py +388 -81
- agno/db/dynamo/schemas.py +47 -10
- agno/db/dynamo/utils.py +63 -4
- agno/db/firestore/firestore.py +435 -64
- agno/db/firestore/schemas.py +11 -0
- agno/db/firestore/utils.py +102 -4
- agno/db/gcs_json/gcs_json_db.py +384 -42
- agno/db/gcs_json/utils.py +60 -26
- agno/db/in_memory/in_memory_db.py +351 -66
- agno/db/in_memory/utils.py +60 -2
- agno/db/json/json_db.py +339 -48
- agno/db/json/utils.py +60 -26
- agno/db/migrations/manager.py +199 -0
- agno/db/migrations/v1_to_v2.py +510 -37
- 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 +2036 -0
- agno/db/mongo/mongo.py +653 -76
- agno/db/mongo/schemas.py +13 -0
- agno/db/mongo/utils.py +80 -8
- agno/db/mysql/mysql.py +687 -25
- agno/db/mysql/schemas.py +61 -37
- agno/db/mysql/utils.py +60 -2
- agno/db/postgres/__init__.py +2 -1
- agno/db/postgres/async_postgres.py +2001 -0
- agno/db/postgres/postgres.py +676 -57
- agno/db/postgres/schemas.py +43 -18
- agno/db/postgres/utils.py +164 -2
- agno/db/redis/redis.py +344 -38
- agno/db/redis/schemas.py +18 -0
- agno/db/redis/utils.py +60 -2
- agno/db/schemas/__init__.py +2 -1
- agno/db/schemas/culture.py +120 -0
- agno/db/schemas/memory.py +13 -0
- agno/db/singlestore/schemas.py +26 -1
- agno/db/singlestore/singlestore.py +687 -53
- agno/db/singlestore/utils.py +60 -2
- agno/db/sqlite/__init__.py +2 -1
- agno/db/sqlite/async_sqlite.py +2371 -0
- agno/db/sqlite/schemas.py +24 -0
- agno/db/sqlite/sqlite.py +774 -85
- agno/db/sqlite/utils.py +168 -5
- agno/db/surrealdb/__init__.py +3 -0
- agno/db/surrealdb/metrics.py +292 -0
- agno/db/surrealdb/models.py +309 -0
- agno/db/surrealdb/queries.py +71 -0
- agno/db/surrealdb/surrealdb.py +1361 -0
- agno/db/surrealdb/utils.py +147 -0
- agno/db/utils.py +50 -22
- agno/eval/accuracy.py +50 -43
- agno/eval/performance.py +6 -3
- agno/eval/reliability.py +6 -3
- agno/eval/utils.py +33 -16
- agno/exceptions.py +68 -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/integrations/discord/client.py +1 -0
- agno/knowledge/chunking/agentic.py +13 -10
- agno/knowledge/chunking/fixed.py +1 -1
- agno/knowledge/chunking/semantic.py +40 -8
- agno/knowledge/chunking/strategy.py +59 -15
- agno/knowledge/embedder/aws_bedrock.py +9 -4
- agno/knowledge/embedder/azure_openai.py +54 -0
- agno/knowledge/embedder/base.py +2 -0
- agno/knowledge/embedder/cohere.py +184 -5
- agno/knowledge/embedder/fastembed.py +1 -1
- agno/knowledge/embedder/google.py +79 -1
- agno/knowledge/embedder/huggingface.py +9 -4
- agno/knowledge/embedder/jina.py +63 -0
- agno/knowledge/embedder/mistral.py +78 -11
- agno/knowledge/embedder/nebius.py +1 -1
- agno/knowledge/embedder/ollama.py +13 -0
- agno/knowledge/embedder/openai.py +37 -65
- agno/knowledge/embedder/sentence_transformer.py +8 -4
- agno/knowledge/embedder/vllm.py +262 -0
- agno/knowledge/embedder/voyageai.py +69 -16
- agno/knowledge/knowledge.py +595 -187
- agno/knowledge/reader/base.py +9 -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 +290 -0
- agno/knowledge/reader/json_reader.py +6 -5
- agno/knowledge/reader/markdown_reader.py +13 -13
- agno/knowledge/reader/pdf_reader.py +43 -68
- agno/knowledge/reader/pptx_reader.py +101 -0
- agno/knowledge/reader/reader_factory.py +51 -6
- agno/knowledge/reader/s3_reader.py +3 -15
- agno/knowledge/reader/tavily_reader.py +194 -0
- agno/knowledge/reader/text_reader.py +13 -13
- agno/knowledge/reader/web_search_reader.py +2 -43
- agno/knowledge/reader/website_reader.py +43 -25
- agno/knowledge/reranker/__init__.py +3 -0
- agno/knowledge/types.py +9 -0
- agno/knowledge/utils.py +20 -0
- agno/media.py +339 -266
- agno/memory/manager.py +336 -82
- agno/models/aimlapi/aimlapi.py +2 -2
- agno/models/anthropic/claude.py +183 -37
- agno/models/aws/bedrock.py +52 -112
- agno/models/aws/claude.py +33 -1
- agno/models/azure/ai_foundry.py +33 -15
- agno/models/azure/openai_chat.py +25 -8
- agno/models/base.py +1011 -566
- agno/models/cerebras/cerebras.py +19 -13
- agno/models/cerebras/cerebras_openai.py +8 -5
- agno/models/cohere/chat.py +27 -1
- agno/models/cometapi/__init__.py +5 -0
- agno/models/cometapi/cometapi.py +57 -0
- agno/models/dashscope/dashscope.py +1 -0
- agno/models/deepinfra/deepinfra.py +2 -2
- agno/models/deepseek/deepseek.py +2 -2
- agno/models/fireworks/fireworks.py +2 -2
- agno/models/google/gemini.py +110 -37
- agno/models/groq/groq.py +28 -11
- agno/models/huggingface/huggingface.py +2 -1
- agno/models/internlm/internlm.py +2 -2
- agno/models/langdb/langdb.py +4 -4
- agno/models/litellm/chat.py +18 -1
- agno/models/litellm/litellm_openai.py +2 -2
- agno/models/llama_cpp/__init__.py +5 -0
- agno/models/llama_cpp/llama_cpp.py +22 -0
- agno/models/message.py +143 -4
- agno/models/meta/llama.py +27 -10
- agno/models/meta/llama_openai.py +5 -17
- agno/models/nebius/nebius.py +6 -6
- agno/models/nexus/__init__.py +3 -0
- agno/models/nexus/nexus.py +22 -0
- agno/models/nvidia/nvidia.py +2 -2
- agno/models/ollama/chat.py +60 -6
- agno/models/openai/chat.py +102 -43
- agno/models/openai/responses.py +103 -106
- agno/models/openrouter/openrouter.py +41 -3
- agno/models/perplexity/perplexity.py +4 -5
- agno/models/portkey/portkey.py +3 -3
- agno/models/requesty/__init__.py +5 -0
- agno/models/requesty/requesty.py +52 -0
- agno/models/response.py +81 -5
- agno/models/sambanova/sambanova.py +2 -2
- agno/models/siliconflow/__init__.py +5 -0
- agno/models/siliconflow/siliconflow.py +25 -0
- agno/models/together/together.py +2 -2
- agno/models/utils.py +254 -8
- agno/models/vercel/v0.py +2 -2
- agno/models/vertexai/__init__.py +0 -0
- agno/models/vertexai/claude.py +96 -0
- agno/models/vllm/vllm.py +1 -0
- agno/models/xai/xai.py +3 -2
- agno/os/app.py +543 -175
- agno/os/auth.py +24 -14
- agno/os/config.py +1 -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 +250 -0
- agno/os/interfaces/a2a/utils.py +924 -0
- agno/os/interfaces/agui/agui.py +23 -7
- agno/os/interfaces/agui/router.py +27 -3
- agno/os/interfaces/agui/utils.py +242 -142
- agno/os/interfaces/base.py +6 -2
- agno/os/interfaces/slack/router.py +81 -23
- agno/os/interfaces/slack/slack.py +29 -14
- agno/os/interfaces/whatsapp/router.py +11 -4
- agno/os/interfaces/whatsapp/whatsapp.py +14 -7
- agno/os/mcp.py +111 -54
- agno/os/middleware/__init__.py +7 -0
- agno/os/middleware/jwt.py +233 -0
- agno/os/router.py +556 -139
- agno/os/routers/evals/evals.py +71 -34
- agno/os/routers/evals/schemas.py +31 -31
- agno/os/routers/evals/utils.py +6 -5
- agno/os/routers/health.py +31 -0
- agno/os/routers/home.py +52 -0
- agno/os/routers/knowledge/knowledge.py +185 -38
- agno/os/routers/knowledge/schemas.py +82 -22
- agno/os/routers/memory/memory.py +158 -53
- agno/os/routers/memory/schemas.py +20 -16
- agno/os/routers/metrics/metrics.py +20 -8
- agno/os/routers/metrics/schemas.py +16 -16
- agno/os/routers/session/session.py +499 -38
- agno/os/schema.py +308 -198
- agno/os/utils.py +401 -41
- agno/reasoning/anthropic.py +80 -0
- agno/reasoning/azure_ai_foundry.py +2 -2
- agno/reasoning/deepseek.py +2 -2
- agno/reasoning/default.py +3 -1
- agno/reasoning/gemini.py +73 -0
- agno/reasoning/groq.py +2 -2
- agno/reasoning/ollama.py +2 -2
- agno/reasoning/openai.py +7 -2
- agno/reasoning/vertexai.py +76 -0
- agno/run/__init__.py +6 -0
- agno/run/agent.py +266 -112
- agno/run/base.py +53 -24
- agno/run/team.py +252 -111
- agno/run/workflow.py +156 -45
- agno/session/agent.py +105 -89
- agno/session/summary.py +65 -25
- agno/session/team.py +176 -96
- agno/session/workflow.py +406 -40
- agno/team/team.py +3854 -1692
- agno/tools/brightdata.py +3 -3
- agno/tools/cartesia.py +3 -5
- agno/tools/dalle.py +9 -8
- agno/tools/decorator.py +4 -2
- agno/tools/desi_vocal.py +2 -2
- agno/tools/duckduckgo.py +15 -11
- agno/tools/e2b.py +20 -13
- agno/tools/eleven_labs.py +26 -28
- agno/tools/exa.py +21 -16
- agno/tools/fal.py +4 -4
- agno/tools/file.py +153 -23
- agno/tools/file_generation.py +350 -0
- agno/tools/firecrawl.py +4 -4
- agno/tools/function.py +257 -37
- agno/tools/giphy.py +2 -2
- agno/tools/gmail.py +238 -14
- agno/tools/google_drive.py +270 -0
- agno/tools/googlecalendar.py +36 -8
- agno/tools/googlesheets.py +20 -5
- agno/tools/jira.py +20 -0
- agno/tools/knowledge.py +3 -3
- agno/tools/lumalab.py +3 -3
- 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 +11 -17
- agno/tools/memori.py +1 -53
- agno/tools/memory.py +419 -0
- agno/tools/models/azure_openai.py +2 -2
- agno/tools/models/gemini.py +3 -3
- agno/tools/models/groq.py +3 -5
- agno/tools/models/nebius.py +7 -7
- agno/tools/models_labs.py +25 -15
- agno/tools/notion.py +204 -0
- agno/tools/openai.py +4 -9
- agno/tools/opencv.py +3 -3
- agno/tools/parallel.py +314 -0
- agno/tools/replicate.py +7 -7
- agno/tools/scrapegraph.py +58 -31
- agno/tools/searxng.py +2 -2
- agno/tools/serper.py +2 -2
- agno/tools/slack.py +18 -3
- agno/tools/spider.py +2 -2
- agno/tools/tavily.py +146 -0
- agno/tools/whatsapp.py +1 -1
- agno/tools/workflow.py +278 -0
- agno/tools/yfinance.py +12 -11
- agno/utils/agent.py +820 -0
- agno/utils/audio.py +27 -0
- agno/utils/common.py +90 -1
- agno/utils/events.py +222 -7
- agno/utils/gemini.py +181 -23
- agno/utils/hooks.py +57 -0
- agno/utils/http.py +111 -0
- agno/utils/knowledge.py +12 -5
- agno/utils/log.py +1 -0
- agno/utils/mcp.py +95 -5
- agno/utils/media.py +188 -10
- agno/utils/merge_dict.py +22 -1
- agno/utils/message.py +60 -0
- agno/utils/models/claude.py +40 -11
- agno/utils/models/cohere.py +1 -1
- agno/utils/models/watsonx.py +1 -1
- agno/utils/openai.py +1 -1
- agno/utils/print_response/agent.py +105 -21
- agno/utils/print_response/team.py +103 -38
- agno/utils/print_response/workflow.py +251 -34
- agno/utils/reasoning.py +22 -1
- agno/utils/serialize.py +32 -0
- agno/utils/streamlit.py +16 -10
- agno/utils/string.py +41 -0
- agno/utils/team.py +98 -9
- agno/utils/tools.py +1 -1
- agno/vectordb/base.py +23 -4
- agno/vectordb/cassandra/cassandra.py +65 -9
- agno/vectordb/chroma/chromadb.py +182 -38
- agno/vectordb/clickhouse/clickhousedb.py +64 -11
- agno/vectordb/couchbase/couchbase.py +105 -10
- agno/vectordb/lancedb/lance_db.py +183 -135
- agno/vectordb/langchaindb/langchaindb.py +25 -7
- agno/vectordb/lightrag/lightrag.py +17 -3
- agno/vectordb/llamaindex/__init__.py +3 -0
- agno/vectordb/llamaindex/llamaindexdb.py +46 -7
- agno/vectordb/milvus/milvus.py +126 -9
- agno/vectordb/mongodb/__init__.py +7 -1
- agno/vectordb/mongodb/mongodb.py +112 -7
- agno/vectordb/pgvector/pgvector.py +142 -21
- agno/vectordb/pineconedb/pineconedb.py +80 -8
- agno/vectordb/qdrant/qdrant.py +125 -39
- agno/vectordb/redis/__init__.py +9 -0
- agno/vectordb/redis/redisdb.py +694 -0
- agno/vectordb/singlestore/singlestore.py +111 -25
- agno/vectordb/surrealdb/surrealdb.py +31 -5
- agno/vectordb/upstashdb/upstashdb.py +76 -8
- agno/vectordb/weaviate/weaviate.py +86 -15
- agno/workflow/__init__.py +2 -0
- agno/workflow/agent.py +299 -0
- agno/workflow/condition.py +112 -18
- agno/workflow/loop.py +69 -10
- agno/workflow/parallel.py +266 -118
- agno/workflow/router.py +110 -17
- agno/workflow/step.py +645 -136
- agno/workflow/steps.py +65 -6
- agno/workflow/types.py +71 -33
- agno/workflow/workflow.py +2113 -300
- agno-2.3.0.dist-info/METADATA +618 -0
- agno-2.3.0.dist-info/RECORD +577 -0
- agno-2.3.0.dist-info/licenses/LICENSE +201 -0
- agno/knowledge/reader/url_reader.py +0 -128
- agno/tools/googlesearch.py +0 -98
- agno/tools/mcp.py +0 -610
- agno/utils/models/aws_claude.py +0 -170
- agno-2.0.0rc2.dist-info/METADATA +0 -355
- agno-2.0.0rc2.dist-info/RECORD +0 -515
- agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
- {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/WHEEL +0 -0
- {agno-2.0.0rc2.dist-info → agno-2.3.0.dist-info}/top_level.txt +0 -0
agno/run/agent.py
CHANGED
|
@@ -1,17 +1,133 @@
|
|
|
1
1
|
from dataclasses import asdict, dataclass, field
|
|
2
2
|
from enum import Enum
|
|
3
3
|
from time import time
|
|
4
|
-
from typing import Any, Dict, List, Optional, Sequence, Union
|
|
4
|
+
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Sequence, Union
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
8
|
-
from agno.media import
|
|
8
|
+
from agno.media import Audio, File, Image, Video
|
|
9
9
|
from agno.models.message import Citations, Message
|
|
10
10
|
from agno.models.metrics import Metrics
|
|
11
11
|
from agno.models.response import ToolExecution
|
|
12
12
|
from agno.reasoning.step import ReasoningStep
|
|
13
13
|
from agno.run.base import BaseRunOutputEvent, MessageReferences, RunStatus
|
|
14
14
|
from agno.utils.log import logger
|
|
15
|
+
from agno.utils.media import (
|
|
16
|
+
reconstruct_audio_list,
|
|
17
|
+
reconstruct_files,
|
|
18
|
+
reconstruct_images,
|
|
19
|
+
reconstruct_response_audio,
|
|
20
|
+
reconstruct_videos,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from agno.session.summary import SessionSummary
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class RunInput:
|
|
29
|
+
"""Container for the raw input data passed to Agent.run().
|
|
30
|
+
|
|
31
|
+
This captures the original input exactly as provided by the user,
|
|
32
|
+
separate from the processed messages that go to the model.
|
|
33
|
+
|
|
34
|
+
Attributes:
|
|
35
|
+
input_content: The literal input message/content passed to run()
|
|
36
|
+
images: Images directly passed to run()
|
|
37
|
+
videos: Videos directly passed to run()
|
|
38
|
+
audios: Audio files directly passed to run()
|
|
39
|
+
files: Files directly passed to run()
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
input_content: Union[str, List, Dict, Message, BaseModel, List[Message]]
|
|
43
|
+
images: Optional[Sequence[Image]] = None
|
|
44
|
+
videos: Optional[Sequence[Video]] = None
|
|
45
|
+
audios: Optional[Sequence[Audio]] = None
|
|
46
|
+
files: Optional[Sequence[File]] = None
|
|
47
|
+
|
|
48
|
+
def input_content_string(self) -> str:
|
|
49
|
+
import json
|
|
50
|
+
|
|
51
|
+
if isinstance(self.input_content, (str)):
|
|
52
|
+
return self.input_content
|
|
53
|
+
elif isinstance(self.input_content, BaseModel):
|
|
54
|
+
return self.input_content.model_dump_json(exclude_none=True)
|
|
55
|
+
elif isinstance(self.input_content, Message):
|
|
56
|
+
return json.dumps(self.input_content.to_dict())
|
|
57
|
+
elif isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], Message):
|
|
58
|
+
return json.dumps([m.to_dict() for m in self.input_content])
|
|
59
|
+
else:
|
|
60
|
+
return str(self.input_content)
|
|
61
|
+
|
|
62
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
63
|
+
"""Convert to dictionary representation"""
|
|
64
|
+
result: Dict[str, Any] = {}
|
|
65
|
+
|
|
66
|
+
if self.input_content is not None:
|
|
67
|
+
if isinstance(self.input_content, (str)):
|
|
68
|
+
result["input_content"] = self.input_content
|
|
69
|
+
elif isinstance(self.input_content, BaseModel):
|
|
70
|
+
result["input_content"] = self.input_content.model_dump(exclude_none=True)
|
|
71
|
+
elif isinstance(self.input_content, Message):
|
|
72
|
+
result["input_content"] = self.input_content.to_dict()
|
|
73
|
+
|
|
74
|
+
# Handle input_content provided as a list of Message objects
|
|
75
|
+
elif (
|
|
76
|
+
isinstance(self.input_content, list)
|
|
77
|
+
and self.input_content
|
|
78
|
+
and isinstance(self.input_content[0], Message)
|
|
79
|
+
):
|
|
80
|
+
result["input_content"] = [m.to_dict() for m in self.input_content]
|
|
81
|
+
|
|
82
|
+
# Handle input_content provided as a list of dicts
|
|
83
|
+
elif (
|
|
84
|
+
isinstance(self.input_content, list) and self.input_content and isinstance(self.input_content[0], dict)
|
|
85
|
+
):
|
|
86
|
+
for content in self.input_content:
|
|
87
|
+
# Handle media input
|
|
88
|
+
if isinstance(content, dict):
|
|
89
|
+
if content.get("images"):
|
|
90
|
+
content["images"] = [
|
|
91
|
+
img.to_dict() if isinstance(img, Image) else img for img in content["images"]
|
|
92
|
+
]
|
|
93
|
+
if content.get("videos"):
|
|
94
|
+
content["videos"] = [
|
|
95
|
+
vid.to_dict() if isinstance(vid, Video) else vid for vid in content["videos"]
|
|
96
|
+
]
|
|
97
|
+
if content.get("audios"):
|
|
98
|
+
content["audios"] = [
|
|
99
|
+
aud.to_dict() if isinstance(aud, Audio) else aud for aud in content["audios"]
|
|
100
|
+
]
|
|
101
|
+
if content.get("files"):
|
|
102
|
+
content["files"] = [
|
|
103
|
+
file.to_dict() if isinstance(file, File) else file for file in content["files"]
|
|
104
|
+
]
|
|
105
|
+
result["input_content"] = self.input_content
|
|
106
|
+
else:
|
|
107
|
+
result["input_content"] = self.input_content
|
|
108
|
+
|
|
109
|
+
if self.images:
|
|
110
|
+
result["images"] = [img.to_dict() for img in self.images]
|
|
111
|
+
if self.videos:
|
|
112
|
+
result["videos"] = [vid.to_dict() for vid in self.videos]
|
|
113
|
+
if self.audios:
|
|
114
|
+
result["audios"] = [aud.to_dict() for aud in self.audios]
|
|
115
|
+
if self.files:
|
|
116
|
+
result["files"] = [file.to_dict() for file in self.files]
|
|
117
|
+
|
|
118
|
+
return result
|
|
119
|
+
|
|
120
|
+
@classmethod
|
|
121
|
+
def from_dict(cls, data: Dict[str, Any]) -> "RunInput":
|
|
122
|
+
"""Create RunInput from dictionary"""
|
|
123
|
+
images = reconstruct_images(data.get("images"))
|
|
124
|
+
videos = reconstruct_videos(data.get("videos"))
|
|
125
|
+
audios = reconstruct_audio_list(data.get("audios"))
|
|
126
|
+
files = reconstruct_files(data.get("files"))
|
|
127
|
+
|
|
128
|
+
return cls(
|
|
129
|
+
input_content=data.get("input_content", ""), images=images, videos=videos, audios=audios, files=files
|
|
130
|
+
)
|
|
15
131
|
|
|
16
132
|
|
|
17
133
|
class RunEvent(str, Enum):
|
|
@@ -19,6 +135,7 @@ class RunEvent(str, Enum):
|
|
|
19
135
|
|
|
20
136
|
run_started = "RunStarted"
|
|
21
137
|
run_content = "RunContent"
|
|
138
|
+
run_content_completed = "RunContentCompleted"
|
|
22
139
|
run_intermediate_content = "RunIntermediateContent"
|
|
23
140
|
run_completed = "RunCompleted"
|
|
24
141
|
run_error = "RunError"
|
|
@@ -27,6 +144,12 @@ class RunEvent(str, Enum):
|
|
|
27
144
|
run_paused = "RunPaused"
|
|
28
145
|
run_continued = "RunContinued"
|
|
29
146
|
|
|
147
|
+
pre_hook_started = "PreHookStarted"
|
|
148
|
+
pre_hook_completed = "PreHookCompleted"
|
|
149
|
+
|
|
150
|
+
post_hook_started = "PostHookStarted"
|
|
151
|
+
post_hook_completed = "PostHookCompleted"
|
|
152
|
+
|
|
30
153
|
tool_call_started = "ToolCallStarted"
|
|
31
154
|
tool_call_completed = "ToolCallCompleted"
|
|
32
155
|
|
|
@@ -37,6 +160,9 @@ class RunEvent(str, Enum):
|
|
|
37
160
|
memory_update_started = "MemoryUpdateStarted"
|
|
38
161
|
memory_update_completed = "MemoryUpdateCompleted"
|
|
39
162
|
|
|
163
|
+
session_summary_started = "SessionSummaryStarted"
|
|
164
|
+
session_summary_completed = "SessionSummaryCompleted"
|
|
165
|
+
|
|
40
166
|
parser_model_response_started = "ParserModelResponseStarted"
|
|
41
167
|
parser_model_response_completed = "ParserModelResponseCompleted"
|
|
42
168
|
|
|
@@ -53,6 +179,7 @@ class BaseAgentRunEvent(BaseRunOutputEvent):
|
|
|
53
179
|
agent_id: str = ""
|
|
54
180
|
agent_name: str = ""
|
|
55
181
|
run_id: Optional[str] = None
|
|
182
|
+
parent_run_id: Optional[str] = None
|
|
56
183
|
session_id: Optional[str] = None
|
|
57
184
|
|
|
58
185
|
# Step context for workflow execution
|
|
@@ -94,17 +221,26 @@ class RunContentEvent(BaseAgentRunEvent):
|
|
|
94
221
|
|
|
95
222
|
event: str = RunEvent.run_content.value
|
|
96
223
|
content: Optional[Any] = None
|
|
224
|
+
workflow_agent: bool = (
|
|
225
|
+
False # Used by consumers of the events to distinguish between workflow agent and regular agent
|
|
226
|
+
)
|
|
97
227
|
content_type: str = "str"
|
|
98
228
|
reasoning_content: Optional[str] = None
|
|
229
|
+
model_provider_data: Optional[Dict[str, Any]] = None
|
|
99
230
|
citations: Optional[Citations] = None
|
|
100
|
-
response_audio: Optional[
|
|
101
|
-
image: Optional[
|
|
231
|
+
response_audio: Optional[Audio] = None # Model audio response
|
|
232
|
+
image: Optional[Image] = None # Image attached to the response
|
|
102
233
|
references: Optional[List[MessageReferences]] = None
|
|
103
234
|
additional_input: Optional[List[Message]] = None
|
|
104
235
|
reasoning_steps: Optional[List[ReasoningStep]] = None
|
|
105
236
|
reasoning_messages: Optional[List[Message]] = None
|
|
106
237
|
|
|
107
238
|
|
|
239
|
+
@dataclass
|
|
240
|
+
class RunContentCompletedEvent(BaseAgentRunEvent):
|
|
241
|
+
event: str = RunEvent.run_content_completed.value
|
|
242
|
+
|
|
243
|
+
|
|
108
244
|
@dataclass
|
|
109
245
|
class IntermediateRunContentEvent(BaseAgentRunEvent):
|
|
110
246
|
event: str = RunEvent.run_intermediate_content.value
|
|
@@ -119,16 +255,18 @@ class RunCompletedEvent(BaseAgentRunEvent):
|
|
|
119
255
|
content_type: str = "str"
|
|
120
256
|
reasoning_content: Optional[str] = None
|
|
121
257
|
citations: Optional[Citations] = None
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
258
|
+
model_provider_data: Optional[Dict[str, Any]] = None
|
|
259
|
+
images: Optional[List[Image]] = None # Images attached to the response
|
|
260
|
+
videos: Optional[List[Video]] = None # Videos attached to the response
|
|
261
|
+
audio: Optional[List[Audio]] = None # Audio attached to the response
|
|
262
|
+
response_audio: Optional[Audio] = None # Model audio response
|
|
126
263
|
references: Optional[List[MessageReferences]] = None
|
|
127
264
|
additional_input: Optional[List[Message]] = None
|
|
128
265
|
reasoning_steps: Optional[List[ReasoningStep]] = None
|
|
129
266
|
reasoning_messages: Optional[List[Message]] = None
|
|
130
267
|
metadata: Optional[Dict[str, Any]] = None
|
|
131
268
|
metrics: Optional[Metrics] = None
|
|
269
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
132
270
|
|
|
133
271
|
|
|
134
272
|
@dataclass
|
|
@@ -151,6 +289,11 @@ class RunErrorEvent(BaseAgentRunEvent):
|
|
|
151
289
|
event: str = RunEvent.run_error.value
|
|
152
290
|
content: Optional[str] = None
|
|
153
291
|
|
|
292
|
+
# From exceptions
|
|
293
|
+
error_type: Optional[str] = None
|
|
294
|
+
error_id: Optional[str] = None
|
|
295
|
+
additional_data: Optional[Dict[str, Any]] = None
|
|
296
|
+
|
|
154
297
|
|
|
155
298
|
@dataclass
|
|
156
299
|
class RunCancelledEvent(BaseAgentRunEvent):
|
|
@@ -162,6 +305,32 @@ class RunCancelledEvent(BaseAgentRunEvent):
|
|
|
162
305
|
return True
|
|
163
306
|
|
|
164
307
|
|
|
308
|
+
@dataclass
|
|
309
|
+
class PreHookStartedEvent(BaseAgentRunEvent):
|
|
310
|
+
event: str = RunEvent.pre_hook_started.value
|
|
311
|
+
pre_hook_name: Optional[str] = None
|
|
312
|
+
run_input: Optional[RunInput] = None
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
@dataclass
|
|
316
|
+
class PreHookCompletedEvent(BaseAgentRunEvent):
|
|
317
|
+
event: str = RunEvent.pre_hook_completed.value
|
|
318
|
+
pre_hook_name: Optional[str] = None
|
|
319
|
+
run_input: Optional[RunInput] = None
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
@dataclass
|
|
323
|
+
class PostHookStartedEvent(BaseAgentRunEvent):
|
|
324
|
+
event: str = RunEvent.post_hook_started.value
|
|
325
|
+
post_hook_name: Optional[str] = None
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
@dataclass
|
|
329
|
+
class PostHookCompletedEvent(BaseAgentRunEvent):
|
|
330
|
+
event: str = RunEvent.post_hook_completed.value
|
|
331
|
+
post_hook_name: Optional[str] = None
|
|
332
|
+
|
|
333
|
+
|
|
165
334
|
@dataclass
|
|
166
335
|
class MemoryUpdateStartedEvent(BaseAgentRunEvent):
|
|
167
336
|
event: str = RunEvent.memory_update_started.value
|
|
@@ -172,6 +341,17 @@ class MemoryUpdateCompletedEvent(BaseAgentRunEvent):
|
|
|
172
341
|
event: str = RunEvent.memory_update_completed.value
|
|
173
342
|
|
|
174
343
|
|
|
344
|
+
@dataclass
|
|
345
|
+
class SessionSummaryStartedEvent(BaseAgentRunEvent):
|
|
346
|
+
event: str = RunEvent.session_summary_started.value
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
@dataclass
|
|
350
|
+
class SessionSummaryCompletedEvent(BaseAgentRunEvent):
|
|
351
|
+
event: str = RunEvent.session_summary_completed.value
|
|
352
|
+
session_summary: Optional["SessionSummary"] = None
|
|
353
|
+
|
|
354
|
+
|
|
175
355
|
@dataclass
|
|
176
356
|
class ReasoningStartedEvent(BaseAgentRunEvent):
|
|
177
357
|
event: str = RunEvent.reasoning_started.value
|
|
@@ -203,9 +383,9 @@ class ToolCallCompletedEvent(BaseAgentRunEvent):
|
|
|
203
383
|
event: str = RunEvent.tool_call_completed.value
|
|
204
384
|
tool: Optional[ToolExecution] = None
|
|
205
385
|
content: Optional[Any] = None
|
|
206
|
-
images: Optional[List[
|
|
207
|
-
videos: Optional[List[
|
|
208
|
-
audio: Optional[List[
|
|
386
|
+
images: Optional[List[Image]] = None # Images produced by the tool call
|
|
387
|
+
videos: Optional[List[Video]] = None # Videos produced by the tool call
|
|
388
|
+
audio: Optional[List[Audio]] = None # Audio produced by the tool call
|
|
209
389
|
|
|
210
390
|
|
|
211
391
|
@dataclass
|
|
@@ -232,21 +412,33 @@ class OutputModelResponseCompletedEvent(BaseAgentRunEvent):
|
|
|
232
412
|
class CustomEvent(BaseAgentRunEvent):
|
|
233
413
|
event: str = RunEvent.custom_event.value
|
|
234
414
|
|
|
415
|
+
def __init__(self, **kwargs):
|
|
416
|
+
# Store arbitrary attributes directly on the instance
|
|
417
|
+
for key, value in kwargs.items():
|
|
418
|
+
setattr(self, key, value)
|
|
419
|
+
|
|
235
420
|
|
|
236
421
|
RunOutputEvent = Union[
|
|
237
422
|
RunStartedEvent,
|
|
238
423
|
RunContentEvent,
|
|
239
424
|
IntermediateRunContentEvent,
|
|
425
|
+
RunContentCompletedEvent,
|
|
240
426
|
RunCompletedEvent,
|
|
241
427
|
RunErrorEvent,
|
|
242
428
|
RunCancelledEvent,
|
|
243
429
|
RunPausedEvent,
|
|
244
430
|
RunContinuedEvent,
|
|
431
|
+
PreHookStartedEvent,
|
|
432
|
+
PreHookCompletedEvent,
|
|
433
|
+
PostHookStartedEvent,
|
|
434
|
+
PostHookCompletedEvent,
|
|
245
435
|
ReasoningStartedEvent,
|
|
246
436
|
ReasoningStepEvent,
|
|
247
437
|
ReasoningCompletedEvent,
|
|
248
438
|
MemoryUpdateStartedEvent,
|
|
249
439
|
MemoryUpdateCompletedEvent,
|
|
440
|
+
SessionSummaryStartedEvent,
|
|
441
|
+
SessionSummaryCompletedEvent,
|
|
250
442
|
ToolCallStartedEvent,
|
|
251
443
|
ToolCallCompletedEvent,
|
|
252
444
|
ParserModelResponseStartedEvent,
|
|
@@ -261,17 +453,24 @@ RunOutputEvent = Union[
|
|
|
261
453
|
RUN_EVENT_TYPE_REGISTRY = {
|
|
262
454
|
RunEvent.run_started.value: RunStartedEvent,
|
|
263
455
|
RunEvent.run_content.value: RunContentEvent,
|
|
456
|
+
RunEvent.run_content_completed.value: RunContentCompletedEvent,
|
|
264
457
|
RunEvent.run_intermediate_content.value: IntermediateRunContentEvent,
|
|
265
458
|
RunEvent.run_completed.value: RunCompletedEvent,
|
|
266
459
|
RunEvent.run_error.value: RunErrorEvent,
|
|
267
460
|
RunEvent.run_cancelled.value: RunCancelledEvent,
|
|
268
461
|
RunEvent.run_paused.value: RunPausedEvent,
|
|
269
462
|
RunEvent.run_continued.value: RunContinuedEvent,
|
|
463
|
+
RunEvent.pre_hook_started.value: PreHookStartedEvent,
|
|
464
|
+
RunEvent.pre_hook_completed.value: PreHookCompletedEvent,
|
|
465
|
+
RunEvent.post_hook_started.value: PostHookStartedEvent,
|
|
466
|
+
RunEvent.post_hook_completed.value: PostHookCompletedEvent,
|
|
270
467
|
RunEvent.reasoning_started.value: ReasoningStartedEvent,
|
|
271
468
|
RunEvent.reasoning_step.value: ReasoningStepEvent,
|
|
272
469
|
RunEvent.reasoning_completed.value: ReasoningCompletedEvent,
|
|
273
470
|
RunEvent.memory_update_started.value: MemoryUpdateStartedEvent,
|
|
274
471
|
RunEvent.memory_update_completed.value: MemoryUpdateCompletedEvent,
|
|
472
|
+
RunEvent.session_summary_started.value: SessionSummaryStartedEvent,
|
|
473
|
+
RunEvent.session_summary_completed.value: SessionSummaryCompletedEvent,
|
|
275
474
|
RunEvent.tool_call_started.value: ToolCallStartedEvent,
|
|
276
475
|
RunEvent.tool_call_completed.value: ToolCallCompletedEvent,
|
|
277
476
|
RunEvent.parser_model_response_started.value: ParserModelResponseStartedEvent,
|
|
@@ -290,78 +489,6 @@ def run_output_event_from_dict(data: dict) -> BaseRunOutputEvent:
|
|
|
290
489
|
return cls.from_dict(data) # type: ignore
|
|
291
490
|
|
|
292
491
|
|
|
293
|
-
@dataclass
|
|
294
|
-
class RunInput:
|
|
295
|
-
"""Container for the raw input data passed to Agent.run().
|
|
296
|
-
|
|
297
|
-
This captures the original input exactly as provided by the user,
|
|
298
|
-
separate from the processed messages that go to the model.
|
|
299
|
-
|
|
300
|
-
Attributes:
|
|
301
|
-
input_content: The literal input message/content passed to run()
|
|
302
|
-
images: Images directly passed to run()
|
|
303
|
-
videos: Videos directly passed to run()
|
|
304
|
-
audios: Audio files directly passed to run()
|
|
305
|
-
files: Files directly passed to run()
|
|
306
|
-
"""
|
|
307
|
-
|
|
308
|
-
input_content: Optional[Union[str, List, Dict, Message, BaseModel, List[Message]]] = None
|
|
309
|
-
images: Optional[Sequence[ImageArtifact]] = None
|
|
310
|
-
videos: Optional[Sequence[VideoArtifact]] = None
|
|
311
|
-
audios: Optional[Sequence[AudioArtifact]] = None
|
|
312
|
-
files: Optional[Sequence[File]] = None
|
|
313
|
-
|
|
314
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
315
|
-
"""Convert to dictionary representation"""
|
|
316
|
-
result: Dict[str, Any] = {}
|
|
317
|
-
|
|
318
|
-
if self.input_content is not None:
|
|
319
|
-
if isinstance(self.input_content, (str)):
|
|
320
|
-
result["input_content"] = self.input_content
|
|
321
|
-
elif isinstance(self.input_content, BaseModel):
|
|
322
|
-
result["input_content"] = self.input_content.model_dump(exclude_none=True)
|
|
323
|
-
elif isinstance(self.input_content, Message):
|
|
324
|
-
result["input_content"] = self.input_content.to_dict()
|
|
325
|
-
elif (
|
|
326
|
-
isinstance(self.input_content, list)
|
|
327
|
-
and self.input_content
|
|
328
|
-
and isinstance(self.input_content[0], Message)
|
|
329
|
-
):
|
|
330
|
-
result["input_content"] = [m.to_dict() for m in self.input_content]
|
|
331
|
-
else:
|
|
332
|
-
result["input_content"] = self.input_content
|
|
333
|
-
|
|
334
|
-
if self.images:
|
|
335
|
-
result["images"] = [img.to_dict() for img in self.images]
|
|
336
|
-
if self.videos:
|
|
337
|
-
result["videos"] = [vid.to_dict() for vid in self.videos]
|
|
338
|
-
if self.audios:
|
|
339
|
-
result["audios"] = [aud.to_dict() for aud in self.audios]
|
|
340
|
-
|
|
341
|
-
return result
|
|
342
|
-
|
|
343
|
-
@classmethod
|
|
344
|
-
def from_dict(cls, data: Dict[str, Any]) -> "RunInput":
|
|
345
|
-
"""Create RunInput from dictionary"""
|
|
346
|
-
images = None
|
|
347
|
-
if data.get("images"):
|
|
348
|
-
images = [ImageArtifact.model_validate(img_data) for img_data in data["images"]]
|
|
349
|
-
|
|
350
|
-
videos = None
|
|
351
|
-
if data.get("videos"):
|
|
352
|
-
videos = [VideoArtifact.model_validate(vid_data) for vid_data in data["videos"]]
|
|
353
|
-
|
|
354
|
-
audios = None
|
|
355
|
-
if data.get("audios"):
|
|
356
|
-
audios = [AudioArtifact.model_validate(aud_data) for aud_data in data["audios"]]
|
|
357
|
-
|
|
358
|
-
files = None
|
|
359
|
-
if data.get("files"):
|
|
360
|
-
files = [File.model_validate(file_data) for file_data in data["files"]]
|
|
361
|
-
|
|
362
|
-
return cls(input_content=data.get("input_content"), images=images, videos=videos, audios=audios, files=files)
|
|
363
|
-
|
|
364
|
-
|
|
365
492
|
@dataclass
|
|
366
493
|
class RunOutput:
|
|
367
494
|
"""Response returned by Agent.run() or Workflow.run() functions"""
|
|
@@ -374,6 +501,9 @@ class RunOutput:
|
|
|
374
501
|
workflow_id: Optional[str] = None
|
|
375
502
|
user_id: Optional[str] = None
|
|
376
503
|
|
|
504
|
+
# Input media and messages from user
|
|
505
|
+
input: Optional[RunInput] = None
|
|
506
|
+
|
|
377
507
|
content: Optional[Any] = None
|
|
378
508
|
content_type: str = "str"
|
|
379
509
|
|
|
@@ -381,6 +511,8 @@ class RunOutput:
|
|
|
381
511
|
reasoning_steps: Optional[List[ReasoningStep]] = None
|
|
382
512
|
reasoning_messages: Optional[List[Message]] = None
|
|
383
513
|
|
|
514
|
+
model_provider_data: Optional[Dict[str, Any]] = None
|
|
515
|
+
|
|
384
516
|
model: Optional[str] = None
|
|
385
517
|
model_provider: Optional[str] = None
|
|
386
518
|
messages: Optional[List[Message]] = None
|
|
@@ -389,18 +521,17 @@ class RunOutput:
|
|
|
389
521
|
|
|
390
522
|
tools: Optional[List[ToolExecution]] = None
|
|
391
523
|
|
|
392
|
-
images: Optional[List[
|
|
393
|
-
videos: Optional[List[
|
|
394
|
-
audio: Optional[List[
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
# Input media and messages from user
|
|
398
|
-
input: Optional[RunInput] = None
|
|
524
|
+
images: Optional[List[Image]] = None # Images attached to the response
|
|
525
|
+
videos: Optional[List[Video]] = None # Videos attached to the response
|
|
526
|
+
audio: Optional[List[Audio]] = None # Audio attached to the response
|
|
527
|
+
files: Optional[List[File]] = None # Files attached to the response
|
|
528
|
+
response_audio: Optional[Audio] = None # Model audio response
|
|
399
529
|
|
|
400
530
|
citations: Optional[Citations] = None
|
|
401
531
|
references: Optional[List[MessageReferences]] = None
|
|
402
532
|
|
|
403
533
|
metadata: Optional[Dict[str, Any]] = None
|
|
534
|
+
session_state: Optional[Dict[str, Any]] = None
|
|
404
535
|
|
|
405
536
|
created_at: int = field(default_factory=lambda: int(time()))
|
|
406
537
|
|
|
@@ -446,6 +577,7 @@ class RunOutput:
|
|
|
446
577
|
"images",
|
|
447
578
|
"videos",
|
|
448
579
|
"audio",
|
|
580
|
+
"files",
|
|
449
581
|
"response_audio",
|
|
450
582
|
"input",
|
|
451
583
|
"citations",
|
|
@@ -487,7 +619,7 @@ class RunOutput:
|
|
|
487
619
|
if self.images is not None:
|
|
488
620
|
_dict["images"] = []
|
|
489
621
|
for img in self.images:
|
|
490
|
-
if isinstance(img,
|
|
622
|
+
if isinstance(img, Image):
|
|
491
623
|
_dict["images"].append(img.to_dict())
|
|
492
624
|
else:
|
|
493
625
|
_dict["images"].append(img)
|
|
@@ -495,7 +627,7 @@ class RunOutput:
|
|
|
495
627
|
if self.videos is not None:
|
|
496
628
|
_dict["videos"] = []
|
|
497
629
|
for vid in self.videos:
|
|
498
|
-
if isinstance(vid,
|
|
630
|
+
if isinstance(vid, Video):
|
|
499
631
|
_dict["videos"].append(vid.to_dict())
|
|
500
632
|
else:
|
|
501
633
|
_dict["videos"].append(vid)
|
|
@@ -503,13 +635,21 @@ class RunOutput:
|
|
|
503
635
|
if self.audio is not None:
|
|
504
636
|
_dict["audio"] = []
|
|
505
637
|
for aud in self.audio:
|
|
506
|
-
if isinstance(aud,
|
|
638
|
+
if isinstance(aud, Audio):
|
|
507
639
|
_dict["audio"].append(aud.to_dict())
|
|
508
640
|
else:
|
|
509
641
|
_dict["audio"].append(aud)
|
|
510
642
|
|
|
643
|
+
if self.files is not None:
|
|
644
|
+
_dict["files"] = []
|
|
645
|
+
for file in self.files:
|
|
646
|
+
if isinstance(file, File):
|
|
647
|
+
_dict["files"].append(file.to_dict())
|
|
648
|
+
else:
|
|
649
|
+
_dict["files"].append(file)
|
|
650
|
+
|
|
511
651
|
if self.response_audio is not None:
|
|
512
|
-
if isinstance(self.response_audio,
|
|
652
|
+
if isinstance(self.response_audio, Audio):
|
|
513
653
|
_dict["response_audio"] = self.response_audio.to_dict()
|
|
514
654
|
else:
|
|
515
655
|
_dict["response_audio"] = self.response_audio
|
|
@@ -536,7 +676,7 @@ class RunOutput:
|
|
|
536
676
|
|
|
537
677
|
return _dict
|
|
538
678
|
|
|
539
|
-
def to_json(self) -> str:
|
|
679
|
+
def to_json(self, separators=(", ", ": "), indent: Optional[int] = 2) -> str:
|
|
540
680
|
import json
|
|
541
681
|
|
|
542
682
|
try:
|
|
@@ -545,7 +685,10 @@ class RunOutput:
|
|
|
545
685
|
logger.error("Failed to convert response to json", exc_info=True)
|
|
546
686
|
raise
|
|
547
687
|
|
|
548
|
-
|
|
688
|
+
if indent is None:
|
|
689
|
+
return json.dumps(_dict, separators=separators)
|
|
690
|
+
else:
|
|
691
|
+
return json.dumps(_dict, indent=indent, separators=separators)
|
|
549
692
|
|
|
550
693
|
@classmethod
|
|
551
694
|
def from_dict(cls, data: Dict[str, Any]) -> "RunOutput":
|
|
@@ -553,10 +696,20 @@ class RunOutput:
|
|
|
553
696
|
data = data.pop("run")
|
|
554
697
|
|
|
555
698
|
events = data.pop("events", None)
|
|
556
|
-
|
|
699
|
+
final_events = []
|
|
700
|
+
for event in events or []:
|
|
701
|
+
if "agent_id" in event:
|
|
702
|
+
event = run_output_event_from_dict(event)
|
|
703
|
+
else:
|
|
704
|
+
# Use the factory from response.py for agent events
|
|
705
|
+
from agno.run.team import team_run_output_event_from_dict
|
|
706
|
+
|
|
707
|
+
event = team_run_output_event_from_dict(event)
|
|
708
|
+
final_events.append(event)
|
|
709
|
+
events = final_events
|
|
557
710
|
|
|
558
711
|
messages = data.pop("messages", None)
|
|
559
|
-
messages = [Message.
|
|
712
|
+
messages = [Message.from_dict(message) for message in messages] if messages else None
|
|
560
713
|
|
|
561
714
|
citations = data.pop("citations", None)
|
|
562
715
|
citations = Citations.model_validate(citations) if citations else None
|
|
@@ -564,17 +717,11 @@ class RunOutput:
|
|
|
564
717
|
tools = data.pop("tools", [])
|
|
565
718
|
tools = [ToolExecution.from_dict(tool) for tool in tools] if tools else None
|
|
566
719
|
|
|
567
|
-
images = data.pop("images", [])
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
audio = data.pop("audio", [])
|
|
574
|
-
audio = [AudioArtifact.model_validate(audio) for audio in audio] if audio else None
|
|
575
|
-
|
|
576
|
-
response_audio = data.pop("response_audio", None)
|
|
577
|
-
response_audio = AudioResponse.model_validate(response_audio) if response_audio else None
|
|
720
|
+
images = reconstruct_images(data.pop("images", []))
|
|
721
|
+
videos = reconstruct_videos(data.pop("videos", []))
|
|
722
|
+
audio = reconstruct_audio_list(data.pop("audio", []))
|
|
723
|
+
files = reconstruct_files(data.pop("files", []))
|
|
724
|
+
response_audio = reconstruct_response_audio(data.pop("response_audio", None))
|
|
578
725
|
|
|
579
726
|
input_data = data.pop("input", None)
|
|
580
727
|
input_obj = None
|
|
@@ -588,7 +735,7 @@ class RunOutput:
|
|
|
588
735
|
additional_input = data.pop("additional_input", None)
|
|
589
736
|
|
|
590
737
|
if additional_input is not None:
|
|
591
|
-
additional_input = [Message.
|
|
738
|
+
additional_input = [Message.from_dict(message) for message in additional_input]
|
|
592
739
|
|
|
593
740
|
reasoning_steps = data.pop("reasoning_steps", None)
|
|
594
741
|
if reasoning_steps is not None:
|
|
@@ -596,12 +743,18 @@ class RunOutput:
|
|
|
596
743
|
|
|
597
744
|
reasoning_messages = data.pop("reasoning_messages", None)
|
|
598
745
|
if reasoning_messages is not None:
|
|
599
|
-
reasoning_messages = [Message.
|
|
746
|
+
reasoning_messages = [Message.from_dict(message) for message in reasoning_messages]
|
|
600
747
|
|
|
601
748
|
references = data.pop("references", None)
|
|
602
749
|
if references is not None:
|
|
603
750
|
references = [MessageReferences.model_validate(reference) for reference in references]
|
|
604
751
|
|
|
752
|
+
# Filter data to only include fields that are actually defined in the RunOutput dataclass
|
|
753
|
+
from dataclasses import fields
|
|
754
|
+
|
|
755
|
+
supported_fields = {f.name for f in fields(cls)}
|
|
756
|
+
filtered_data = {k: v for k, v in data.items() if k in supported_fields}
|
|
757
|
+
|
|
605
758
|
return cls(
|
|
606
759
|
messages=messages,
|
|
607
760
|
metrics=metrics,
|
|
@@ -610,6 +763,7 @@ class RunOutput:
|
|
|
610
763
|
images=images,
|
|
611
764
|
audio=audio,
|
|
612
765
|
videos=videos,
|
|
766
|
+
files=files,
|
|
613
767
|
response_audio=response_audio,
|
|
614
768
|
input=input_obj,
|
|
615
769
|
events=events,
|
|
@@ -617,7 +771,7 @@ class RunOutput:
|
|
|
617
771
|
reasoning_steps=reasoning_steps,
|
|
618
772
|
reasoning_messages=reasoning_messages,
|
|
619
773
|
references=references,
|
|
620
|
-
**
|
|
774
|
+
**filtered_data,
|
|
621
775
|
)
|
|
622
776
|
|
|
623
777
|
def get_content_as_string(self, **kwargs) -> str:
|