agno 2.0.0rc1__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 (85) hide show
  1. agno/agent/agent.py +101 -140
  2. agno/db/mongo/mongo.py +8 -3
  3. agno/eval/accuracy.py +12 -5
  4. agno/knowledge/chunking/strategy.py +14 -14
  5. agno/knowledge/knowledge.py +156 -120
  6. agno/knowledge/reader/arxiv_reader.py +5 -5
  7. agno/knowledge/reader/csv_reader.py +6 -77
  8. agno/knowledge/reader/docx_reader.py +5 -5
  9. agno/knowledge/reader/firecrawl_reader.py +5 -5
  10. agno/knowledge/reader/json_reader.py +5 -5
  11. agno/knowledge/reader/markdown_reader.py +31 -9
  12. agno/knowledge/reader/pdf_reader.py +10 -123
  13. agno/knowledge/reader/reader_factory.py +65 -72
  14. agno/knowledge/reader/s3_reader.py +44 -114
  15. agno/knowledge/reader/text_reader.py +5 -5
  16. agno/knowledge/reader/url_reader.py +75 -31
  17. agno/knowledge/reader/web_search_reader.py +6 -29
  18. agno/knowledge/reader/website_reader.py +5 -5
  19. agno/knowledge/reader/wikipedia_reader.py +5 -5
  20. agno/knowledge/reader/youtube_reader.py +6 -6
  21. agno/knowledge/reranker/__init__.py +9 -0
  22. agno/knowledge/utils.py +10 -10
  23. agno/media.py +269 -268
  24. agno/models/aws/bedrock.py +3 -7
  25. agno/models/base.py +50 -54
  26. agno/models/google/gemini.py +11 -10
  27. agno/models/message.py +4 -4
  28. agno/models/ollama/chat.py +1 -1
  29. agno/models/openai/chat.py +33 -14
  30. agno/models/response.py +5 -5
  31. agno/os/app.py +40 -29
  32. agno/os/mcp.py +39 -59
  33. agno/os/router.py +547 -16
  34. agno/os/routers/evals/evals.py +197 -12
  35. agno/os/routers/knowledge/knowledge.py +428 -14
  36. agno/os/routers/memory/memory.py +250 -28
  37. agno/os/routers/metrics/metrics.py +125 -7
  38. agno/os/routers/session/session.py +393 -25
  39. agno/os/schema.py +55 -2
  40. agno/run/agent.py +37 -28
  41. agno/run/base.py +9 -19
  42. agno/run/team.py +110 -19
  43. agno/run/workflow.py +41 -28
  44. agno/team/team.py +808 -1080
  45. agno/tools/brightdata.py +3 -3
  46. agno/tools/cartesia.py +3 -5
  47. agno/tools/dalle.py +7 -4
  48. agno/tools/desi_vocal.py +2 -2
  49. agno/tools/e2b.py +6 -6
  50. agno/tools/eleven_labs.py +3 -3
  51. agno/tools/fal.py +4 -4
  52. agno/tools/function.py +7 -7
  53. agno/tools/giphy.py +2 -2
  54. agno/tools/lumalab.py +3 -3
  55. agno/tools/mcp.py +1 -2
  56. agno/tools/models/azure_openai.py +2 -2
  57. agno/tools/models/gemini.py +3 -3
  58. agno/tools/models/groq.py +3 -5
  59. agno/tools/models/nebius.py +2 -2
  60. agno/tools/models_labs.py +5 -5
  61. agno/tools/openai.py +4 -9
  62. agno/tools/opencv.py +3 -3
  63. agno/tools/replicate.py +7 -7
  64. agno/utils/events.py +5 -5
  65. agno/utils/gemini.py +1 -1
  66. agno/utils/log.py +52 -2
  67. agno/utils/mcp.py +57 -5
  68. agno/utils/models/aws_claude.py +1 -1
  69. agno/utils/models/claude.py +0 -8
  70. agno/utils/models/cohere.py +1 -1
  71. agno/utils/models/watsonx.py +1 -1
  72. agno/utils/openai.py +1 -1
  73. agno/utils/print_response/team.py +177 -73
  74. agno/utils/streamlit.py +27 -0
  75. agno/vectordb/lancedb/lance_db.py +82 -25
  76. agno/workflow/step.py +7 -7
  77. agno/workflow/types.py +13 -13
  78. agno/workflow/workflow.py +37 -28
  79. {agno-2.0.0rc1.dist-info → agno-2.0.1.dist-info}/METADATA +140 -1
  80. {agno-2.0.0rc1.dist-info → agno-2.0.1.dist-info}/RECORD +83 -84
  81. agno-2.0.1.dist-info/licenses/LICENSE +201 -0
  82. agno/knowledge/reader/gcs_reader.py +0 -67
  83. agno-2.0.0rc1.dist-info/licenses/LICENSE +0 -375
  84. {agno-2.0.0rc1.dist-info → agno-2.0.1.dist-info}/WHEEL +0 -0
  85. {agno-2.0.0rc1.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
@@ -129,10 +129,10 @@ class Agent:
129
129
  session_id: Optional[str] = None
130
130
  # Default session state (stored in the database to persist across runs)
131
131
  session_state: Optional[Dict[str, Any]] = None
132
- # If True, the agent can update the session state
133
- enable_agentic_state: bool = False
134
- # If True, add the session state to the user prompt
132
+ # Set to True to add the session_state to the context
135
133
  add_session_state_to_context: bool = False
134
+ # Set to True to give the agent tools to update the session_state dynamically
135
+ enable_agentic_state: bool = False
136
136
  # If True, cache the current Agent session in memory for faster access
137
137
  cache_session: bool = False
138
138
 
@@ -321,8 +321,6 @@ class Agent:
321
321
  # --- If this Agent is part of a workflow ---
322
322
  # Optional workflow ID. Indicates this agent is part of a workflow.
323
323
  workflow_id: Optional[str] = None
324
- # Set when this agent is part of a workflow.
325
- workflow_session_id: Optional[str] = None
326
324
 
327
325
  # Metadata stored with this agent
328
326
  metadata: Optional[Dict[str, Any]] = None
@@ -345,7 +343,6 @@ class Agent:
345
343
  id: Optional[str] = None,
346
344
  introduction: Optional[str] = None,
347
345
  user_id: Optional[str] = None,
348
- app_id: Optional[str] = None,
349
346
  session_id: Optional[str] = None,
350
347
  session_state: Optional[Dict[str, Any]] = None,
351
348
  add_session_state_to_context: bool = False,
@@ -429,7 +426,6 @@ class Agent:
429
426
  self.id = id
430
427
  self.introduction = introduction
431
428
  self.user_id = user_id
432
- self.app_id = app_id
433
429
 
434
430
  self.session_id = session_id
435
431
  self.session_state = session_state
@@ -593,6 +589,15 @@ class Agent:
593
589
  if isinstance(input, Message):
594
590
  input = input.content # type: ignore
595
591
 
592
+ # If input is a string, convert it to a dict
593
+ if isinstance(input, str):
594
+ import json
595
+
596
+ try:
597
+ input = json.loads(input)
598
+ except Exception as e:
599
+ raise ValueError(f"Failed to parse input. Is it a valid JSON string?: {e}")
600
+
596
601
  # Case 1: Message is already a BaseModel instance
597
602
  if isinstance(input, BaseModel):
598
603
  if isinstance(input, self.input_schema):
@@ -1073,7 +1078,7 @@ class Agent:
1073
1078
  # Initialize the Agent
1074
1079
  self.initialize_agent(debug_mode=debug_mode)
1075
1080
 
1076
- image_artifacts, video_artifacts, audio_artifacts = self._convert_media_to_artifacts(
1081
+ image_artifacts, video_artifacts, audio_artifacts = self._validate_media_object_id(
1077
1082
  images=images, videos=videos, audios=audio
1078
1083
  )
1079
1084
 
@@ -1642,7 +1647,7 @@ class Agent:
1642
1647
  # Initialize the Agent
1643
1648
  self.initialize_agent(debug_mode=debug_mode)
1644
1649
 
1645
- image_artifacts, video_artifacts, audio_artifacts = self._convert_media_to_artifacts(
1650
+ image_artifacts, video_artifacts, audio_artifacts = self._validate_media_object_id(
1646
1651
  images=images, videos=videos, audios=audio
1647
1652
  )
1648
1653
 
@@ -3231,6 +3236,12 @@ class Agent:
3231
3236
  if isinstance(model_response_event, tuple(get_args(RunOutputEvent))) or isinstance(
3232
3237
  model_response_event, tuple(get_args(TeamRunOutputEvent))
3233
3238
  ):
3239
+ if model_response_event.event == RunEvent.custom_event: # type: ignore
3240
+ model_response_event.agent_id = self.id # type: ignore
3241
+ model_response_event.agent_name = self.name # type: ignore
3242
+ model_response_event.session_id = session.session_id # type: ignore
3243
+ model_response_event.run_id = run_response.run_id # type: ignore
3244
+
3234
3245
  # We just bubble the event up
3235
3246
  yield self._handle_event(model_response_event, run_response) # type: ignore
3236
3247
  else:
@@ -3309,23 +3320,47 @@ class Agent:
3309
3320
  # Process audio
3310
3321
  if model_response_event.audio is not None:
3311
3322
  if model_response.audio is None:
3312
- model_response.audio = AudioResponse(id=str(uuid4()), content="", transcript="")
3323
+ model_response.audio = Audio(id=str(uuid4()), content=b"", transcript="")
3313
3324
 
3314
3325
  if model_response_event.audio.id is not None:
3315
3326
  model_response.audio.id = model_response_event.audio.id # type: ignore
3327
+
3316
3328
  if model_response_event.audio.content is not None:
3317
- 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
+
3318
3350
  if model_response_event.audio.transcript is not None:
3319
3351
  model_response.audio.transcript += model_response_event.audio.transcript # type: ignore
3352
+
3320
3353
  if model_response_event.audio.expires_at is not None:
3321
3354
  model_response.audio.expires_at = model_response_event.audio.expires_at # type: ignore
3322
3355
  if model_response_event.audio.mime_type is not None:
3323
3356
  model_response.audio.mime_type = model_response_event.audio.mime_type # type: ignore
3324
- model_response.audio.sample_rate = model_response_event.audio.sample_rate
3325
- 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
3326
3361
 
3327
3362
  # Yield the audio and transcript bit by bit
3328
- run_response.response_audio = AudioResponse(
3363
+ run_response.response_audio = Audio(
3329
3364
  id=model_response_event.audio.id,
3330
3365
  content=model_response_event.audio.content,
3331
3366
  transcript=model_response_event.audio.transcript,
@@ -3353,6 +3388,14 @@ class Agent:
3353
3388
  workflow_context=workflow_context,
3354
3389
  )
3355
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
+
3356
3399
  # Handle tool interruption events
3357
3400
  elif model_response_event.event == ModelResponseEvent.tool_call_paused.value:
3358
3401
  # Add tool calls to the run_response
@@ -3751,19 +3794,11 @@ class Agent:
3751
3794
  session: Optional[AgentSession] = None,
3752
3795
  ) -> Optional[Sequence[Image]]:
3753
3796
  """Collect images from input, session history, and current run response."""
3754
- joint_images = []
3797
+ joint_images: List[Image] = []
3755
3798
 
3756
3799
  # 1. Add images from current input
3757
3800
  if run_input and run_input.images:
3758
- for artifact in run_input.images:
3759
- try:
3760
- if artifact.url:
3761
- joint_images.append(Image(url=artifact.url))
3762
- elif artifact.content:
3763
- joint_images.append(Image(content=artifact.content))
3764
- except Exception as e:
3765
- log_warning(f"Error converting ImageArtifact to Image: {e}")
3766
- continue
3801
+ joint_images.extend(run_input.images)
3767
3802
  log_debug(f"Added {len(run_input.images)} input images to joint list")
3768
3803
 
3769
3804
  # 2. Add images from session history (from both input and generated sources)
@@ -3772,30 +3807,14 @@ class Agent:
3772
3807
  for historical_run in session.runs:
3773
3808
  # Add generated images from previous runs
3774
3809
  if historical_run.images:
3775
- for artifact in historical_run.images:
3776
- try:
3777
- if artifact.url:
3778
- joint_images.append(Image(url=artifact.url))
3779
- elif artifact.content:
3780
- joint_images.append(Image(content=artifact.content))
3781
- except Exception as e:
3782
- log_warning(f"Error converting historical ImageArtifact to Image: {e}")
3783
- continue
3810
+ joint_images.extend(historical_run.images)
3784
3811
  log_debug(
3785
3812
  f"Added {len(historical_run.images)} generated images from historical run {historical_run.run_id}"
3786
3813
  )
3787
3814
 
3788
3815
  # Add input images from previous runs
3789
3816
  if historical_run.input and historical_run.input.images:
3790
- for artifact in historical_run.input.images:
3791
- try:
3792
- if artifact.url:
3793
- joint_images.append(Image(url=artifact.url))
3794
- elif artifact.content:
3795
- joint_images.append(Image(content=artifact.content))
3796
- except Exception as e:
3797
- log_warning(f"Error converting input ImageArtifact to Image: {e}")
3798
- continue
3817
+ joint_images.extend(historical_run.input.images)
3799
3818
  log_debug(
3800
3819
  f"Added {len(historical_run.input.images)} input images from historical run {historical_run.run_id}"
3801
3820
  )
@@ -3812,19 +3831,11 @@ class Agent:
3812
3831
  session: Optional[AgentSession] = None,
3813
3832
  ) -> Optional[Sequence[Video]]:
3814
3833
  """Collect videos from input, session history, and current run response."""
3815
- joint_videos = []
3834
+ joint_videos: List[Video] = []
3816
3835
 
3817
3836
  # 1. Add videos from current input
3818
3837
  if run_input and run_input.videos:
3819
- for artifact in run_input.videos:
3820
- try:
3821
- if artifact.url:
3822
- joint_videos.append(Video(url=artifact.url))
3823
- elif artifact.content:
3824
- joint_videos.append(Video(content=artifact.content))
3825
- except Exception as e:
3826
- log_warning(f"Error converting VideoArtifact to Video: {e}")
3827
- continue
3838
+ joint_videos.extend(run_input.videos)
3828
3839
  log_debug(f"Added {len(run_input.videos)} input videos to joint list")
3829
3840
 
3830
3841
  # 2. Add videos from session history (from both input and generated sources)
@@ -3833,30 +3844,14 @@ class Agent:
3833
3844
  for historical_run in session.runs:
3834
3845
  # Add generated videos from previous runs
3835
3846
  if historical_run.videos:
3836
- for artifact in historical_run.videos:
3837
- try:
3838
- if artifact.url:
3839
- joint_videos.append(Video(url=artifact.url))
3840
- elif artifact.content:
3841
- joint_videos.append(Video(content=artifact.content))
3842
- except Exception as e:
3843
- log_warning(f"Error converting historical VideoArtifact to Video: {e}")
3844
- continue
3847
+ joint_videos.extend(historical_run.videos)
3845
3848
  log_debug(
3846
3849
  f"Added {len(historical_run.videos)} generated videos from historical run {historical_run.run_id}"
3847
3850
  )
3848
3851
 
3849
3852
  # Add input videos from previous runs
3850
3853
  if historical_run.input and historical_run.input.videos:
3851
- for artifact in historical_run.input.videos:
3852
- try:
3853
- if artifact.url:
3854
- joint_videos.append(Video(url=artifact.url))
3855
- elif artifact.content:
3856
- joint_videos.append(Video(content=artifact.content))
3857
- except Exception as e:
3858
- log_warning(f"Error converting input VideoArtifact to Video: {e}")
3859
- continue
3854
+ joint_videos.extend(historical_run.input.videos)
3860
3855
  log_debug(
3861
3856
  f"Added {len(historical_run.input.videos)} input videos from historical run {historical_run.run_id}"
3862
3857
  )
@@ -3873,19 +3868,11 @@ class Agent:
3873
3868
  session: Optional[AgentSession] = None,
3874
3869
  ) -> Optional[Sequence[Audio]]:
3875
3870
  """Collect audios from input, session history, and current run response."""
3876
- joint_audios = []
3871
+ joint_audios: List[Audio] = []
3877
3872
 
3878
3873
  # 1. Add audios from current input
3879
3874
  if run_input and run_input.audios:
3880
- for artifact in run_input.audios:
3881
- try:
3882
- if artifact.url:
3883
- joint_audios.append(Audio(url=artifact.url))
3884
- elif artifact.base64_audio:
3885
- joint_audios.append(Audio(content=artifact.base64_audio))
3886
- except Exception as e:
3887
- log_warning(f"Error converting AudioArtifact to Audio: {e}")
3888
- continue
3875
+ joint_audios.extend(run_input.audios)
3889
3876
  log_debug(f"Added {len(run_input.audios)} input audios to joint list")
3890
3877
 
3891
3878
  # 2. Add audios from session history (from both input and generated sources)
@@ -3894,30 +3881,14 @@ class Agent:
3894
3881
  for historical_run in session.runs:
3895
3882
  # Add generated audios from previous runs
3896
3883
  if historical_run.audio:
3897
- for artifact in historical_run.audio:
3898
- try:
3899
- if artifact.url:
3900
- joint_audios.append(Audio(url=artifact.url))
3901
- elif artifact.base64_audio:
3902
- joint_audios.append(Audio(content=artifact.base64_audio))
3903
- except Exception as e:
3904
- log_warning(f"Error converting historical AudioArtifact to Audio: {e}")
3905
- continue
3884
+ joint_audios.extend(historical_run.audio)
3906
3885
  log_debug(
3907
3886
  f"Added {len(historical_run.audio)} generated audios from historical run {historical_run.run_id}"
3908
3887
  )
3909
3888
 
3910
3889
  # Add input audios from previous runs
3911
3890
  if historical_run.input and historical_run.input.audios:
3912
- for artifact in historical_run.input.audios:
3913
- try:
3914
- if artifact.url:
3915
- joint_audios.append(Audio(url=artifact.url))
3916
- elif artifact.base64_audio:
3917
- joint_audios.append(Audio(content=artifact.base64_audio))
3918
- except Exception as e:
3919
- log_warning(f"Error converting input AudioArtifact to Audio: {e}")
3920
- continue
3891
+ joint_audios.extend(historical_run.input.audios)
3921
3892
  log_debug(
3922
3893
  f"Added {len(historical_run.input.audios)} input audios from historical run {historical_run.run_id}"
3923
3894
  )
@@ -4365,7 +4336,7 @@ class Agent:
4365
4336
 
4366
4337
  return agent_session
4367
4338
 
4368
- log_warning(f"AgentSession {session_id_to_load} not found in db")
4339
+ log_debug(f"AgentSession {session_id_to_load} not found in db")
4369
4340
  return None
4370
4341
 
4371
4342
  def save_session(self, session: AgentSession) -> None:
@@ -5658,21 +5629,21 @@ class Agent:
5658
5629
  # Handle images, videos and audio
5659
5630
  ###########################################################################
5660
5631
 
5661
- def _add_image(self, image: ImageArtifact, run_response: RunOutput) -> None:
5632
+ def _add_image(self, image: Image, run_response: RunOutput) -> None:
5662
5633
  """Add an image to both the agent's stateful storage and the current run response"""
5663
5634
  # Add to run response
5664
5635
  if run_response.images is None:
5665
5636
  run_response.images = []
5666
5637
  run_response.images.append(image)
5667
5638
 
5668
- def _add_video(self, video: VideoArtifact, run_response: RunOutput) -> None:
5639
+ def _add_video(self, video: Video, run_response: RunOutput) -> None:
5669
5640
  """Add a video to both the agent's stateful storage and the current run response"""
5670
5641
  # Add to run response
5671
5642
  if run_response.videos is None:
5672
5643
  run_response.videos = []
5673
5644
  run_response.videos.append(video)
5674
5645
 
5675
- def _add_audio(self, audio: AudioArtifact, run_response: RunOutput) -> None:
5646
+ def _add_audio(self, audio: Audio, run_response: RunOutput) -> None:
5676
5647
  """Add audio to both the agent's stateful storage and the current run response"""
5677
5648
  # Add to run response
5678
5649
  if run_response.audio is None:
@@ -6841,6 +6812,7 @@ class Agent:
6841
6812
 
6842
6813
  if self.output_schema is not None:
6843
6814
  markdown = False
6815
+ markdown = False
6844
6816
 
6845
6817
  if stream is None:
6846
6818
  stream = self.stream or False
@@ -7156,57 +7128,46 @@ class Agent:
7156
7128
  message.image_output = None
7157
7129
  message.video_output = None
7158
7130
 
7159
- def _convert_media_to_artifacts(
7131
+ def _validate_media_object_id(
7160
7132
  self,
7161
7133
  images: Optional[Sequence[Image]] = None,
7162
7134
  videos: Optional[Sequence[Video]] = None,
7163
7135
  audios: Optional[Sequence[Audio]] = None,
7164
7136
  ) -> tuple:
7165
- """Convert raw Image/Video/Audio objects to ImageArtifact/VideoArtifact/AudioArtifact objects."""
7166
- from uuid import uuid4
7167
-
7168
- from agno.media import AudioArtifact, ImageArtifact, VideoArtifact
7169
-
7170
- 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
7171
7140
  if images:
7172
- image_artifacts = []
7141
+ image_list = []
7173
7142
  for img in images:
7174
- try:
7175
- if img.url:
7176
- image_artifacts.append(ImageArtifact(id=str(uuid4()), url=img.url))
7177
- elif img.content:
7178
- image_artifacts.append(ImageArtifact(id=str(uuid4()), content=img.content))
7179
- except Exception as e:
7180
- log_warning(f"Error creating ImageArtifact: {e}")
7181
- continue
7143
+ # Ensure ID is set (validation should handle this, but double-check)
7144
+ if not img.id:
7145
+ from uuid import uuid4
7146
+
7147
+ img.id = str(uuid4())
7148
+ image_list.append(img)
7182
7149
 
7183
- video_artifacts = None
7150
+ video_list = None
7184
7151
  if videos:
7185
- video_artifacts = []
7152
+ video_list = []
7186
7153
  for vid in videos:
7187
- try:
7188
- if vid.url:
7189
- video_artifacts.append(VideoArtifact(id=str(uuid4()), url=vid.url))
7190
- elif vid.content:
7191
- video_artifacts.append(VideoArtifact(id=str(uuid4()), content=vid.content))
7192
- except Exception as e:
7193
- log_warning(f"Error creating VideoArtifact: {e}")
7194
- continue
7154
+ if not vid.id:
7155
+ from uuid import uuid4
7195
7156
 
7196
- audio_artifacts = None
7157
+ vid.id = str(uuid4())
7158
+ video_list.append(vid)
7159
+
7160
+ audio_list = None
7197
7161
  if audios:
7198
- audio_artifacts = []
7162
+ audio_list = []
7199
7163
  for aud in audios:
7200
- try:
7201
- if aud.url:
7202
- audio_artifacts.append(AudioArtifact(id=str(uuid4()), url=aud.url))
7203
- elif aud.content:
7204
- audio_artifacts.append(AudioArtifact(id=str(uuid4()), content=aud.content))
7205
- except Exception as e:
7206
- log_warning(f"Error creating AudioArtifact: {e}")
7207
- continue
7164
+ if not aud.id:
7165
+ from uuid import uuid4
7166
+
7167
+ aud.id = str(uuid4())
7168
+ audio_list.append(aud)
7208
7169
 
7209
- return image_artifacts, video_artifacts, audio_artifacts
7170
+ return image_list, video_list, audio_list
7210
7171
 
7211
7172
  def cli_app(
7212
7173
  self,
agno/db/mongo/mongo.py CHANGED
@@ -672,7 +672,9 @@ class MongoDb(BaseDb):
672
672
  if result is None or not deserialize:
673
673
  return result
674
674
 
675
- return UserMemory.from_dict(result)
675
+ # Remove MongoDB's _id field before creating UserMemory object
676
+ result_filtered = {k: v for k, v in result.items() if k != "_id"}
677
+ return UserMemory.from_dict(result_filtered)
676
678
 
677
679
  except Exception as e:
678
680
  log_error(f"Exception reading from collection: {e}")
@@ -750,7 +752,8 @@ class MongoDb(BaseDb):
750
752
  if not deserialize:
751
753
  return records, total_count
752
754
 
753
- return [UserMemory.from_dict(record) for record in records]
755
+ # Remove MongoDB's _id field before creating UserMemory objects
756
+ return [UserMemory.from_dict({k: v for k, v in record.items() if k != "_id"}) for record in records]
754
757
 
755
758
  except Exception as e:
756
759
  log_error(f"Exception reading from collection: {e}")
@@ -861,7 +864,9 @@ class MongoDb(BaseDb):
861
864
  if not deserialize:
862
865
  return update_doc
863
866
 
864
- return UserMemory.from_dict(update_doc)
867
+ # Remove MongoDB's _id field before creating UserMemory object
868
+ update_doc_filtered = {k: v for k, v in update_doc.items() if k != "_id"}
869
+ return UserMemory.from_dict(update_doc_filtered)
865
870
 
866
871
  except Exception as e:
867
872
  log_error(f"Exception upserting user memory: {e}")
agno/eval/accuracy.py CHANGED
@@ -97,11 +97,18 @@ class AccuracyResult:
97
97
  title_justify="center",
98
98
  )
99
99
  summary_table.add_row("Number of Runs", f"{len(self.results)}")
100
- summary_table.add_row("Average Score", f"{self.avg_score:.2f}")
101
- summary_table.add_row("Mean Score", f"{self.mean_score:.2f}")
102
- summary_table.add_row("Minimum Score", f"{self.min_score:.2f}")
103
- summary_table.add_row("Maximum Score", f"{self.max_score:.2f}")
104
- summary_table.add_row("Standard Deviation", f"{self.std_dev_score:.2f}")
100
+
101
+ if self.avg_score is not None:
102
+ summary_table.add_row("Average Score", f"{self.avg_score:.2f}")
103
+ if self.mean_score is not None:
104
+ summary_table.add_row("Mean Score", f"{self.mean_score:.2f}")
105
+ if self.min_score is not None:
106
+ summary_table.add_row("Minimum Score", f"{self.min_score:.2f}")
107
+ if self.max_score is not None:
108
+ summary_table.add_row("Maximum Score", f"{self.max_score:.2f}")
109
+ if self.std_dev_score is not None:
110
+ summary_table.add_row("Standard Deviation", f"{self.std_dev_score:.2f}")
111
+
105
112
  console.print(summary_table)
106
113
 
107
114
  def print_results(self, console: Optional["Console"] = None):
@@ -35,13 +35,13 @@ class ChunkingStrategy(ABC):
35
35
  class ChunkingStrategyType(str, Enum):
36
36
  """Enumeration of available chunking strategies."""
37
37
 
38
- AGENTIC_CHUNKING = "AgenticChunking"
39
- DOCUMENT_CHUNKING = "DocumentChunking"
40
- RECURSIVE_CHUNKING = "RecursiveChunking"
41
- SEMANTIC_CHUNKING = "SemanticChunking"
42
- FIXED_SIZE_CHUNKING = "FixedSizeChunking"
43
- ROW_CHUNKING = "RowChunking"
44
- MARKDOWN_CHUNKING = "MarkdownChunking"
38
+ AGENTIC_CHUNKER = "AgenticChunker"
39
+ DOCUMENT_CHUNKER = "DocumentChunker"
40
+ RECURSIVE_CHUNKER = "RecursiveChunker"
41
+ SEMANTIC_CHUNKER = "SemanticChunker"
42
+ FIXED_SIZE_CHUNKER = "FixedSizeChunker"
43
+ ROW_CHUNKER = "RowChunker"
44
+ MARKDOWN_CHUNKER = "MarkdownChunker"
45
45
 
46
46
  @classmethod
47
47
  def from_string(cls, strategy_name: str) -> "ChunkingStrategyType":
@@ -63,13 +63,13 @@ class ChunkingStrategyFactory:
63
63
  def create_strategy(cls, strategy_type: ChunkingStrategyType, **kwargs) -> ChunkingStrategy:
64
64
  """Create an instance of the chunking strategy with the given parameters."""
65
65
  strategy_map = {
66
- ChunkingStrategyType.AGENTIC_CHUNKING: cls._create_agentic_chunking,
67
- ChunkingStrategyType.DOCUMENT_CHUNKING: cls._create_document_chunking,
68
- ChunkingStrategyType.RECURSIVE_CHUNKING: cls._create_recursive_chunking,
69
- ChunkingStrategyType.SEMANTIC_CHUNKING: cls._create_semantic_chunking,
70
- ChunkingStrategyType.FIXED_SIZE_CHUNKING: cls._create_fixed_chunking,
71
- ChunkingStrategyType.ROW_CHUNKING: cls._create_row_chunking,
72
- ChunkingStrategyType.MARKDOWN_CHUNKING: cls._create_markdown_chunking,
66
+ ChunkingStrategyType.AGENTIC_CHUNKER: cls._create_agentic_chunking,
67
+ ChunkingStrategyType.DOCUMENT_CHUNKER: cls._create_document_chunking,
68
+ ChunkingStrategyType.RECURSIVE_CHUNKER: cls._create_recursive_chunking,
69
+ ChunkingStrategyType.SEMANTIC_CHUNKER: cls._create_semantic_chunking,
70
+ ChunkingStrategyType.FIXED_SIZE_CHUNKER: cls._create_fixed_chunking,
71
+ ChunkingStrategyType.ROW_CHUNKER: cls._create_row_chunking,
72
+ ChunkingStrategyType.MARKDOWN_CHUNKER: cls._create_markdown_chunking,
73
73
  }
74
74
  return strategy_map[strategy_type](**kwargs)
75
75