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.
Files changed (51) hide show
  1. agno/agent/agent.py +78 -135
  2. agno/knowledge/knowledge.py +1 -1
  3. agno/knowledge/reranker/__init__.py +3 -0
  4. agno/media.py +269 -268
  5. agno/models/base.py +13 -48
  6. agno/models/google/gemini.py +11 -10
  7. agno/models/message.py +4 -4
  8. agno/models/ollama/chat.py +1 -1
  9. agno/models/openai/chat.py +33 -14
  10. agno/models/response.py +5 -5
  11. agno/os/app.py +8 -5
  12. agno/run/agent.py +28 -28
  13. agno/run/base.py +9 -19
  14. agno/run/team.py +24 -24
  15. agno/run/workflow.py +16 -16
  16. agno/team/team.py +72 -154
  17. agno/tools/brightdata.py +3 -3
  18. agno/tools/cartesia.py +3 -5
  19. agno/tools/dalle.py +7 -4
  20. agno/tools/desi_vocal.py +2 -2
  21. agno/tools/e2b.py +6 -6
  22. agno/tools/eleven_labs.py +3 -3
  23. agno/tools/fal.py +4 -4
  24. agno/tools/function.py +7 -7
  25. agno/tools/giphy.py +2 -2
  26. agno/tools/lumalab.py +3 -3
  27. agno/tools/models/azure_openai.py +2 -2
  28. agno/tools/models/gemini.py +3 -3
  29. agno/tools/models/groq.py +3 -5
  30. agno/tools/models/nebius.py +2 -2
  31. agno/tools/models_labs.py +5 -5
  32. agno/tools/openai.py +4 -9
  33. agno/tools/opencv.py +3 -3
  34. agno/tools/replicate.py +7 -7
  35. agno/utils/events.py +5 -5
  36. agno/utils/gemini.py +1 -1
  37. agno/utils/mcp.py +3 -3
  38. agno/utils/models/aws_claude.py +1 -1
  39. agno/utils/models/cohere.py +1 -1
  40. agno/utils/models/watsonx.py +1 -1
  41. agno/utils/openai.py +1 -1
  42. agno/vectordb/lancedb/lance_db.py +82 -25
  43. agno/workflow/step.py +7 -7
  44. agno/workflow/types.py +13 -13
  45. agno/workflow/workflow.py +28 -28
  46. {agno-2.0.0rc2.dist-info → agno-2.0.2.dist-info}/METADATA +140 -1
  47. {agno-2.0.0rc2.dist-info → agno-2.0.2.dist-info}/RECORD +50 -50
  48. agno-2.0.2.dist-info/licenses/LICENSE +201 -0
  49. agno-2.0.0rc2.dist-info/licenses/LICENSE +0 -375
  50. {agno-2.0.0rc2.dist-info → agno-2.0.2.dist-info}/WHEEL +0 -0
  51. {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 AudioArtifact, AudioResponse, File, ImageArtifact, VideoArtifact
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[AudioResponse] = None # Model audio response
102
- image: Optional[ImageArtifact] = None # Image attached to the response
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[ImageArtifact]] = None # Images attached to the response
124
- videos: Optional[List[VideoArtifact]] = None # Videos attached to the response
125
- audio: Optional[List[AudioArtifact]] = None # Audio attached to the response
126
- response_audio: Optional[AudioResponse] = None # Model audio response
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[ImageArtifact]] = None # Images produced by the tool call
194
- videos: Optional[List[VideoArtifact]] = None # Videos produced by the tool call
195
- audio: Optional[List[AudioArtifact]] = None # Audio produced by the tool call
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[ImageArtifact]] = None
293
- videos: Optional[Sequence[VideoArtifact]] = None
294
- audios: Optional[Sequence[AudioArtifact]] = None
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 = [ImageArtifact.model_validate(img_data) for img_data in data["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 = [VideoArtifact.model_validate(vid_data) for vid_data in data["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 = [AudioArtifact.model_validate(aud_data) for aud_data in data["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[ImageArtifact]] = None # Images from member runs
370
- videos: Optional[List[VideoArtifact]] = None # Videos from member runs
371
- audio: Optional[List[AudioArtifact]] = None # Audio from member runs
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[AudioResponse] = None # Model audio response
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 = [ImageArtifact.model_validate(image) for image in images] if images else None
542
+ images = [Image.model_validate(image) for image in images] if images else None
543
543
 
544
544
  videos = data.pop("videos", [])
545
- videos = [VideoArtifact.model_validate(video) for video in videos] if videos else None
545
+ videos = [Video.model_validate(video) for video in videos] if videos else None
546
546
 
547
547
  audio = data.pop("audio", [])
548
- audio = [AudioArtifact.model_validate(audio) for audio in audio] if audio else None
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 = AudioResponse.model_validate(response_audio) if response_audio else None
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 AudioArtifact, AudioResponse, ImageArtifact, VideoArtifact
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[ImageArtifact]] = None
186
- videos: Optional[List[VideoArtifact]] = None
187
- audio: Optional[List[AudioArtifact]] = None
188
- response_audio: Optional[AudioResponse] = None
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[ImageArtifact]]:
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[VideoArtifact]]:
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[AudioArtifact]]:
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[ImageArtifact]] = None
437
- videos: Optional[List[VideoArtifact]] = None
438
- audio: Optional[List[AudioArtifact]] = None
439
- response_audio: Optional[AudioResponse] = None
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 = [ImageArtifact.model_validate(image) for image in images] if images else None
557
+ images = [Image.model_validate(image) for image in images] if images else None
558
558
 
559
559
  videos = data.pop("videos", [])
560
- videos = [VideoArtifact.model_validate(video) for video in videos] if videos else None
560
+ videos = [Video.model_validate(video) for video in videos] if videos else None
561
561
 
562
562
  audio = data.pop("audio", [])
563
- audio = [AudioArtifact.model_validate(audio) for audio in audio] if audio else None
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 = AudioResponse.model_validate(response_audio) if response_audio else None
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, AudioArtifact, AudioResponse, File, Image, ImageArtifact, Video, VideoArtifact
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[ImageArtifact]] = None
549
+ self.images: Optional[List[Image]] = None
550
550
  # Audio generated during this session
551
- self.audio: Optional[List[AudioArtifact]] = None
551
+ self.audio: Optional[List[Audio]] = None
552
552
  # Videos generated during this session
553
- self.videos: Optional[List[VideoArtifact]] = None
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._convert_media_to_artifacts(
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._convert_media_to_artifacts(
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 = AudioResponse(id=str(uuid4()), content="", transcript="")
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
- full_model_response.audio.content += model_response_event.audio.content # type: ignore
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 _convert_media_to_artifacts(
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
- """Convert raw Image/Video/Audio objects to ImageArtifact/VideoArtifact/AudioArtifact objects."""
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
- image_artifacts = []
3042
+ image_list = []
3038
3043
  for img in images:
3039
- try:
3040
- artifact_id = img.id if hasattr(img, "id") and img.id else str(uuid4())
3044
+ if not img.id:
3045
+ from uuid import uuid4
3041
3046
 
3042
- if img.url:
3043
- image_artifacts.append(ImageArtifact(id=artifact_id, url=img.url))
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
- video_artifacts = None
3050
+ video_list = None
3051
3051
  if videos:
3052
- video_artifacts = []
3052
+ video_list = []
3053
3053
  for vid in videos:
3054
- try:
3055
- artifact_id = vid.id if hasattr(vid, "id") and vid.id else str(uuid4())
3054
+ if not vid.id:
3055
+ from uuid import uuid4
3056
3056
 
3057
- if vid.url:
3058
- video_artifacts.append(VideoArtifact(id=artifact_id, url=vid.url))
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
- audio_artifacts = None
3060
+ audio_list = None
3066
3061
  if audios:
3067
- audio_artifacts = []
3062
+ audio_list = []
3068
3063
  for aud in audios:
3069
- try:
3070
- artifact_id = aud.id if hasattr(aud, "id") and aud.id else str(uuid4())
3064
+ if not aud.id:
3065
+ from uuid import uuid4
3071
3066
 
3072
- if aud.url:
3073
- audio_artifacts.append(AudioArtifact(id=artifact_id, url=aud.url))
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 image_artifacts, video_artifacts, audio_artifacts
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
- for artifact in run_input.images:
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
- for artifact in historical_run.images:
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
- for artifact in historical_run.input.images:
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
- for artifact in run_input.videos:
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
- for artifact in historical_run.videos:
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
- for artifact in historical_run.input.videos:
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
- for artifact in run_input.audios:
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
- for artifact in historical_run.audio:
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
- for artifact in historical_run.input.audios:
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([Image.from_artifact(img) for img in context_images])
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([Video.from_artifact(vid) for vid in context_videos])
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([Audio.from_artifact(aud) for aud in context_audio])
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[ImageArtifact]:
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[VideoArtifact]:
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[AudioArtifact]:
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: ImageArtifact, run_response: TeamRunOutput) -> None:
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: VideoArtifact, run_response: TeamRunOutput) -> None:
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: AudioArtifact, run_response: TeamRunOutput) -> None:
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 ImageArtifact
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 ImageArtifact for the screenshot
162
- image_artifact = ImageArtifact(
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 AudioArtifact
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 = AudioArtifact(
174
+ audio_artifact = Audio(
177
175
  id=str(uuid4()),
178
- base64_audio=base64_audio,
176
+ content=audio_data,
179
177
  mime_type=mime_type, # Hardcoded to audio/mpeg
180
178
  )
181
179