agno 2.0.0rc2__py3-none-any.whl → 2.0.2__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 +78 -135
- agno/knowledge/knowledge.py +1 -1
- agno/knowledge/reranker/__init__.py +3 -0
- agno/media.py +269 -268
- agno/models/base.py +13 -48
- agno/models/google/gemini.py +11 -10
- agno/models/message.py +4 -4
- agno/models/ollama/chat.py +1 -1
- agno/models/openai/chat.py +33 -14
- agno/models/response.py +5 -5
- agno/os/app.py +8 -5
- agno/run/agent.py +28 -28
- agno/run/base.py +9 -19
- agno/run/team.py +24 -24
- agno/run/workflow.py +16 -16
- agno/team/team.py +72 -154
- agno/tools/brightdata.py +3 -3
- agno/tools/cartesia.py +3 -5
- agno/tools/dalle.py +7 -4
- agno/tools/desi_vocal.py +2 -2
- agno/tools/e2b.py +6 -6
- agno/tools/eleven_labs.py +3 -3
- agno/tools/fal.py +4 -4
- agno/tools/function.py +7 -7
- agno/tools/giphy.py +2 -2
- agno/tools/lumalab.py +3 -3
- 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 +2 -2
- agno/tools/models_labs.py +5 -5
- agno/tools/openai.py +4 -9
- agno/tools/opencv.py +3 -3
- agno/tools/replicate.py +7 -7
- agno/utils/events.py +5 -5
- agno/utils/gemini.py +1 -1
- agno/utils/mcp.py +3 -3
- agno/utils/models/aws_claude.py +1 -1
- agno/utils/models/cohere.py +1 -1
- agno/utils/models/watsonx.py +1 -1
- agno/utils/openai.py +1 -1
- agno/vectordb/lancedb/lance_db.py +82 -25
- agno/workflow/step.py +7 -7
- agno/workflow/types.py +13 -13
- agno/workflow/workflow.py +28 -28
- {agno-2.0.0rc2.dist-info → agno-2.0.2.dist-info}/METADATA +140 -1
- {agno-2.0.0rc2.dist-info → agno-2.0.2.dist-info}/RECORD +50 -50
- agno-2.0.2.dist-info/licenses/LICENSE +201 -0
- agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
- {agno-2.0.0rc2.dist-info → agno-2.0.2.dist-info}/WHEEL +0 -0
- {agno-2.0.0rc2.dist-info → agno-2.0.2.dist-info}/top_level.txt +0 -0
agno/run/team.py
CHANGED
|
@@ -5,7 +5,7 @@ from typing import 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
|
|
@@ -98,8 +98,8 @@ class RunContentEvent(BaseTeamRunEvent):
|
|
|
98
98
|
content_type: str = "str"
|
|
99
99
|
reasoning_content: Optional[str] = None
|
|
100
100
|
citations: Optional[Citations] = None
|
|
101
|
-
response_audio: Optional[
|
|
102
|
-
image: Optional[
|
|
101
|
+
response_audio: Optional[Audio] = None # Model audio response
|
|
102
|
+
image: Optional[Image] = None # Image attached to the response
|
|
103
103
|
references: Optional[List[MessageReferences]] = None
|
|
104
104
|
additional_input: Optional[List[Message]] = None
|
|
105
105
|
reasoning_steps: Optional[List[ReasoningStep]] = None
|
|
@@ -120,10 +120,10 @@ class RunCompletedEvent(BaseTeamRunEvent):
|
|
|
120
120
|
content_type: str = "str"
|
|
121
121
|
reasoning_content: Optional[str] = None
|
|
122
122
|
citations: Optional[Citations] = None
|
|
123
|
-
images: Optional[List[
|
|
124
|
-
videos: Optional[List[
|
|
125
|
-
audio: Optional[List[
|
|
126
|
-
response_audio: Optional[
|
|
123
|
+
images: Optional[List[Image]] = None # Images attached to the response
|
|
124
|
+
videos: Optional[List[Video]] = None # Videos attached to the response
|
|
125
|
+
audio: Optional[List[Audio]] = None # Audio attached to the response
|
|
126
|
+
response_audio: Optional[Audio] = None # Model audio response
|
|
127
127
|
references: Optional[List[MessageReferences]] = None
|
|
128
128
|
additional_input: Optional[List[Message]] = None
|
|
129
129
|
reasoning_steps: Optional[List[ReasoningStep]] = None
|
|
@@ -190,9 +190,9 @@ class ToolCallCompletedEvent(BaseTeamRunEvent):
|
|
|
190
190
|
event: str = TeamRunEvent.tool_call_completed.value
|
|
191
191
|
tool: Optional[ToolExecution] = None
|
|
192
192
|
content: Optional[Any] = None
|
|
193
|
-
images: Optional[List[
|
|
194
|
-
videos: Optional[List[
|
|
195
|
-
audio: Optional[List[
|
|
193
|
+
images: Optional[List[Image]] = None # Images produced by the tool call
|
|
194
|
+
videos: Optional[List[Video]] = None # Videos produced by the tool call
|
|
195
|
+
audio: Optional[List[Audio]] = None # Audio produced by the tool call
|
|
196
196
|
|
|
197
197
|
|
|
198
198
|
@dataclass
|
|
@@ -289,9 +289,9 @@ class TeamRunInput:
|
|
|
289
289
|
"""
|
|
290
290
|
|
|
291
291
|
input_content: Optional[Union[str, List, Dict, Message, BaseModel, List[Message]]] = None
|
|
292
|
-
images: Optional[Sequence[
|
|
293
|
-
videos: Optional[Sequence[
|
|
294
|
-
audios: Optional[Sequence[
|
|
292
|
+
images: Optional[Sequence[Image]] = None
|
|
293
|
+
videos: Optional[Sequence[Video]] = None
|
|
294
|
+
audios: Optional[Sequence[Audio]] = None
|
|
295
295
|
files: Optional[Sequence[File]] = None
|
|
296
296
|
|
|
297
297
|
def to_dict(self) -> Dict[str, Any]:
|
|
@@ -328,15 +328,15 @@ class TeamRunInput:
|
|
|
328
328
|
"""Create TeamRunInput from dictionary"""
|
|
329
329
|
images = None
|
|
330
330
|
if data.get("images"):
|
|
331
|
-
images = [
|
|
331
|
+
images = [Image.model_validate(img_data) for img_data in data["images"]]
|
|
332
332
|
|
|
333
333
|
videos = None
|
|
334
334
|
if data.get("videos"):
|
|
335
|
-
videos = [
|
|
335
|
+
videos = [Video.model_validate(vid_data) for vid_data in data["videos"]]
|
|
336
336
|
|
|
337
337
|
audios = None
|
|
338
338
|
if data.get("audios"):
|
|
339
|
-
audios = [
|
|
339
|
+
audios = [Audio.model_validate(aud_data) for aud_data in data["audios"]]
|
|
340
340
|
|
|
341
341
|
files = None
|
|
342
342
|
if data.get("files"):
|
|
@@ -366,11 +366,11 @@ class TeamRunOutput:
|
|
|
366
366
|
|
|
367
367
|
tools: Optional[List[ToolExecution]] = None
|
|
368
368
|
|
|
369
|
-
images: Optional[List[
|
|
370
|
-
videos: Optional[List[
|
|
371
|
-
audio: Optional[List[
|
|
369
|
+
images: Optional[List[Image]] = None # Images from member runs
|
|
370
|
+
videos: Optional[List[Video]] = None # Videos from member runs
|
|
371
|
+
audio: Optional[List[Audio]] = None # Audio from member runs
|
|
372
372
|
|
|
373
|
-
response_audio: Optional[
|
|
373
|
+
response_audio: Optional[Audio] = None # Model audio response
|
|
374
374
|
|
|
375
375
|
# Input media and messages from user
|
|
376
376
|
input: Optional[TeamRunInput] = None
|
|
@@ -539,19 +539,19 @@ class TeamRunOutput:
|
|
|
539
539
|
references = [MessageReferences.model_validate(reference) for reference in references]
|
|
540
540
|
|
|
541
541
|
images = data.pop("images", [])
|
|
542
|
-
images = [
|
|
542
|
+
images = [Image.model_validate(image) for image in images] if images else None
|
|
543
543
|
|
|
544
544
|
videos = data.pop("videos", [])
|
|
545
|
-
videos = [
|
|
545
|
+
videos = [Video.model_validate(video) for video in videos] if videos else None
|
|
546
546
|
|
|
547
547
|
audio = data.pop("audio", [])
|
|
548
|
-
audio = [
|
|
548
|
+
audio = [Audio.model_validate(audio) for audio in audio] if audio else None
|
|
549
549
|
|
|
550
550
|
tools = data.pop("tools", [])
|
|
551
551
|
tools = [ToolExecution.from_dict(tool) for tool in tools] if tools else None
|
|
552
552
|
|
|
553
553
|
response_audio = data.pop("response_audio", None)
|
|
554
|
-
response_audio =
|
|
554
|
+
response_audio = Audio.model_validate(response_audio) if response_audio else None
|
|
555
555
|
|
|
556
556
|
input_data = data.pop("input", None)
|
|
557
557
|
input_obj = None
|
agno/run/workflow.py
CHANGED
|
@@ -5,7 +5,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
|
|
5
5
|
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
8
|
-
from agno.media import
|
|
8
|
+
from agno.media import Audio, Image, Video
|
|
9
9
|
from agno.run.agent import RunOutput
|
|
10
10
|
from agno.run.base import RunStatus
|
|
11
11
|
from agno.run.team import TeamRunOutput
|
|
@@ -182,10 +182,10 @@ class StepCompletedEvent(BaseWorkflowRunOutputEvent):
|
|
|
182
182
|
content_type: str = "str"
|
|
183
183
|
|
|
184
184
|
# Media content fields
|
|
185
|
-
images: Optional[List[
|
|
186
|
-
videos: Optional[List[
|
|
187
|
-
audio: Optional[List[
|
|
188
|
-
response_audio: Optional[
|
|
185
|
+
images: Optional[List[Image]] = None
|
|
186
|
+
videos: Optional[List[Video]] = None
|
|
187
|
+
audio: Optional[List[Audio]] = None
|
|
188
|
+
response_audio: Optional[Audio] = None
|
|
189
189
|
|
|
190
190
|
# Store actual step execution results as StepOutput objects
|
|
191
191
|
step_response: Optional[StepOutput] = None
|
|
@@ -361,15 +361,15 @@ class StepOutputEvent(BaseWorkflowRunOutputEvent):
|
|
|
361
361
|
return self.step_output.content if self.step_output else None
|
|
362
362
|
|
|
363
363
|
@property
|
|
364
|
-
def images(self) -> Optional[List[
|
|
364
|
+
def images(self) -> Optional[List[Image]]:
|
|
365
365
|
return self.step_output.images if self.step_output else None
|
|
366
366
|
|
|
367
367
|
@property
|
|
368
|
-
def videos(self) -> Optional[List[
|
|
368
|
+
def videos(self) -> Optional[List[Video]]:
|
|
369
369
|
return self.step_output.videos if self.step_output else None
|
|
370
370
|
|
|
371
371
|
@property
|
|
372
|
-
def audio(self) -> Optional[List[
|
|
372
|
+
def audio(self) -> Optional[List[Audio]]:
|
|
373
373
|
return self.step_output.audio if self.step_output else None
|
|
374
374
|
|
|
375
375
|
@property
|
|
@@ -433,10 +433,10 @@ class WorkflowRunOutput:
|
|
|
433
433
|
session_id: Optional[str] = None
|
|
434
434
|
|
|
435
435
|
# Media content fields
|
|
436
|
-
images: Optional[List[
|
|
437
|
-
videos: Optional[List[
|
|
438
|
-
audio: Optional[List[
|
|
439
|
-
response_audio: Optional[
|
|
436
|
+
images: Optional[List[Image]] = None
|
|
437
|
+
videos: Optional[List[Video]] = None
|
|
438
|
+
audio: Optional[List[Audio]] = None
|
|
439
|
+
response_audio: Optional[Audio] = None
|
|
440
440
|
|
|
441
441
|
# Store actual step execution results as StepOutput objects
|
|
442
442
|
step_results: List[Union[StepOutput, List[StepOutput]]] = field(default_factory=list)
|
|
@@ -554,16 +554,16 @@ class WorkflowRunOutput:
|
|
|
554
554
|
metadata = data.pop("metadata", None)
|
|
555
555
|
|
|
556
556
|
images = data.pop("images", [])
|
|
557
|
-
images = [
|
|
557
|
+
images = [Image.model_validate(image) for image in images] if images else None
|
|
558
558
|
|
|
559
559
|
videos = data.pop("videos", [])
|
|
560
|
-
videos = [
|
|
560
|
+
videos = [Video.model_validate(video) for video in videos] if videos else None
|
|
561
561
|
|
|
562
562
|
audio = data.pop("audio", [])
|
|
563
|
-
audio = [
|
|
563
|
+
audio = [Audio.model_validate(audio) for audio in audio] if audio else None
|
|
564
564
|
|
|
565
565
|
response_audio = data.pop("response_audio", None)
|
|
566
|
-
response_audio =
|
|
566
|
+
response_audio = Audio.model_validate(response_audio) if response_audio else None
|
|
567
567
|
|
|
568
568
|
events = data.pop("events", [])
|
|
569
569
|
|
agno/team/team.py
CHANGED
|
@@ -33,7 +33,7 @@ from agno.agent import Agent
|
|
|
33
33
|
from agno.db.base import BaseDb, SessionType, UserMemory
|
|
34
34
|
from agno.exceptions import ModelProviderError, RunCancelledException
|
|
35
35
|
from agno.knowledge.knowledge import Knowledge
|
|
36
|
-
from agno.media import Audio,
|
|
36
|
+
from agno.media import Audio, File, Image, Video
|
|
37
37
|
from agno.memory import MemoryManager
|
|
38
38
|
from agno.models.base import Model
|
|
39
39
|
from agno.models.message import Message, MessageReferences
|
|
@@ -546,11 +546,11 @@ class Team:
|
|
|
546
546
|
|
|
547
547
|
# TODO: Remove these
|
|
548
548
|
# Images generated during this session
|
|
549
|
-
self.images: Optional[List[
|
|
549
|
+
self.images: Optional[List[Image]] = None
|
|
550
550
|
# Audio generated during this session
|
|
551
|
-
self.audio: Optional[List[
|
|
551
|
+
self.audio: Optional[List[Audio]] = None
|
|
552
552
|
# Videos generated during this session
|
|
553
|
-
self.videos: Optional[List[
|
|
553
|
+
self.videos: Optional[List[Video]] = None
|
|
554
554
|
|
|
555
555
|
# Team session
|
|
556
556
|
self._team_session: Optional[TeamSession] = None
|
|
@@ -1119,7 +1119,7 @@ class Team:
|
|
|
1119
1119
|
# Initialize Team
|
|
1120
1120
|
self.initialize_team(debug_mode=debug_mode)
|
|
1121
1121
|
|
|
1122
|
-
image_artifacts, video_artifacts, audio_artifacts = self.
|
|
1122
|
+
image_artifacts, video_artifacts, audio_artifacts = self._validate_media_object_id(
|
|
1123
1123
|
images=images, videos=videos, audios=audio
|
|
1124
1124
|
)
|
|
1125
1125
|
|
|
@@ -1661,7 +1661,7 @@ class Team:
|
|
|
1661
1661
|
# Initialize Team
|
|
1662
1662
|
self.initialize_team(debug_mode=debug_mode)
|
|
1663
1663
|
|
|
1664
|
-
image_artifacts, video_artifacts, audio_artifacts = self.
|
|
1664
|
+
image_artifacts, video_artifacts, audio_artifacts = self._validate_media_object_id(
|
|
1665
1665
|
images=images, videos=videos, audios=audio
|
|
1666
1666
|
)
|
|
1667
1667
|
|
|
@@ -2155,28 +2155,38 @@ class Team:
|
|
|
2155
2155
|
should_yield = True
|
|
2156
2156
|
|
|
2157
2157
|
# Process thinking
|
|
2158
|
-
if model_response_event.reasoning_content is not None:
|
|
2159
|
-
if not full_model_response.reasoning_content:
|
|
2160
|
-
full_model_response.reasoning_content = model_response_event.reasoning_content
|
|
2161
|
-
else:
|
|
2162
|
-
full_model_response.reasoning_content += model_response_event.reasoning_content
|
|
2163
|
-
should_yield = True
|
|
2164
|
-
|
|
2165
|
-
if model_response_event.citations is not None:
|
|
2166
|
-
# We get citations in one chunk
|
|
2167
|
-
full_model_response.citations = model_response_event.citations
|
|
2168
|
-
should_yield = True
|
|
2169
|
-
|
|
2170
|
-
# Process audio
|
|
2171
2158
|
if model_response_event.audio is not None:
|
|
2172
2159
|
if full_model_response.audio is None:
|
|
2173
|
-
full_model_response.audio =
|
|
2160
|
+
full_model_response.audio = Audio(id=str(uuid4()), content=b"", transcript="")
|
|
2174
2161
|
|
|
2175
2162
|
if model_response_event.audio.id is not None:
|
|
2176
2163
|
full_model_response.audio.id = model_response_event.audio.id # type: ignore
|
|
2164
|
+
|
|
2177
2165
|
if model_response_event.audio.content is not None:
|
|
2178
|
-
|
|
2166
|
+
# Handle both base64 string and bytes content
|
|
2167
|
+
if isinstance(model_response_event.audio.content, str):
|
|
2168
|
+
# Decode base64 string to bytes
|
|
2169
|
+
try:
|
|
2170
|
+
import base64
|
|
2171
|
+
|
|
2172
|
+
decoded_content = base64.b64decode(model_response_event.audio.content)
|
|
2173
|
+
if full_model_response.audio.content is None:
|
|
2174
|
+
full_model_response.audio.content = b""
|
|
2175
|
+
full_model_response.audio.content += decoded_content
|
|
2176
|
+
except Exception:
|
|
2177
|
+
# If decode fails, encode string as bytes
|
|
2178
|
+
if full_model_response.audio.content is None:
|
|
2179
|
+
full_model_response.audio.content = b""
|
|
2180
|
+
full_model_response.audio.content += model_response_event.audio.content.encode("utf-8")
|
|
2181
|
+
elif isinstance(model_response_event.audio.content, bytes):
|
|
2182
|
+
# Content is already bytes
|
|
2183
|
+
if full_model_response.audio.content is None:
|
|
2184
|
+
full_model_response.audio.content = b""
|
|
2185
|
+
full_model_response.audio.content += model_response_event.audio.content
|
|
2186
|
+
|
|
2179
2187
|
if model_response_event.audio.transcript is not None:
|
|
2188
|
+
if full_model_response.audio.transcript is None:
|
|
2189
|
+
full_model_response.audio.transcript = ""
|
|
2180
2190
|
full_model_response.audio.transcript += model_response_event.audio.transcript # type: ignore
|
|
2181
2191
|
if model_response_event.audio.expires_at is not None:
|
|
2182
2192
|
full_model_response.audio.expires_at = model_response_event.audio.expires_at # type: ignore
|
|
@@ -3021,63 +3031,43 @@ class Team:
|
|
|
3021
3031
|
message.image_output = None
|
|
3022
3032
|
message.video_output = None
|
|
3023
3033
|
|
|
3024
|
-
def
|
|
3034
|
+
def _validate_media_object_id(
|
|
3025
3035
|
self,
|
|
3026
3036
|
images: Optional[Sequence[Image]] = None,
|
|
3027
3037
|
videos: Optional[Sequence[Video]] = None,
|
|
3028
3038
|
audios: Optional[Sequence[Audio]] = None,
|
|
3029
3039
|
) -> tuple:
|
|
3030
|
-
|
|
3031
|
-
from uuid import uuid4
|
|
3032
|
-
|
|
3033
|
-
from agno.media import AudioArtifact, ImageArtifact, VideoArtifact
|
|
3034
|
-
|
|
3035
|
-
image_artifacts = None
|
|
3040
|
+
image_list = None
|
|
3036
3041
|
if images:
|
|
3037
|
-
|
|
3042
|
+
image_list = []
|
|
3038
3043
|
for img in images:
|
|
3039
|
-
|
|
3040
|
-
|
|
3044
|
+
if not img.id:
|
|
3045
|
+
from uuid import uuid4
|
|
3041
3046
|
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
elif img.content:
|
|
3045
|
-
image_artifacts.append(ImageArtifact(id=artifact_id, content=img.content))
|
|
3046
|
-
except Exception as e:
|
|
3047
|
-
log_warning(f"Error creating ImageArtifact: {e}")
|
|
3048
|
-
continue
|
|
3047
|
+
img.id = str(uuid4())
|
|
3048
|
+
image_list.append(img)
|
|
3049
3049
|
|
|
3050
|
-
|
|
3050
|
+
video_list = None
|
|
3051
3051
|
if videos:
|
|
3052
|
-
|
|
3052
|
+
video_list = []
|
|
3053
3053
|
for vid in videos:
|
|
3054
|
-
|
|
3055
|
-
|
|
3054
|
+
if not vid.id:
|
|
3055
|
+
from uuid import uuid4
|
|
3056
3056
|
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
elif vid.content:
|
|
3060
|
-
video_artifacts.append(VideoArtifact(id=artifact_id, content=vid.content))
|
|
3061
|
-
except Exception as e:
|
|
3062
|
-
log_warning(f"Error creating VideoArtifact: {e}")
|
|
3063
|
-
continue
|
|
3057
|
+
vid.id = str(uuid4())
|
|
3058
|
+
video_list.append(vid)
|
|
3064
3059
|
|
|
3065
|
-
|
|
3060
|
+
audio_list = None
|
|
3066
3061
|
if audios:
|
|
3067
|
-
|
|
3062
|
+
audio_list = []
|
|
3068
3063
|
for aud in audios:
|
|
3069
|
-
|
|
3070
|
-
|
|
3064
|
+
if not aud.id:
|
|
3065
|
+
from uuid import uuid4
|
|
3071
3066
|
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
elif aud.content:
|
|
3075
|
-
audio_artifacts.append(AudioArtifact(id=artifact_id, base64_audio=aud.content))
|
|
3076
|
-
except Exception as e:
|
|
3077
|
-
log_warning(f"Error creating AudioArtifact: {e}")
|
|
3078
|
-
continue
|
|
3067
|
+
aud.id = str(uuid4())
|
|
3068
|
+
audio_list.append(aud)
|
|
3079
3069
|
|
|
3080
|
-
return
|
|
3070
|
+
return image_list, video_list, audio_list
|
|
3081
3071
|
|
|
3082
3072
|
def cli_app(
|
|
3083
3073
|
self,
|
|
@@ -3754,19 +3744,11 @@ class Team:
|
|
|
3754
3744
|
session: Optional[TeamSession] = None,
|
|
3755
3745
|
) -> Optional[Sequence[Image]]:
|
|
3756
3746
|
"""Collect images from input, session history, and current run response."""
|
|
3757
|
-
joint_images = []
|
|
3747
|
+
joint_images: List[Image] = []
|
|
3758
3748
|
|
|
3759
3749
|
# 1. Add images from current input
|
|
3760
3750
|
if run_input and run_input.images:
|
|
3761
|
-
|
|
3762
|
-
try:
|
|
3763
|
-
if artifact.url:
|
|
3764
|
-
joint_images.append(Image(url=artifact.url))
|
|
3765
|
-
elif artifact.content:
|
|
3766
|
-
joint_images.append(Image(content=artifact.content))
|
|
3767
|
-
except Exception as e:
|
|
3768
|
-
log_warning(f"Error converting ImageArtifact to Image: {e}")
|
|
3769
|
-
continue
|
|
3751
|
+
joint_images.extend(run_input.images)
|
|
3770
3752
|
log_debug(f"Added {len(run_input.images)} input images to joint list")
|
|
3771
3753
|
|
|
3772
3754
|
# 2. Add images from session history (from both input and generated sources)
|
|
@@ -3775,30 +3757,14 @@ class Team:
|
|
|
3775
3757
|
for historical_run in session.runs:
|
|
3776
3758
|
# Add generated images from previous runs
|
|
3777
3759
|
if historical_run.images:
|
|
3778
|
-
|
|
3779
|
-
try:
|
|
3780
|
-
if artifact.url:
|
|
3781
|
-
joint_images.append(Image(url=artifact.url))
|
|
3782
|
-
elif artifact.content:
|
|
3783
|
-
joint_images.append(Image(content=artifact.content))
|
|
3784
|
-
except Exception as e:
|
|
3785
|
-
log_warning(f"Error converting historical ImageArtifact to Image: {e}")
|
|
3786
|
-
continue
|
|
3760
|
+
joint_images.extend(historical_run.images)
|
|
3787
3761
|
log_debug(
|
|
3788
3762
|
f"Added {len(historical_run.images)} generated images from historical run {historical_run.run_id}"
|
|
3789
3763
|
)
|
|
3790
3764
|
|
|
3791
3765
|
# Add input images from previous runs
|
|
3792
3766
|
if historical_run.input and historical_run.input.images:
|
|
3793
|
-
|
|
3794
|
-
try:
|
|
3795
|
-
if artifact.url:
|
|
3796
|
-
joint_images.append(Image(url=artifact.url))
|
|
3797
|
-
elif artifact.content:
|
|
3798
|
-
joint_images.append(Image(content=artifact.content))
|
|
3799
|
-
except Exception as e:
|
|
3800
|
-
log_warning(f"Error converting input ImageArtifact to Image: {e}")
|
|
3801
|
-
continue
|
|
3767
|
+
joint_images.extend(historical_run.input.images)
|
|
3802
3768
|
log_debug(
|
|
3803
3769
|
f"Added {len(historical_run.input.images)} input images from historical run {historical_run.run_id}"
|
|
3804
3770
|
)
|
|
@@ -3815,19 +3781,11 @@ class Team:
|
|
|
3815
3781
|
session: Optional[TeamSession] = None,
|
|
3816
3782
|
) -> Optional[Sequence[Video]]:
|
|
3817
3783
|
"""Collect videos from input, session history, and current run response."""
|
|
3818
|
-
joint_videos = []
|
|
3784
|
+
joint_videos: List[Video] = []
|
|
3819
3785
|
|
|
3820
3786
|
# 1. Add videos from current input
|
|
3821
3787
|
if run_input and run_input.videos:
|
|
3822
|
-
|
|
3823
|
-
try:
|
|
3824
|
-
if artifact.url:
|
|
3825
|
-
joint_videos.append(Video(url=artifact.url))
|
|
3826
|
-
elif artifact.content:
|
|
3827
|
-
joint_videos.append(Video(content=artifact.content))
|
|
3828
|
-
except Exception as e:
|
|
3829
|
-
log_warning(f"Error converting VideoArtifact to Video: {e}")
|
|
3830
|
-
continue
|
|
3788
|
+
joint_videos.extend(run_input.videos)
|
|
3831
3789
|
log_debug(f"Added {len(run_input.videos)} input videos to joint list")
|
|
3832
3790
|
|
|
3833
3791
|
# 2. Add videos from session history (from both input and generated sources)
|
|
@@ -3836,30 +3794,14 @@ class Team:
|
|
|
3836
3794
|
for historical_run in session.runs:
|
|
3837
3795
|
# Add generated videos from previous runs
|
|
3838
3796
|
if historical_run.videos:
|
|
3839
|
-
|
|
3840
|
-
try:
|
|
3841
|
-
if artifact.url:
|
|
3842
|
-
joint_videos.append(Video(url=artifact.url))
|
|
3843
|
-
elif artifact.content:
|
|
3844
|
-
joint_videos.append(Video(content=artifact.content))
|
|
3845
|
-
except Exception as e:
|
|
3846
|
-
log_warning(f"Error converting historical VideoArtifact to Video: {e}")
|
|
3847
|
-
continue
|
|
3797
|
+
joint_videos.extend(historical_run.videos)
|
|
3848
3798
|
log_debug(
|
|
3849
3799
|
f"Added {len(historical_run.videos)} generated videos from historical run {historical_run.run_id}"
|
|
3850
3800
|
)
|
|
3851
3801
|
|
|
3852
3802
|
# Add input videos from previous runs
|
|
3853
3803
|
if historical_run.input and historical_run.input.videos:
|
|
3854
|
-
|
|
3855
|
-
try:
|
|
3856
|
-
if artifact.url:
|
|
3857
|
-
joint_videos.append(Video(url=artifact.url))
|
|
3858
|
-
elif artifact.content:
|
|
3859
|
-
joint_videos.append(Video(content=artifact.content))
|
|
3860
|
-
except Exception as e:
|
|
3861
|
-
log_warning(f"Error converting input VideoArtifact to Video: {e}")
|
|
3862
|
-
continue
|
|
3804
|
+
joint_videos.extend(historical_run.input.videos)
|
|
3863
3805
|
log_debug(
|
|
3864
3806
|
f"Added {len(historical_run.input.videos)} input videos from historical run {historical_run.run_id}"
|
|
3865
3807
|
)
|
|
@@ -3876,19 +3818,11 @@ class Team:
|
|
|
3876
3818
|
session: Optional[TeamSession] = None,
|
|
3877
3819
|
) -> Optional[Sequence[Audio]]:
|
|
3878
3820
|
"""Collect audios from input, session history, and current run response."""
|
|
3879
|
-
joint_audios = []
|
|
3821
|
+
joint_audios: List[Audio] = []
|
|
3880
3822
|
|
|
3881
3823
|
# 1. Add audios from current input
|
|
3882
3824
|
if run_input and run_input.audios:
|
|
3883
|
-
|
|
3884
|
-
try:
|
|
3885
|
-
if artifact.url:
|
|
3886
|
-
joint_audios.append(Audio(url=artifact.url))
|
|
3887
|
-
elif artifact.base64_audio:
|
|
3888
|
-
joint_audios.append(Audio(content=artifact.base64_audio))
|
|
3889
|
-
except Exception as e:
|
|
3890
|
-
log_warning(f"Error converting AudioArtifact to Audio: {e}")
|
|
3891
|
-
continue
|
|
3825
|
+
joint_audios.extend(run_input.audios)
|
|
3892
3826
|
log_debug(f"Added {len(run_input.audios)} input audios to joint list")
|
|
3893
3827
|
|
|
3894
3828
|
# 2. Add audios from session history (from both input and generated sources)
|
|
@@ -3897,30 +3831,14 @@ class Team:
|
|
|
3897
3831
|
for historical_run in session.runs:
|
|
3898
3832
|
# Add generated audios from previous runs
|
|
3899
3833
|
if historical_run.audio:
|
|
3900
|
-
|
|
3901
|
-
try:
|
|
3902
|
-
if artifact.url:
|
|
3903
|
-
joint_audios.append(Audio(url=artifact.url))
|
|
3904
|
-
elif artifact.base64_audio:
|
|
3905
|
-
joint_audios.append(Audio(content=artifact.base64_audio))
|
|
3906
|
-
except Exception as e:
|
|
3907
|
-
log_warning(f"Error converting historical AudioArtifact to Audio: {e}")
|
|
3908
|
-
continue
|
|
3834
|
+
joint_audios.extend(historical_run.audio)
|
|
3909
3835
|
log_debug(
|
|
3910
3836
|
f"Added {len(historical_run.audio)} generated audios from historical run {historical_run.run_id}"
|
|
3911
3837
|
)
|
|
3912
3838
|
|
|
3913
3839
|
# Add input audios from previous runs
|
|
3914
3840
|
if historical_run.input and historical_run.input.audios:
|
|
3915
|
-
|
|
3916
|
-
try:
|
|
3917
|
-
if artifact.url:
|
|
3918
|
-
joint_audios.append(Audio(url=artifact.url))
|
|
3919
|
-
elif artifact.base64_audio:
|
|
3920
|
-
joint_audios.append(Audio(content=artifact.base64_audio))
|
|
3921
|
-
except Exception as e:
|
|
3922
|
-
log_warning(f"Error converting input AudioArtifact to Audio: {e}")
|
|
3923
|
-
continue
|
|
3841
|
+
joint_audios.extend(historical_run.input.audios)
|
|
3924
3842
|
log_debug(
|
|
3925
3843
|
f"Added {len(historical_run.input.audios)} input audios from historical run {historical_run.run_id}"
|
|
3926
3844
|
)
|
|
@@ -5114,11 +5032,11 @@ class Team:
|
|
|
5114
5032
|
if self.share_member_interactions:
|
|
5115
5033
|
team_member_interactions_str = self._get_team_member_interactions_str(team_run_context=team_run_context) # type: ignore
|
|
5116
5034
|
if context_images := self._get_team_run_context_images(team_run_context=team_run_context): # type: ignore
|
|
5117
|
-
images.extend(
|
|
5035
|
+
images.extend(context_images)
|
|
5118
5036
|
if context_videos := self._get_team_run_context_videos(team_run_context=team_run_context): # type: ignore
|
|
5119
|
-
videos.extend(
|
|
5037
|
+
videos.extend(context_videos)
|
|
5120
5038
|
if context_audio := self._get_team_run_context_audio(team_run_context=team_run_context): # type: ignore
|
|
5121
|
-
audio.extend(
|
|
5039
|
+
audio.extend(context_audio)
|
|
5122
5040
|
return team_member_interactions_str
|
|
5123
5041
|
|
|
5124
5042
|
def _find_member_by_id(self, member_id: str) -> Optional[Tuple[int, Union[Agent, "Team"]]]:
|
|
@@ -6188,7 +6106,7 @@ class Team:
|
|
|
6188
6106
|
team_member_interactions_str += "</member interactions>\n"
|
|
6189
6107
|
return team_member_interactions_str
|
|
6190
6108
|
|
|
6191
|
-
def _get_team_run_context_images(self, team_run_context: Dict[str, Any]) -> List[
|
|
6109
|
+
def _get_team_run_context_images(self, team_run_context: Dict[str, Any]) -> List[Image]:
|
|
6192
6110
|
if not team_run_context:
|
|
6193
6111
|
return []
|
|
6194
6112
|
images = []
|
|
@@ -6198,7 +6116,7 @@ class Team:
|
|
|
6198
6116
|
images.extend(interaction["run_response"].images)
|
|
6199
6117
|
return images
|
|
6200
6118
|
|
|
6201
|
-
def _get_team_run_context_videos(self, team_run_context: Dict[str, Any]) -> List[
|
|
6119
|
+
def _get_team_run_context_videos(self, team_run_context: Dict[str, Any]) -> List[Video]:
|
|
6202
6120
|
if not team_run_context:
|
|
6203
6121
|
return []
|
|
6204
6122
|
videos = []
|
|
@@ -6208,7 +6126,7 @@ class Team:
|
|
|
6208
6126
|
videos.extend(interaction["run_response"].videos)
|
|
6209
6127
|
return videos
|
|
6210
6128
|
|
|
6211
|
-
def _get_team_run_context_audio(self, team_run_context: Dict[str, Any]) -> List[
|
|
6129
|
+
def _get_team_run_context_audio(self, team_run_context: Dict[str, Any]) -> List[Audio]:
|
|
6212
6130
|
if not team_run_context:
|
|
6213
6131
|
return []
|
|
6214
6132
|
audio = []
|
|
@@ -6222,21 +6140,21 @@ class Team:
|
|
|
6222
6140
|
# Handle images, videos and audio
|
|
6223
6141
|
###########################################################################
|
|
6224
6142
|
|
|
6225
|
-
def _add_image(self, image:
|
|
6143
|
+
def _add_image(self, image: Image, run_response: TeamRunOutput) -> None:
|
|
6226
6144
|
"""Add an image to both the agent's stateful storage and the current run response"""
|
|
6227
6145
|
# Add to run response
|
|
6228
6146
|
if run_response.images is None:
|
|
6229
6147
|
run_response.images = []
|
|
6230
6148
|
run_response.images.append(image)
|
|
6231
6149
|
|
|
6232
|
-
def _add_video(self, video:
|
|
6150
|
+
def _add_video(self, video: Video, run_response: TeamRunOutput) -> None:
|
|
6233
6151
|
"""Add a video to both the agent's stateful storage and the current run response"""
|
|
6234
6152
|
# Add to run response
|
|
6235
6153
|
if run_response.videos is None:
|
|
6236
6154
|
run_response.videos = []
|
|
6237
6155
|
run_response.videos.append(video)
|
|
6238
6156
|
|
|
6239
|
-
def _add_audio(self, audio:
|
|
6157
|
+
def _add_audio(self, audio: Audio, run_response: TeamRunOutput) -> None:
|
|
6240
6158
|
"""Add audio to both the agent's stateful storage and the current run response"""
|
|
6241
6159
|
# Add to run response
|
|
6242
6160
|
if run_response.audio is None:
|
agno/tools/brightdata.py
CHANGED
|
@@ -5,7 +5,7 @@ from typing import Any, Dict, List, Optional
|
|
|
5
5
|
from uuid import uuid4
|
|
6
6
|
|
|
7
7
|
from agno.agent import Agent
|
|
8
|
-
from agno.media import
|
|
8
|
+
from agno.media import Image
|
|
9
9
|
from agno.tools import Toolkit
|
|
10
10
|
from agno.tools.function import ToolResult
|
|
11
11
|
from agno.utils.log import log_debug, log_error, log_info
|
|
@@ -158,8 +158,8 @@ class BrightDataTools(Toolkit):
|
|
|
158
158
|
|
|
159
159
|
media_id = str(uuid4())
|
|
160
160
|
|
|
161
|
-
# Create
|
|
162
|
-
image_artifact =
|
|
161
|
+
# Create Image for the screenshot
|
|
162
|
+
image_artifact = Image(
|
|
163
163
|
id=media_id,
|
|
164
164
|
content=base64_encoded_image.encode("utf-8"),
|
|
165
165
|
mime_type="image/png",
|
agno/tools/cartesia.py
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import json
|
|
2
|
-
from base64 import b64encode
|
|
3
2
|
from os import getenv
|
|
4
3
|
from typing import Any, Dict, List, Optional, Union
|
|
5
4
|
from uuid import uuid4
|
|
6
5
|
|
|
7
6
|
from agno.agent import Agent
|
|
8
|
-
from agno.media import
|
|
7
|
+
from agno.media import Audio
|
|
9
8
|
from agno.team.team import Team
|
|
10
9
|
from agno.tools import Toolkit
|
|
11
10
|
from agno.tools.function import ToolResult
|
|
@@ -170,12 +169,11 @@ class CartesiaTools(Toolkit):
|
|
|
170
169
|
|
|
171
170
|
audio_iterator = self.client.tts.bytes(**params)
|
|
172
171
|
audio_data = b"".join(chunk for chunk in audio_iterator)
|
|
173
|
-
base64_audio = b64encode(audio_data).decode("utf-8")
|
|
174
172
|
|
|
175
173
|
# Create AudioArtifact
|
|
176
|
-
audio_artifact =
|
|
174
|
+
audio_artifact = Audio(
|
|
177
175
|
id=str(uuid4()),
|
|
178
|
-
|
|
176
|
+
content=audio_data,
|
|
179
177
|
mime_type=mime_type, # Hardcoded to audio/mpeg
|
|
180
178
|
)
|
|
181
179
|
|