agno 2.0.0rc2__py3-none-any.whl → 2.0.1__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 +9 -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.1.dist-info}/METADATA +140 -1
  47. {agno-2.0.0rc2.dist-info → agno-2.0.1.dist-info}/RECORD +50 -50
  48. agno-2.0.1.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.1.dist-info}/WHEEL +0 -0
  51. {agno-2.0.0rc2.dist-info → agno-2.0.1.dist-info}/top_level.txt +0 -0
agno/agent/agent.py CHANGED
@@ -30,7 +30,7 @@ from pydantic import BaseModel
30
30
  from agno.db.base import BaseDb, SessionType, UserMemory
31
31
  from agno.exceptions import ModelProviderError, RunCancelledException, StopAgentRun
32
32
  from agno.knowledge.knowledge import Knowledge
33
- from agno.media import Audio, AudioArtifact, AudioResponse, File, Image, ImageArtifact, Video, VideoArtifact
33
+ from agno.media import Audio, File, Image, Video
34
34
  from agno.memory import MemoryManager
35
35
  from agno.models.base import Model
36
36
  from agno.models.message import Message, MessageReferences
@@ -1078,7 +1078,7 @@ class Agent:
1078
1078
  # Initialize the Agent
1079
1079
  self.initialize_agent(debug_mode=debug_mode)
1080
1080
 
1081
- image_artifacts, video_artifacts, audio_artifacts = self._convert_media_to_artifacts(
1081
+ image_artifacts, video_artifacts, audio_artifacts = self._validate_media_object_id(
1082
1082
  images=images, videos=videos, audios=audio
1083
1083
  )
1084
1084
 
@@ -1647,7 +1647,7 @@ class Agent:
1647
1647
  # Initialize the Agent
1648
1648
  self.initialize_agent(debug_mode=debug_mode)
1649
1649
 
1650
- image_artifacts, video_artifacts, audio_artifacts = self._convert_media_to_artifacts(
1650
+ image_artifacts, video_artifacts, audio_artifacts = self._validate_media_object_id(
1651
1651
  images=images, videos=videos, audios=audio
1652
1652
  )
1653
1653
 
@@ -3320,23 +3320,47 @@ class Agent:
3320
3320
  # Process audio
3321
3321
  if model_response_event.audio is not None:
3322
3322
  if model_response.audio is None:
3323
- model_response.audio = AudioResponse(id=str(uuid4()), content="", transcript="")
3323
+ model_response.audio = Audio(id=str(uuid4()), content=b"", transcript="")
3324
3324
 
3325
3325
  if model_response_event.audio.id is not None:
3326
3326
  model_response.audio.id = model_response_event.audio.id # type: ignore
3327
+
3327
3328
  if model_response_event.audio.content is not None:
3328
- model_response.audio.content += model_response_event.audio.content # type: ignore
3329
+ # Handle both base64 string and bytes content
3330
+ if isinstance(model_response_event.audio.content, str):
3331
+ # Decode base64 string to bytes
3332
+ try:
3333
+ import base64
3334
+
3335
+ decoded_content = base64.b64decode(model_response_event.audio.content)
3336
+ if model_response.audio.content is None:
3337
+ model_response.audio.content = b""
3338
+ model_response.audio.content += decoded_content
3339
+ except Exception:
3340
+ # If decode fails, encode string as bytes
3341
+ if model_response.audio.content is None:
3342
+ model_response.audio.content = b""
3343
+ model_response.audio.content += model_response_event.audio.content.encode("utf-8")
3344
+ elif isinstance(model_response_event.audio.content, bytes):
3345
+ # Content is already bytes
3346
+ if model_response.audio.content is None:
3347
+ model_response.audio.content = b""
3348
+ model_response.audio.content += model_response_event.audio.content
3349
+
3329
3350
  if model_response_event.audio.transcript is not None:
3330
3351
  model_response.audio.transcript += model_response_event.audio.transcript # type: ignore
3352
+
3331
3353
  if model_response_event.audio.expires_at is not None:
3332
3354
  model_response.audio.expires_at = model_response_event.audio.expires_at # type: ignore
3333
3355
  if model_response_event.audio.mime_type is not None:
3334
3356
  model_response.audio.mime_type = model_response_event.audio.mime_type # type: ignore
3335
- model_response.audio.sample_rate = model_response_event.audio.sample_rate
3336
- model_response.audio.channels = model_response_event.audio.channels
3357
+ if model_response_event.audio.sample_rate is not None:
3358
+ model_response.audio.sample_rate = model_response_event.audio.sample_rate
3359
+ if model_response_event.audio.channels is not None:
3360
+ model_response.audio.channels = model_response_event.audio.channels
3337
3361
 
3338
3362
  # Yield the audio and transcript bit by bit
3339
- run_response.response_audio = AudioResponse(
3363
+ run_response.response_audio = Audio(
3340
3364
  id=model_response_event.audio.id,
3341
3365
  content=model_response_event.audio.content,
3342
3366
  transcript=model_response_event.audio.transcript,
@@ -3364,6 +3388,14 @@ class Agent:
3364
3388
  workflow_context=workflow_context,
3365
3389
  )
3366
3390
 
3391
+ if model_response.images is None:
3392
+ model_response.images = []
3393
+ model_response.images.extend(model_response_event.images)
3394
+ # Store media in run_response if store_media is enabled
3395
+ if self.store_media:
3396
+ for image in model_response_event.images:
3397
+ self._add_image(image, run_response)
3398
+
3367
3399
  # Handle tool interruption events
3368
3400
  elif model_response_event.event == ModelResponseEvent.tool_call_paused.value:
3369
3401
  # Add tool calls to the run_response
@@ -3762,19 +3794,11 @@ class Agent:
3762
3794
  session: Optional[AgentSession] = None,
3763
3795
  ) -> Optional[Sequence[Image]]:
3764
3796
  """Collect images from input, session history, and current run response."""
3765
- joint_images = []
3797
+ joint_images: List[Image] = []
3766
3798
 
3767
3799
  # 1. Add images from current input
3768
3800
  if run_input and run_input.images:
3769
- for artifact in run_input.images:
3770
- try:
3771
- if artifact.url:
3772
- joint_images.append(Image(url=artifact.url))
3773
- elif artifact.content:
3774
- joint_images.append(Image(content=artifact.content))
3775
- except Exception as e:
3776
- log_warning(f"Error converting ImageArtifact to Image: {e}")
3777
- continue
3801
+ joint_images.extend(run_input.images)
3778
3802
  log_debug(f"Added {len(run_input.images)} input images to joint list")
3779
3803
 
3780
3804
  # 2. Add images from session history (from both input and generated sources)
@@ -3783,30 +3807,14 @@ class Agent:
3783
3807
  for historical_run in session.runs:
3784
3808
  # Add generated images from previous runs
3785
3809
  if historical_run.images:
3786
- for artifact in historical_run.images:
3787
- try:
3788
- if artifact.url:
3789
- joint_images.append(Image(url=artifact.url))
3790
- elif artifact.content:
3791
- joint_images.append(Image(content=artifact.content))
3792
- except Exception as e:
3793
- log_warning(f"Error converting historical ImageArtifact to Image: {e}")
3794
- continue
3810
+ joint_images.extend(historical_run.images)
3795
3811
  log_debug(
3796
3812
  f"Added {len(historical_run.images)} generated images from historical run {historical_run.run_id}"
3797
3813
  )
3798
3814
 
3799
3815
  # Add input images from previous runs
3800
3816
  if historical_run.input and historical_run.input.images:
3801
- for artifact in historical_run.input.images:
3802
- try:
3803
- if artifact.url:
3804
- joint_images.append(Image(url=artifact.url))
3805
- elif artifact.content:
3806
- joint_images.append(Image(content=artifact.content))
3807
- except Exception as e:
3808
- log_warning(f"Error converting input ImageArtifact to Image: {e}")
3809
- continue
3817
+ joint_images.extend(historical_run.input.images)
3810
3818
  log_debug(
3811
3819
  f"Added {len(historical_run.input.images)} input images from historical run {historical_run.run_id}"
3812
3820
  )
@@ -3823,19 +3831,11 @@ class Agent:
3823
3831
  session: Optional[AgentSession] = None,
3824
3832
  ) -> Optional[Sequence[Video]]:
3825
3833
  """Collect videos from input, session history, and current run response."""
3826
- joint_videos = []
3834
+ joint_videos: List[Video] = []
3827
3835
 
3828
3836
  # 1. Add videos from current input
3829
3837
  if run_input and run_input.videos:
3830
- for artifact in run_input.videos:
3831
- try:
3832
- if artifact.url:
3833
- joint_videos.append(Video(url=artifact.url))
3834
- elif artifact.content:
3835
- joint_videos.append(Video(content=artifact.content))
3836
- except Exception as e:
3837
- log_warning(f"Error converting VideoArtifact to Video: {e}")
3838
- continue
3838
+ joint_videos.extend(run_input.videos)
3839
3839
  log_debug(f"Added {len(run_input.videos)} input videos to joint list")
3840
3840
 
3841
3841
  # 2. Add videos from session history (from both input and generated sources)
@@ -3844,30 +3844,14 @@ class Agent:
3844
3844
  for historical_run in session.runs:
3845
3845
  # Add generated videos from previous runs
3846
3846
  if historical_run.videos:
3847
- for artifact in historical_run.videos:
3848
- try:
3849
- if artifact.url:
3850
- joint_videos.append(Video(url=artifact.url))
3851
- elif artifact.content:
3852
- joint_videos.append(Video(content=artifact.content))
3853
- except Exception as e:
3854
- log_warning(f"Error converting historical VideoArtifact to Video: {e}")
3855
- continue
3847
+ joint_videos.extend(historical_run.videos)
3856
3848
  log_debug(
3857
3849
  f"Added {len(historical_run.videos)} generated videos from historical run {historical_run.run_id}"
3858
3850
  )
3859
3851
 
3860
3852
  # Add input videos from previous runs
3861
3853
  if historical_run.input and historical_run.input.videos:
3862
- for artifact in historical_run.input.videos:
3863
- try:
3864
- if artifact.url:
3865
- joint_videos.append(Video(url=artifact.url))
3866
- elif artifact.content:
3867
- joint_videos.append(Video(content=artifact.content))
3868
- except Exception as e:
3869
- log_warning(f"Error converting input VideoArtifact to Video: {e}")
3870
- continue
3854
+ joint_videos.extend(historical_run.input.videos)
3871
3855
  log_debug(
3872
3856
  f"Added {len(historical_run.input.videos)} input videos from historical run {historical_run.run_id}"
3873
3857
  )
@@ -3884,19 +3868,11 @@ class Agent:
3884
3868
  session: Optional[AgentSession] = None,
3885
3869
  ) -> Optional[Sequence[Audio]]:
3886
3870
  """Collect audios from input, session history, and current run response."""
3887
- joint_audios = []
3871
+ joint_audios: List[Audio] = []
3888
3872
 
3889
3873
  # 1. Add audios from current input
3890
3874
  if run_input and run_input.audios:
3891
- for artifact in run_input.audios:
3892
- try:
3893
- if artifact.url:
3894
- joint_audios.append(Audio(url=artifact.url))
3895
- elif artifact.base64_audio:
3896
- joint_audios.append(Audio(content=artifact.base64_audio))
3897
- except Exception as e:
3898
- log_warning(f"Error converting AudioArtifact to Audio: {e}")
3899
- continue
3875
+ joint_audios.extend(run_input.audios)
3900
3876
  log_debug(f"Added {len(run_input.audios)} input audios to joint list")
3901
3877
 
3902
3878
  # 2. Add audios from session history (from both input and generated sources)
@@ -3905,30 +3881,14 @@ class Agent:
3905
3881
  for historical_run in session.runs:
3906
3882
  # Add generated audios from previous runs
3907
3883
  if historical_run.audio:
3908
- for artifact in historical_run.audio:
3909
- try:
3910
- if artifact.url:
3911
- joint_audios.append(Audio(url=artifact.url))
3912
- elif artifact.base64_audio:
3913
- joint_audios.append(Audio(content=artifact.base64_audio))
3914
- except Exception as e:
3915
- log_warning(f"Error converting historical AudioArtifact to Audio: {e}")
3916
- continue
3884
+ joint_audios.extend(historical_run.audio)
3917
3885
  log_debug(
3918
3886
  f"Added {len(historical_run.audio)} generated audios from historical run {historical_run.run_id}"
3919
3887
  )
3920
3888
 
3921
3889
  # Add input audios from previous runs
3922
3890
  if historical_run.input and historical_run.input.audios:
3923
- for artifact in historical_run.input.audios:
3924
- try:
3925
- if artifact.url:
3926
- joint_audios.append(Audio(url=artifact.url))
3927
- elif artifact.base64_audio:
3928
- joint_audios.append(Audio(content=artifact.base64_audio))
3929
- except Exception as e:
3930
- log_warning(f"Error converting input AudioArtifact to Audio: {e}")
3931
- continue
3891
+ joint_audios.extend(historical_run.input.audios)
3932
3892
  log_debug(
3933
3893
  f"Added {len(historical_run.input.audios)} input audios from historical run {historical_run.run_id}"
3934
3894
  )
@@ -5669,21 +5629,21 @@ class Agent:
5669
5629
  # Handle images, videos and audio
5670
5630
  ###########################################################################
5671
5631
 
5672
- def _add_image(self, image: ImageArtifact, run_response: RunOutput) -> None:
5632
+ def _add_image(self, image: Image, run_response: RunOutput) -> None:
5673
5633
  """Add an image to both the agent's stateful storage and the current run response"""
5674
5634
  # Add to run response
5675
5635
  if run_response.images is None:
5676
5636
  run_response.images = []
5677
5637
  run_response.images.append(image)
5678
5638
 
5679
- def _add_video(self, video: VideoArtifact, run_response: RunOutput) -> None:
5639
+ def _add_video(self, video: Video, run_response: RunOutput) -> None:
5680
5640
  """Add a video to both the agent's stateful storage and the current run response"""
5681
5641
  # Add to run response
5682
5642
  if run_response.videos is None:
5683
5643
  run_response.videos = []
5684
5644
  run_response.videos.append(video)
5685
5645
 
5686
- def _add_audio(self, audio: AudioArtifact, run_response: RunOutput) -> None:
5646
+ def _add_audio(self, audio: Audio, run_response: RunOutput) -> None:
5687
5647
  """Add audio to both the agent's stateful storage and the current run response"""
5688
5648
  # Add to run response
5689
5649
  if run_response.audio is None:
@@ -7168,63 +7128,46 @@ class Agent:
7168
7128
  message.image_output = None
7169
7129
  message.video_output = None
7170
7130
 
7171
- def _convert_media_to_artifacts(
7131
+ def _validate_media_object_id(
7172
7132
  self,
7173
7133
  images: Optional[Sequence[Image]] = None,
7174
7134
  videos: Optional[Sequence[Video]] = None,
7175
7135
  audios: Optional[Sequence[Audio]] = None,
7176
7136
  ) -> tuple:
7177
- """Convert raw Image/Video/Audio objects to ImageArtifact/VideoArtifact/AudioArtifact objects."""
7178
- from uuid import uuid4
7179
-
7180
- from agno.media import AudioArtifact, ImageArtifact, VideoArtifact
7181
-
7182
- image_artifacts = None
7137
+ """Convert raw Image/Video/Audio objects - now unified, so just return as-is."""
7138
+ # With unified classes, no conversion needed - just ensure IDs are set
7139
+ image_list = None
7183
7140
  if images:
7184
- image_artifacts = []
7141
+ image_list = []
7185
7142
  for img in images:
7186
- try:
7187
- artifact_id = img.id if hasattr(img, "id") and img.id else str(uuid4())
7143
+ # Ensure ID is set (validation should handle this, but double-check)
7144
+ if not img.id:
7145
+ from uuid import uuid4
7188
7146
 
7189
- if img.url:
7190
- image_artifacts.append(ImageArtifact(id=artifact_id, url=img.url))
7191
- elif img.content:
7192
- image_artifacts.append(ImageArtifact(id=artifact_id, content=img.content))
7193
- except Exception as e:
7194
- log_warning(f"Error creating ImageArtifact: {e}")
7195
- continue
7147
+ img.id = str(uuid4())
7148
+ image_list.append(img)
7196
7149
 
7197
- video_artifacts = None
7150
+ video_list = None
7198
7151
  if videos:
7199
- video_artifacts = []
7152
+ video_list = []
7200
7153
  for vid in videos:
7201
- try:
7202
- artifact_id = vid.id if hasattr(vid, "id") and vid.id else str(uuid4())
7154
+ if not vid.id:
7155
+ from uuid import uuid4
7203
7156
 
7204
- if vid.url:
7205
- video_artifacts.append(VideoArtifact(id=artifact_id, url=vid.url))
7206
- elif vid.content:
7207
- video_artifacts.append(VideoArtifact(id=artifact_id, content=vid.content))
7208
- except Exception as e:
7209
- log_warning(f"Error creating VideoArtifact: {e}")
7210
- continue
7157
+ vid.id = str(uuid4())
7158
+ video_list.append(vid)
7211
7159
 
7212
- audio_artifacts = None
7160
+ audio_list = None
7213
7161
  if audios:
7214
- audio_artifacts = []
7162
+ audio_list = []
7215
7163
  for aud in audios:
7216
- try:
7217
- artifact_id = aud.id if hasattr(aud, "id") and aud.id else str(uuid4())
7164
+ if not aud.id:
7165
+ from uuid import uuid4
7218
7166
 
7219
- if aud.url:
7220
- audio_artifacts.append(AudioArtifact(id=artifact_id, url=aud.url))
7221
- elif aud.content:
7222
- audio_artifacts.append(AudioArtifact(id=artifact_id, content=aud.content))
7223
- except Exception as e:
7224
- log_warning(f"Error creating AudioArtifact: {e}")
7225
- continue
7167
+ aud.id = str(uuid4())
7168
+ audio_list.append(aud)
7226
7169
 
7227
- return image_artifacts, video_artifacts, audio_artifacts
7170
+ return image_list, video_list, audio_list
7228
7171
 
7229
7172
  def cli_app(
7230
7173
  self,
@@ -474,7 +474,7 @@ class Knowledge:
474
474
  # 4. Select reader
475
475
  # If a reader was provided by the user, use it
476
476
  reader = content.reader
477
- name = content.name
477
+ name = content.name if content.name else content.url
478
478
  # Else select based on file extension
479
479
  if reader is None:
480
480
  url_path = Path(parsed_url.path)
@@ -0,0 +1,9 @@
1
+ from agno.knowledge.reranker.cohere import CohereReranker
2
+ from agno.knowledge.reranker.infinity import InfinityReranker
3
+ from agno.knowledge.reranker.sentence_transformer import SentenceTransformerReranker
4
+
5
+ __all__ = [
6
+ "CohereReranker",
7
+ "InfinityReranker",
8
+ "SentenceTransformerReranker",
9
+ ]